GraphQL

On this page 7

GraphQL is a query language for APIs and a server-side runtime that executes those queries against a strongly typed schema. Instead of calling many fixed endpoints, a client sends one request describing exactly the fields it needs, and the server returns a JSON response with the same shape.

Originally developed at Facebook for mobile applications and released as an open specification in 2015, GraphQL is now governed by the GraphQL Foundation. In the APIs landscape it sits alongside REST API, gRPC and JSON-RPC as a major style, and it is especially common where many different clients consume the same data.

How a GraphQL request is processed

Every GraphQL service starts with a schema written in the Schema Definition Language. The schema declares object types, their fields and the relationships between them, plus three root operation types: Query for reads, Mutation for writes and Subscription for real-time events.

When a request arrives, the server runs three phases. It parses the query text into a syntax tree, validates it against the schema so that unknown fields or wrong argument types are rejected before any work starts, and then executes it by calling a resolver function for each requested field. Resolvers can fetch data from databases, other services or caches.

The following table lists the core building blocks of a GraphQL API and their purpose.

ElementPurposeExample
SchemaTyped contract between client and servertype User { id: ID! name: String }
QueryRead operation{ user(id: 7) { name } }
MutationWrite operation with a resultcreateOrder(input: ...)
SubscriptionStream of events over a long-lived connectionorderShipped { id }
ResolverFunction that produces a field’s valueDatabase lookup for User.name
FragmentReusable set of fields...UserCard in several queries
Core building blocks of a GraphQL API

Key features of the GraphQL type system

The type system is what distinguishes GraphQL from ad hoc JSON APIs. Fields are nullable by default and marked non-null with an exclamation mark, lists are explicit, and enums, interfaces, unions and input types model complex domains precisely.

Because the schema is machine-readable through introspection, tools can generate typed client code, autocomplete queries in editors and detect breaking changes automatically. Fields are retired with the @deprecated directive rather than by versioning the whole API, which encourages continuous schema evolution instead of v1 and v2 endpoints.

Errors follow a specific convention. A response normally returns HTTP status 200 even when some fields failed, with a data object holding whatever succeeded and an errors array describing the failures. This partial success model is useful but surprises teams used to status-code-based error handling.

GraphQL compared with other API styles

GraphQL solves over-fetching and under-fetching, the two classic problems of fixed endpoints: receiving more fields than needed, or needing several round trips to assemble one screen. It pays for this flexibility with a more complex server and harder caching.

AspectGraphQLREST APIgRPC
EndpointsOne endpoint, usually /graphqlMany resource URLsService methods
Response shapeChosen by the clientFixed by the serverFixed by Protocol Buffers
ContractSchema in SDLOptional, often OpenAPIMandatory .proto files
TransportUsually HTTP POST with JSONHTTP verbs and status codesHTTP/2 with binary payloads
HTTP cachingLimited, needs extra workNative through GET and headersNot applicable
Best fitVaried clients and nested dataSimple, cacheable resourcesInternal service-to-service calls
GraphQL compared with neighboring API styles

The styles are not mutually exclusive. A common architecture places a GraphQL gateway in front of REST or gRPC microservices, giving front-end teams one flexible API while the backend keeps efficient internal protocols.

Performance and security considerations

Because clients control query shape, a GraphQL server must protect itself from expensive queries. A deeply nested query can multiply database work, and naive resolvers produce the N+1 problem, where fetching 100 orders triggers 100 separate customer lookups.

The table below maps the typical risks to their standard countermeasures.

RiskSymptomCountermeasure
N+1 queriesHundreds of small database calls per requestBatching with a DataLoader pattern
Deep or cyclic queriesExponential work from nested relationsDepth limits, often 7 to 15 levels
Expensive field combinationsSlow responses and high CPU useQuery cost analysis and budgets
Schema exposureAttackers map the entire APIDisable introspection in public production
Arbitrary queriesUnpredictable load and abusePersisted queries with an allowlist
Field-level data leaksUsers read fields they should notAuthorization in resolvers or a policy layer
Common GraphQL risks and countermeasures

Caching also needs deliberate design. Since most requests are POST calls to one URL, standard HTTP caches do not help, so teams use normalized client caches keyed by type and ID, persisted queries sent as GET requests, or response caching at the gateway.

When to choose GraphQL

GraphQL is the stronger choice when several clients with different data needs share one backend and the domain is a graph of related entities. It is weaker for simple CRUD services, file transfer and public APIs that rely heavily on HTTP caching.

SituationRecommendationReason
Web and mobile apps sharing one backendGraphQLEach client fetches only what it shows
Aggregating many microservicesGraphQL gateway or federationOne schema hides service boundaries
Public, cache-heavy read APIREST APICDN and browser caching work natively
High-throughput internal callsgRPCBinary encoding and streaming are faster
Event notifications to partnersWebhookPush delivery without polling
Decision guide for adopting GraphQL

Stripped to the essentials

Imagine ordering in a restaurant where every dish comes as a fixed set menu. GraphQL is like ordering à la carte from one waiter: you list exactly what you want, and the kitchen brings precisely that, on one tray, in the order you asked.

For software, this means an app can ask a server for only the information it will display, in a single request. The menu itself, called the schema, is written down precisely, so both sides always know what can be ordered.

Where it is applied

A travel company runs a website, an iOS app and an Android app that all show bookings, flights, hotels and loyalty points. With its old REST API, the mobile booking screen needed six separate requests and downloaded many fields it never displayed, which made the screen slow on weak mobile connections.

The company adds a GraphQL layer in front of its existing services. The mobile screen now sends one query naming the 15 fields it needs, while the website requests a richer set from the same schema. Resolvers use batching, so a page with 50 bookings makes one hotel lookup instead of 50. The mobile payload shrinks considerably and front-end teams can add fields to screens without waiting for new backend endpoints.