GraphQL
Query language and runtime for APIs - clients request exactly the fields they need, one endpoint replaces many REST routes, strong schema typing catches errors at build time.
skill: GraphQL category: Web Development tags: [GraphQL, API, Apollo, Schema, Type System] readingTime: 7
GraphQL is ideal when clients have diverse data needs, you have many frontend teams consuming the same API, or you need real-time subscriptions. For simple CRUD APIs with a single client, REST is simpler. For very high-throughput simple queries, REST may outperform due to fewer resolver overheads.
Workflow
- Define the schema firstSchema-first development makes the contract explicit - frontend and backend teams agree on types before writing any resolver logic.
- Set up Apollo ServerApollo Server handles parsing, validation, execution, and error formatting - letting you focus on resolver logic.
- Write resolversResolvers map schema fields to data sources - DB queries, REST calls, or computed values.
- Solve the N+1 problem with DataLoaderWithout batching, fetching 100 posts each calling user resolver fires 100 DB queries. DataLoader batches them into one.
- Add subscriptions for real-timeGraphQL subscriptions push data changes to clients over WebSockets - no polling required.
Output Format
GraphQL API with typed schema, resolvers, DataLoader batching, and Apollo Server.
graphql-api/
├── schema.graphql # Type definitions
├── resolvers/
│ ├── query.ts
│ ├── mutation.ts
│ └── subscription.ts
├── dataloaders/ # Batching per entity
├── context.ts # DB, auth, loaders
└── server.tsExamples
Input
Output
Input
Output
Edge Cases & Gotchas
- N+1 without DataLoader - Every resolver that fetches a related entity without batching multiplies DB queries. Always use DataLoader for any one-to-many or many-to-one resolver.
- Introspection in production - GraphQL introspection exposes your full schema. Disable it in production unless you're building a public API: `introspection: process.env.NODE_ENV !== 'production'`.
- Large query depth attacks - Deeply nested queries can DOS your server. Use `graphql-depth-limit` or `graphql-query-complexity` to reject expensive queries.
- Nullable vs non-null types - Non-null fields (!) propagate errors upward - a resolver error on a non-null field nulls the entire parent. Mark fields nullable unless you're certain they'll always resolve.
When to Break These Rules
- Use REST for simple CRUD APIs with one client - GraphQL's overhead (schema, resolvers, DataLoader) isn't worth it for three endpoints.
- Use gRPC when you need binary efficiency, streaming, or server-to-server communication without a browser client.
Reference Files
https://graphql.org/learn/https://www.apollographql.com/docs/apollo-server