Concept lesson

GraphQL vs REST API Architecture

Schema stitching, N+1 query problem, DataLoader batching, and REST endpoint design.

lesson
Freshness: current15 min read
Mastery
not started · 0%

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.

GraphQL Query Document Input
AST Query Parser & Type Validator
Execute Resolvers across Data Models
DataLoader Batches SQL Queries
Return Formatted JSON Payload
Conceptual teaching model synthesized from:FastAPI Framework Architecture & Dependency Injection Specification

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

  1. 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).
  2. 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.
Reflect before revealing the guide

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

not-started · 0%
theory0%
decision0%
activityNot mapped
projectNot mapped
1. What is the core architectural principle governing graphql vs rest apis?
2. What primary operational trade-off must be managed when configuring graphql vs rest apis?
3. Which failure mode is most commonly observed when graphql vs rest apis is misconfigured?

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