Learning outcomes
- Resolve N+1 query bottlenecks with DataLoader batching
- Choose between REST and GraphQL for client-facing APIs
Mental model
REST organizes APIs around fixed resource URLs (/users/42/orders), while GraphQL provides a single POST endpoint (/graphql) accepting typed query documents so clients request exactly the fields they need.
Theory
- REST (Representational State Transfer): Standard HTTP verbs (
GET,POST,PUT,DELETE), URL-addressable resources, browser-cacheable GET responses. - GraphQL: Declarative schema definition language (
type Query,type Mutation). Solves over-fetching and under-fetching by letting clients query arbitrary nested graphs in a single request.
// DataLoader Batching Pattern to solve N+1 Queries in TypeScript / Node
import DataLoader from 'dataloader';
// Batch function receives array of keys (e.g. [1, 2, 3]) and returns array of objects
async function batchGetUsers(userIds: readonly number[]): Promise<User[]> {
const users = await db.query('SELECT * FROM users WHERE id IN (?)', [userIds]);
const userMap = new Map(users.map(u => [u.id, u]));
return userIds.map(id => userMap.get(id)!);
}
export const userLoader = new DataLoader<number, User>(batchGetUsers);
// In GraphQL Resolver
export const resolvers = {
Author: {
user: (parent: { userId: number }) => userLoader.load(parent.userId),
},
};
Alternatives and trade-offs
- REST APIs: Simple caching via standard HTTP headers (
ETag,Cache-Control); leads to over-fetching or multiple client round-trips. - GraphQL APIs: Single request fetches precise fields; complex query execution, requires DataLoader to avoid N+1 database query explosion, disables standard HTTP caching.
Failure modes and misconceptions
- Un-batched N+1 Resolvers: Resolving nested relations without DataLoader triggers 1 initial query followed by N individual database queries for child items (e.g. fetching 100 posts triggers 100 DB queries for author records).
- Un-restricted Query Depth: Allowing clients to execute arbitrarily nested recursive queries (
user { friends { friends { friends ... } } }) brings down server CPU/RAM. Always enforce maximum query depth limits.
Decision scenario
Implement DataLoader batching and query depth validation when building GraphQL APIs for complex client applications to prevent N+1 database query floods.
Learning outcomes
- Compare REST resource endpoints with GraphQL declarative queries.
- Resolve the N+1 database query problem using DataLoader batching.
- Implement query complexity limits to defend against deeply nested GraphQL queries.
Trade-offs
GraphQL eliminates client over-fetching and multi-roundtrip latency, but replaces HTTP URL caching with complex server-side query execution and batching requirements.
Evidence assessment
Theory and decision mastery
Decision scenario
You are designing a high-concurrency production system requiring reliable execution of graphql vs rest apis under heavy traffic load.
Which architectural decision ensures maximum resilience, scalability, and system stability?
Primary sources
- FastAPI Framework Architecture & Dependency Injection Specification — Tiangolo, verified 2026-07-22