Glossary
GraphQL
GraphQL gives clients precise control over the data they select. It is neither a database language nor an automatic solution to performance, permissions, or API design.
Short definition
An API contract described through types, fields, and operations.
The server first publishes a GraphQL schema: types, available fields, inputs, and operations. A client then sends a query to read data or a mutation to change it, selecting only the fields it needs. The server validates the query syntactically and by type, runs resolvers, and generally returns JSON containing data and, where applicable, a list of errors.
GraphQL does not sit directly on top of tables. A resolver can read a relational database, call several internal services, use a cache, or combine data from an external API. The public GraphQL schema is a contract for clients, not a reflection of the internal database structure.
What it is used for
When different clients need different views of the same data
Field selection is especially useful for multiple frontends or screens that show different levels of detail from the same domain model.
- web and mobile applications read orders with different levels of detail
- an administration interface combines an overview from orders, customers, and synchronisation statuses
- a frontend loads the data needed for a specific screen in a single query
- a mutation creates or changes business objects through a typed input contract
- an internal API evolves its schema gradually without exposing tables directly to clients
Practical example
Order details without unnecessary fields
The administration frontend needs to display the order number, status, customer name, items, and total price. The query explicitly selects these fields; before returning them, the server verifies that the current user may read the order within the given organisation.
The example does not mean that the customer or items fields are public to everyone. A resolver or shared authorization layer must enforce the same rules as a REST endpoint. Sensitive data is not added to the schema merely because it exists in the database internally.
GraphQL and JSON
query OrderDetail($id: ID!) {
order(id: $id) {
number
status
customer { displayName }
items { quantity productName totalPrice }
totalPrice
}
}
{"id":"ord_42"}
How it works
Text diagram: client query → schema → resolvers → authorized data → JSON response
The schema defines the public contract; individual resolvers decide where to obtain the data and whether it may be returned.
- The schema describes the contract Types define available fields, their inputs, and nullability. Introspection can help clients discover the contract if the operator deliberately exposes it.
- The client builds an operation A query selects data, a mutation requests a change, and variables carry values separately from the query text. A fragment lets clients reuse a field selection.
- The server validates the operation It checks syntax, field existence, input types, and limits. Valid GraphQL does not mean that a request is authorized or inexpensive.
- Resolvers load and verify data A resolver can work with a database or service, but must handle authorization, errors, and efficient loading of related objects.
- The response carries data and errors Part of the data may succeed while another field results in an error. The client therefore evaluates both the HTTP status and the response structure.
Key concepts
Types and resolvers give field selection its rules
A good contract is understandable to clients without hiding operational rules solely in its implementation.
Query, mutation, and subscription
A query reads data and a mutation expresses a change. A subscription can announce ongoing changes, but often uses WebSocket or another mechanism for transport and requires the same authorization.
Type, field, and nullability
A type defines the contract shape, a field provides a specific value, and nullability indicates whether the value may be missing. These are not the same as database columns or tables.
Resolver
A resolver is code that calculates or loads a field value. One resolver can combine several sources, so it needs sensible limits and must track the number of additional calls.
Variable and fragment
Variables carry input values separately from the query structure. A fragment helps share a repeated field selection; neither mechanism replaces validation of business rules.
Introspection and schema evolution
A schema can be examined by machines and extended gradually. An obsolete field should be marked as deprecated and removed only after a controlled client migration.
Benefits and limitations
Precise data selection in exchange for more demanding cost and permission controls
Benefits
- one operation can deliver data for a specific screen without unnecessary fields
- a typed schema facilitates documentation, validation, and editor support
- the contract can evolve gradually by adding fields and deprecating older ones
- it unifies access to multiple data sources behind one public contract
Common mistakes
- mistaking GraphQL for direct database access
- assuming that field selection automatically solves N+1 and performance
- authorizing only the whole operation, rather than individual objects or sensitive fields
- allowing unlimited query depth, width, or cost
- treating HTTP 200 as success even when the response contains GraphQL errors
When to use it
When maintaining a rich, long-term contract for multiple clients is worthwhile.
GraphQL can suit an administration interface and multiple frontends that use the same domain objects but need a different subset on each screen. Its value grows with the quality of the schema, sensible mutation modelling, and the ability to operate query limits, monitoring, and authorization.
For a small integration operation with a clear HTTP resource, a REST endpoint may be easier to understand, cache, and operate. GraphQL is not a replacement for a database model, documentation of error states, or an interface for asynchronous events.
What to consider
The public schema is both a product and security interface.
Limits, traceability, and authorization rules close to the data matter—not just convenient field selection on the client.
- model types and mutations according to domain meaning, rather than as direct tables
- verify permissions at the operation, object, and sensitive-field levels
- measure resolver duration, load counts, and query cost; address N+1 with batching or suitable loading
- limit depth, complexity, and input size, and consider persisted or allowlisted operations
- version the contract through evolution: add, mark as deprecated, and only then remove safely
Common questions
GraphQL without oversimplified promises
Is GraphQL a replacement for REST?
Not necessarily. It is another way to design an API contract. One system may reasonably use GraphQL for a frontend, REST for a partner integration, and a webhook for event notifications.
Is GraphQL a database language?
No. It queries a public API schema. A resolver may access a database, but the server determines which data is available and how it is loaded.
Does GraphQL eliminate the N+1 problem?
Not automatically. A naïve resolver can run another query for every row. The application must measure this and use suitable batching, eager loading, or other strategies.
Does HTTP 200 always mean a GraphQL operation succeeded?
No. A response can contain partial data and an errors field. The client must handle the response contract, not only the transport status.
How I design APIs in practice
I tie an API contract to domain meaning, permissions, and operational limits.
When designing integrations, I address data, compatibility, errors, query performance, and server-side verification of specific access—regardless of whether the transport uses REST or GraphQL.