Level 2 · Intermediate Real Data¶
Goal: design a schema clients can depend on for years, back it with a real database without drowning it in queries, and prove it all with tests that catch regressions you can't see by eye.
Three ideas carry this level:
- Design from the screen backwards. A schema shaped like your tables keeps every cost of GraphQL and loses its benefits. Start from what clients render.
- Count your queries. GraphQL's execution model makes N+1 data access the default. A per-request statement counter turns an invisible problem into a failing test.
- Expected failures are data. Invalid input and "already taken" belong in the schema as
typed results; the
errorsarray is for things that actually went wrong.
Modules¶
- Schema Design — client-shaped vs database-shaped schemas, naming, money and time, a tested matrix of safe and breaking nullability changes
- Interfaces and Unions — inline fragments,
__resolveType, theNodepattern, every validation error you'll meet - Custom Scalars —
serialize,parseValue,parseLiteral; a February 30th bug;graphql-scalars - Connecting a Database —
node:sqlite, per-request context, parameters,LIKEwildcards, constraint errors - The N+1 Problem — statement counts for 10, 100 and 500 rows; why resolvers can't see it
- DataLoader — batching and caching, from 1,001 statements to 3; five pitfalls, each run
- Pagination — the offset bug, keyset cursors, connections, query plans
- Mutation Design —
userErrorspayloads vs result unions, constraint codes, evolving outcomes - Testing a GraphQL Server — unit,
executeOperation, HTTP and schema-snapshot tests; two regressions caught - Project — A Bookstore API on SQLite — everything above, plus a cache-invalidation bug found by a test
What you need before starting¶
- Level 1 of this course: resolvers, context, mutations, errors, Apollo Server basics.
- Basic SQL:
SELECT,JOIN,WHERE, indexes and constraints. The SQL Mastery Path covers them. - Install:
npm install graphql @apollo/server @graphql-tools/schema dataloader graphql-scalars.
How the examples were checked¶
Everything in this level was run on Node.js 26.3 (whose built-in node:sqlite bundles
SQLite 3.53.4) with graphql 16.14.2, Apollo Server 5.5.1, @graphql-tools/schema
10.1.3, DataLoader 2.2.3 and graphql-scalars 2.0.0. Statement counts are exact.
Timings come from one laptop with in-memory databases; they show ratios (24 ms vs 4.7 ms for the
same query with and without batching), not benchmarks — a networked database would widen the gap.
What wasn't run
No PostgreSQL or MySQL server was used. Where their behaviour differs from SQLite in a way that matters (async drivers, SQLSTATE codes, row-value support), the lesson says so and describes the documented behaviour rather than showing output.