API & BACKEND ARCHITECTURE / SYSTEM CONCEPT BRIEF

GraphQL

GraphQL is a query language and runtime for APIs.

IntermediatePhase 02 / Topic 2 of 20RequirementsTrade-offsFailure modes
01

Overview

GraphQL is a query language and runtime for APIs. The server publishes a typed schema, and each client sends a query describing exactly the fields it needs, possibly across related objects, in a single request. The server resolves each field with resolver functions and returns JSON in the same shape as the query.

It solves REST's over-fetching and under-fetching, which matters most for complex UIs and mobile apps. The costs are real: caching is harder (usually one POST endpoint), naive resolvers cause N+1 database queries, and clients can craft expensive queries, so production GraphQL needs batching, query cost limits, and persisted queries.

Ordering a custom meal instead of set menus

REST is a set menu: each dish comes with fixed sides whether you want them or not, and you may need to order from several menus. GraphQL lets you tell the waiter exactly what you want on one plate, taken from several kitchens.

02

When to use it

  • Many different clients need different slices of the same data.
  • Screens combine data from several services in one view.
  • Mobile clients on slow networks where round trips are costly.
  • Rapid front-end iteration without new endpoints for every screen.
03

Where it shows up in interviews

Aggregation layer

Recognize it when: one screen needs data from users, posts, and comments services.

  • Design Facebook's news feed API
  • Design a mobile app backend
API federation

Recognize it when: many teams own parts of one graph.

  • Design a unified API for 50 microservices
04

Where it is used in real software

Facebook

GraphQL was created at Facebook in 2012 for the mobile news feed, where many round trips on slow networks were unacceptable.

GitHub GraphQL API

Offers a public GraphQL API alongside REST, with a rate limit based on query cost points.

Apollo Federation

Lets teams own subgraphs that a gateway composes into one supergraph (used by Netflix, Expedia).

05

Key terms

Schema
Typed description of objects, fields, queries, and mutations.
Resolver
A function that returns the value for one field.
Mutation
An operation that changes data.
Subscription
Real-time updates pushed over WebSockets.
DataLoader
Batches and caches loads within a request to avoid N+1 queries.
06

How it works, step by step

  1. 1
    Client sends a query

    POST /graphql with the query text (or a persisted query ID) and variables.

  2. 2
    Server parses and validates

    Checks syntax and types against the schema; rejects unknown fields.

  3. 3
    Cost analysis

    Estimate depth and complexity; reject queries above the limit.

  4. 4
    Resolve fields

    Resolvers run for each field; DataLoader batches related lookups.

  5. 5
    Return shaped JSON

    The response mirrors the query; partial errors appear in an errors array.

07

The N+1 problem and DataLoader

Query: 50 posts, each with its author

Step 1 / 3
ApproachDatabase queriesWhy
Naive resolvers1 + 50 = 51author resolver runs once per post
DataLoader batching1 + 1 = 2all author IDs collected and loaded with one IN query
Join in the posts resolver1but couples resolvers to query shape

NOWApproach: Naive resolvers | Database queries: 1 + 50 = 51 | Why: author resolver runs once per post

DataLoader is the standard fix: it waits until the current tick, collects all requested keys, and issues one batched query.

08

Implementation

import DataLoader from "dataloader"; const typeDefs = `#graphql  type User { id: ID!, name: String! }  type Post { id: ID!, title: String!, author: User! }  type Query { feed(first: Int = 20, after: String): [Post!]! }  type Mutation { createPost(title: String!): Post! }`; // One loader per request so caching never leaks between usersfunction createLoaders(db: Db) {  return {    userById: new DataLoader<string, User>(async (ids) => {      const rows = await db.users.findMany({ where: { id: { in: [...ids] } } });      const byId = new Map(rows.map((u) => [u.id, u]));      return ids.map((id) => byId.get(id)!);    }),  };} const resolvers = {  Query: {    feed: (_: unknown, args: { first: number; after?: string }, ctx: Ctx) => ctx.db.posts.page(args),  },  Post: {    author: (post: Post, _: unknown, ctx: Ctx) => ctx.loaders.userById.load(post.authorId), // batched  },  Mutation: {    createPost: (_: unknown, { title }: { title: string }, ctx: Ctx) => ctx.db.posts.create({ title, authorId: ctx.user.id }),  },};
09

Complexity and performance

Round trips per screen1

One query for nested data.

N+1 without batchingO(n) queries

Fix with DataLoader.

HTTP cachingLow

Needs persisted queries or client caches.

10

Trade-offs

Flexibility vs protection

Clients can ask for anything in the schema, so you must limit depth and cost, and consider persisted queries for public clients.

Caching

CDN caching is easy for REST GET URLs; GraphQL relies on client-side normalized caches (Apollo, Relay) or GET with persisted query hashes.

11

Variants and related techniques

Federation

Multiple subgraphs composed by a gateway, each owned by a team.

Persisted queries

Clients send a hash of an approved query, enabling CDN caching and blocking arbitrary queries.

12

Common mistakes

  • N+1 resolver queries.

    Fix: Use DataLoader per request.

  • Unbounded query depth.

    Fix: Enforce depth and complexity limits and timeouts.

  • Authorization only at the endpoint.

    Fix: Check permissions in resolvers or the data layer, per field and object.

13

Interview questions

When would you choose GraphQL over REST?

When many clients need different shapes of related data, especially mobile clients where round trips are expensive, or when aggregating many backend services for a UI.

How do you prevent abusive GraphQL queries?

Depth limits, query cost analysis with budgets per client, pagination limits, timeouts, and persisted queries for first-party clients.

14

Practice problems

ProblemDifficultyWhat it trains
Model a schema for a blog with users, posts, commentsEasyTypes and relations.
Fix an N+1 problem in a feed resolverMediumDataLoader.
Design a federated graph for an e-commerce companyHardOwnership and gateway.