GraphQL Best Practices with RESTHeart
This guide outlines best practices for building robust, secure, and performant GraphQL APIs with RESTHeart.
Schema Design
Type Definitions
-
Clear Type Names
-
Use descriptive, domain-specific names
-
Follow PascalCase convention
-
Avoid abbreviations unless widely understood
-
-
Field Naming
-
Use camelCase for field names
-
Be consistent with naming patterns
-
Make names self-descriptive
-
# Good
type UserProfile {
firstName: String!
lastName: String!
emailAddress: String!
}
# Avoid
type UP {
fname: String!
lname: String!
email: String!
}
-
Nullability
-
Make fields non-null (
!
) when they’re required -
Consider optional fields for future extensibility
-
Use non-null lists
[Type!]
when elements are required
-
Query Design
-
Pagination
-
Always paginate list queries
-
Use cursor-based pagination for large datasets
-
Include total counts when needed
-
type Query {
users(
first: Int = 10
after: String
): UserConnection!
}
type UserConnection {
edges: [UserEdge!]!
pageInfo: PageInfo!
totalCount: Int!
}
-
Filtering
-
Use input types for complex filters
-
Support multiple filter combinations
-
Provide sensible defaults
-
input UserFilter {
name: String
age: IntRange
status: UserStatus
AND: [UserFilter!]
OR: [UserFilter!]
}
input IntRange {
min: Int
max: Int
}
MongoDB Integration
Collection Mapping
-
Document Structure
-
Map GraphQL types to logical MongoDB collections
-
Use embedded documents judiciously
-
Consider denormalization for performance
-
-
Indexes
-
Create indexes for frequently queried fields
-
Index fields used in sorting
-
Use compound indexes for complex queries
-
Query Optimization
-
Field Selection
-
Project only needed fields
-
Use MongoDB aggregation for complex transformations
-
Avoid retrieving large arrays if possible
-
{
"mappings": {
"Query": {
"userProfile": {
"db": "users",
"collection": "profiles",
"find": { "_id": { "$arg": "userId" } },
"project": {
"firstName": 1,
"lastName": 1,
"email": 1
}
}
}
}
}
-
Aggregation Pipelines
-
Keep pipelines simple and efficient
-
Use early filtering stages
-
Limit memory usage in group operations
-
Performance
N+1 Prevention
-
DataLoader Usage
-
Enable batching for related data
-
Configure appropriate batch sizes
-
Use caching when data is relatively static
-
{
"mappings": {
"Post": {
"author": {
"db": "users",
"collection": "authors",
"find": { "_id": { "$fk": "authorId" } },
"dataLoader": {
"batching": true,
"caching": true,
"maxBatchSize": 100
}
}
}
}
}
-
Relationship Loading
-
Use single queries for related data when possible
-
Consider denormalization for frequently accessed data
-
Monitor query patterns
-
Next Steps
-
Explore Complex App Example
-
Learn about Performance Optimization
-
Check out Basic Tutorial