Level 3 · Advanced Production Concerns¶
Goal: take a working GraphQL API and make it safe to put in front of real users — authenticated, authorized on every path, resistant to expensive queries, cacheable, real-time where it needs to be, and pleasant to consume from typed clients.
Three ideas carry this level:
- Clients choose the work; the server must bound it. Depth, cost, page sizes and — for first-party apps — an allowlist of trusted operations.
- Authorization belongs in the data layer. A graph has many paths to the same object; only a rule every path goes through is safe.
- Conventions are features. Stable ids,
__typename, payloads that return what changed — they're what make normalized client caches, codegen and HTTP caching work.
Modules¶
- Authentication — issuing and verifying JWTs, context, four attacks rejected
- Authorization — operation, object and field rules; hidden equals missing; the second-path bug
- Custom Schema Directives —
@auth,@lower,@truncatewithmapSchema; what introspection doesn't show - Subscriptions over WebSockets —
graphql-ws, async iterators, a pub/sub, cleanup and scaling limits - Securing a Public Graph — 176,821 resolver calls from 127 characters; depth limits, cost analysis, batching
- Caching & Persisted Queries —
@cacheControl, GET, APQ, trusted documents - Clients —
fetch, Apollo Client 4's normalized cache, cache redirects - Type Safety with GraphQL Code Generator — typed documents and resolvers; five mistakes caught
- GraphQL over HTTP in Depth — media types and status codes compared across servers, uploads and CSRF
- Project — A Real-Time Task Board with Auth — HTTP and WebSocket auth, per-event authorization, revocation
What you need before starting¶
- Levels 1 and 2 of this course, especially context, DataLoader and mutation payloads.
- Web security basics: what CSRF and XSS are, how cookies and bearer tokens differ. The Cybersecurity Mastery Path covers them.
- TypeScript basics for lesson 8 — see the TypeScript Mastery Path.
How the examples were checked¶
Everything was run on Node.js 26.3 with graphql 16.14.2, Apollo Server 5.5.1,
jose 6.2.12, graphql-ws 6.3.0 with ws 8.22.0, @graphql-tools/utils 12.0.3,
graphql-query-complexity 2.0.0, Apollo Client 4.3.3, GraphQL Yoga 5.24.4, and — for
lesson 8 — @graphql-codegen/cli 7.4.5 with TypeScript 7.0.2. Servers were real processes on
localhost ports, exercised with curl, fetch and real WebSocket clients. Several first attempts
failed and are shown: a plugin hook that turned an error into a crash, generated imports that a
NodeNext project rejected, a stray process holding a port.
What wasn't run
No external identity provider, Redis or message broker, CDN, or cloud object storage was used. Scaling subscriptions across instances, CDN caching behaviour and signed-URL uploads are described from documented behaviour and marked as not run.