What is GraphQL?
Understanding the modern approach to API design: Queries, Mutations, and the REST comparison.
For over a decade, Representational State Transfer (REST) has been the undisputed standard for designing web APIs. But as mobile applications grew and client-side web frameworks demanded more complex, nested data structures, REST began to show its limitations.
Enter GraphQL. Developed internally by Facebook in 2012 and open-sourced in 2015, GraphQL is a query language for your API, and a server-side runtime for executing those queries using a type system you define for your data.
The Problem with REST
To understand why GraphQL exists, we must understand the two biggest problems with traditional REST architectures:
- Over-fetching: You hit an endpoint (e.g.,
/api/users/123) just to get the user's name, but the server returns the entire user object containing 50 fields, wasting bandwidth and memory. - Under-fetching (and the N+1 problem): You hit
/api/poststo get a list of a user's blog posts. But you also need the author's avatar for each post. Now you must make a separate request to/api/users/idfor every single post returned in the first call.
How GraphQL Solves This
GraphQL shifts the power from the server to the client. Instead of hitting multiple endpoints that return fixed data structures, a GraphQL client hits a single endpoint (usually /graphql) and sends a document describing exactly what it wants.
# The Client Request (Query)
query {
user(id: "123") {
name
email
posts {
title
comments(limit: 2) {
text
author {
name
}
}
}
}
} In a single HTTP request, the client asked for a user, their posts, and the last two comments on each post (including the author of the comment). The server responds with JSON that exactly matches the shape of the query. No over-fetching, no under-fetching.
Core Concepts of GraphQL
1. The Schema (SDL)
At the heart of any GraphQL server is the schema. Written in the Schema Definition Language (SDL), it acts as a strict contract between the client and the server.
type User {
id: ID!
name: String!
email: String
posts: [Post!]!
}
type Post {
id: ID!
title: String!
body: String!
author: User!
} The exclamation mark (!) denotes a non-nullable field, guaranteeing the client that the field will always return a value.
2. Queries
Queries are how you fetch data. They are analogous to GET requests in REST. They are read-only operations.
3. Mutations
Mutations are used to create, update, or delete data. They are analogous to POST, PUT, PATCH, and DELETE in REST. While they look syntactically similar to queries, GraphQL guarantees that mutations are executed serially (one after another) to prevent race conditions.
mutation {
createPost(title: "GraphQL is awesome", body: "...") {
id
title
}
} 4. Resolvers
If the schema is the blueprint, resolvers are the actual builders. A resolver is a function associated with a specific field in the schema. When a query asks for user.name, the server executes the resolver function for name on the User type to fetch the data from the database, a microservice, or a third-party API.
GraphQL vs REST: A Summary
| Feature | REST | GraphQL |
|---|---|---|
| Endpoints | Multiple (URLs dictate resources) | Single (/graphql) |
| Data Shape | Determined by the Server | Dictated by the Client |
| Versioning | Required (/v1/, /v2/) | Deprecate fields seamlessly |
| HTTP Caching | Native (GET requests cache easily) | Complex (Requires Apollo/Relay) |
The Challenges of GraphQL
GraphQL is not a silver bullet. It introduces its own set of complexities:
- Caching: Because all requests use POST to a single endpoint, standard HTTP caching at the CDN level breaks. You must rely on sophisticated client-side caches (like Apollo Client) or specialized edge services.
- The N+1 Problem: If a client requests 100 users, and their associated posts, a naive GraphQL server will hit the database 101 times. Tools like DataLoader are required to batch these queries.
- Security & Complexity: A malicious client could write a deeply nested query (e.g., User -> Posts -> Comments -> Author -> Posts) that brings down your server. You must implement query depth limiting and cost analysis.