RESTful and GraphQL APIs
Learning Objectives
By the end of this page, you should be able to:
- Explain what an API is and why REST and GraphQL exist as two competing styles for building them.
- Describe the key architectural constraints of REST (statelessness, uniform interface, resource-based URLs) and write example REST requests.
- Write a basic GraphQL schema, query, and mutation, and explain how a single GraphQL endpoint replaces many REST endpoints.
- Identify the over-fetching and under-fetching problems in REST and explain how GraphQL solves them.
- Compare REST and GraphQL on caching, complexity, versioning, and tooling, and justify choosing one for a given scenario.
- Recognize common mistakes in API design, such as treating GraphQL as strictly "better" or ignoring authorization at the resource level.
Quick Answer
An API (Application Programming Interface) lets one piece of software request data or services from another — it's how your phone's weather app gets weather data, and how a web front-end gets data from a back-end server. REST and GraphQL are the two dominant styles for designing such APIs. REST models data as resources accessed through multiple URLs using standard HTTP methods (GET, POST, PUT, DELETE); it's simple, cacheable, and the long-standing web standard. GraphQL exposes a single endpoint where clients send a query describing exactly the fields they want, across multiple related resources, in one round trip. REST is simpler and better-cached; GraphQL is more flexible and avoids over/under-fetching — the right choice depends on your client's needs, not on which is "newer."
Table of Contents
- What is an API?
- RESTful APIs
- GraphQL APIs
- Request Flow: REST vs GraphQL
- Key Terms
- Common Mistakes
- Comparison and Connections
- Practice Questions
- FAQ
- Quick Revision
- Related Topics
What is an API?
An API (Application Programming Interface) is a defined contract that lets one program request data or trigger behavior in another, without needing to know how the other program is implemented internally. On the web, this usually means a client (a browser, mobile app, or another server) sends an HTTP request to a server, and the server responds with structured data — typically JSON.
Whenever you log into a website with your Google account, check a weather widget, or see a map embedded in a food-delivery app, an API call is happening behind the scenes. Without APIs, every application would have to rebuild every service (maps, payments, authentication) from scratch instead of reusing someone else's.
REST and GraphQL are both styles for designing such APIs — neither is a protocol like HTTP itself, but a set of conventions layered on top of it.
RESTful APIs
REST (Representational State Transfer) is an architectural style introduced by Roy Fielding in his 2000 doctoral dissertation. It treats everything the API exposes as a resource — a user, an order, a tweet — each identified by a URL, and manipulated using standard HTTP methods.
GET /users/42 → Read user 42
POST /users → Create a new user
PUT /users/42 → Replace user 42 entirely
PATCH /users/42 → Partially update user 42
DELETE /users/42 → Delete user 42
The HTTP method describes the action; the URL describes the resource. This mapping is what makes REST APIs predictable — a developer who has never seen your API can often guess DELETE /orders/17 deletes order 17, without reading documentation.
Key Characteristics of REST
- Stateless — every request must carry all the information the server needs (e.g. an auth token in a header); the server keeps no memory of previous requests from that client. This is why REST APIs scale horizontally so easily — any server in a pool can handle any request.
- Resource-based URLs — nouns, not verbs:
/orders/17, not/getOrder?id=17. - Uniform interface — the same small set of HTTP methods and status codes (
200,201,404,500, etc.) is reused across every resource, so clients learn one convention and it applies everywhere. - Cacheable — because
GET /users/42always identifies the same resource, HTTP caches (browsers, CDNs, proxies) can store and reuse the response automatically. - Layered system — a client talking to
api.example.comdoesn't need to know if it's hitting the application server directly or going through a load balancer, cache, or gateway first.
A Worked REST Example
Say a blogging app needs a post and its author's name for a page. With REST, that typically takes two round trips, because "post" and "author" are separate resources:
GET /posts/101
→ { "id": 101, "title": "REST 101", "authorId": 7, "body": "..." }
GET /users/7
→ { "id": 7, "name": "Asha Rao", "email": "asha@example.com" }
Notice the second response includes an email field the client never asked for and doesn't need — this is over-fetching. Needing two calls to assemble one page is under-fetching (of a single resource) forcing multiple requests. Both are structural side effects of REST's one-URL-per-resource design, not bugs in a particular API.
Advantages and Disadvantages of REST
Advantages:
- Simple mental model — matches how HTTP and web caching already work.
- Mature tooling: every language, browser, and proxy understands HTTP verbs and status codes natively.
- Easy to cache aggressively at the network layer (CDNs, browser cache) using URLs as cache keys.
Disadvantages:
- Over-fetching and under-fetching, as shown above, especially for nested/related data.
- Versioning is awkward — as a resource's shape changes, you often need
/v1/usersand/v2/usersside by side. - No built-in way for a client to ask "give me only these three fields" — the server decides the response shape.
GraphQL APIs
GraphQL is a query language for APIs, created at Facebook in 2012 and open-sourced in 2015. Instead of many URLs, a GraphQL API exposes one endpoint (typically /graphql). The client sends a query describing exactly which fields it wants, potentially spanning multiple related resources, and the server returns exactly that shape — nothing more, nothing less.
A GraphQL API starts with a schema that defines the available types and how they relate:
type User {
id: ID!
name: String!
email: String!
posts: [Post!]!
}
type Post {
id: ID!
title: String!
body: String!
author: User!
}
type Query {
post(id: ID!): Post
}
type Mutation {
createPost(title: String!, body: String!, authorId: ID!): Post!
}
Key Characteristics of GraphQL
- Single endpoint — all queries and mutations go to the same URL; the query itself, not the URL, determines what's fetched.
- Strongly typed schema — every field has a declared type, so tooling can validate a query before it's ever sent, and generate documentation automatically.
- Client-specified shape — the client decides exactly which fields it needs; the server never sends unrequested data.
- Mutations and subscriptions —
Queryreads data,Mutationwrites data, andSubscriptionpushes real-time updates over a persistent connection (e.g. WebSockets).
A Worked GraphQL Example
The same "post + author" page from the REST example becomes a single request in GraphQL:
query {
post(id: 101) {
title
body
author {
name
}
}
}
{
"data": {
"post": {
"title": "REST 101",
"body": "...",
"author": { "name": "Asha Rao" }
}
}
}
Notice the response contains exactly title, body, and author.name — no email, no second request. A mutation to create a post looks similar, but uses the mutation keyword:
mutation {
createPost(title: "GraphQL 101", body: "...", authorId: 7) {
id
title
}
}
Advantages and Disadvantages of GraphQL
Advantages:
- Solves over-fetching and under-fetching by letting the client shape the response.
- One request can gather deeply nested, related data that would take several REST calls.
- The schema is self-documenting and enables strong client-side tooling (autocomplete, type generation).
Disadvantages:
- A single complex query can trigger expensive server-side work (e.g. deeply nested queries hitting the database many times) — this needs deliberate cost limiting.
- HTTP-level caching mostly stops working, since every query is a
POSTto the same URL; caching must be handled at the application layer instead. - More setup complexity: schema design, resolvers, and query-cost analysis are additional concerns REST doesn't have.
Request Flow: REST vs GraphQL
REST trades round trips for simplicity and cacheability; GraphQL trades a more complex server for a leaner, client-driven response.
Key Terms
| Term | Definition | Context/Related Concepts |
|---|---|---|
| API | A contract allowing one program to request data/services from another | Umbrella term covering REST, GraphQL, SOAP, gRPC |
| REST | An architectural style using HTTP methods and resource-based URLs | Stateless, cacheable, one URL per resource |
| Resource | An object or entity exposed by an API (a user, an order) | Identified by a URL in REST |
| Endpoint | A specific URL an API exposes for a resource or action | REST has many; GraphQL typically has one |
| HTTP method (verb) | GET, POST, PUT, PATCH, DELETE — describes the action to perform | Core to REST's uniform interface |
| Statelessness | Each request contains all information needed; server stores no client context between requests | Enables horizontal scaling |
| Over-fetching | Receiving more data in a response than the client needs | Common REST drawback; solved by GraphQL |
| Under-fetching | Needing multiple requests to gather related data | Common REST drawback; solved by GraphQL |
| GraphQL | A query language and runtime letting clients specify the exact shape of the response | Single endpoint, strongly typed schema |
| Schema | The GraphQL type definitions describing available data and operations | Enables validation and tooling |
| Query (GraphQL) | A read operation requesting specific fields | Analogous to REST GET |
| Mutation (GraphQL) | A write operation that creates, updates, or deletes data | Analogous to REST POST/PUT/DELETE |
| Resolver | Server-side function that fetches the data for a specific GraphQL field | Where the actual database/service calls happen |
| Idempotent | An operation that produces the same result no matter how many times it's repeated | GET, PUT, DELETE are idempotent; POST is not |
Common Mistakes
-
Misconception 1: "GraphQL is strictly better than REST, so REST is obsolete."
- Why it's wrong: GraphQL solves specific problems (over/under-fetching, multiple round trips) at the cost of others (HTTP caching, simplicity, protection against expensive queries). Many APIs — especially simple CRUD services or public APIs relying on CDN caching — are better served by REST.
- Correct explanation: The choice depends on the client's data-fetching needs. A mobile app aggregating many nested resources benefits from GraphQL; a simple public API serving cacheable, uniform resources often benefits from REST.
-
Misconception 2: "REST just means using JSON over HTTP."
- Why it's wrong: Sending JSON over HTTP without following REST's constraints (statelessness, resource-based URLs, uniform interface) is sometimes called an "RPC-style" API, not REST. Plenty of JSON APIs use verbs in URLs like
/getUserData— that's not RESTful. - Correct explanation: REST is defined by its architectural constraints, not its data format. A true REST API models nouns as URLs and uses HTTP methods to express actions on them.
- Why it's wrong: Sending JSON over HTTP without following REST's constraints (statelessness, resource-based URLs, uniform interface) is sometimes called an "RPC-style" API, not REST. Plenty of JSON APIs use verbs in URLs like
-
Misconception 3: "Because GraphQL lets clients query anything, authorization can be checked once at the API entry point."
- Why it's wrong: A single GraphQL query can touch many different types and fields in one request (e.g.
user { orders { payment { cardNumber } } }), so a single top-level permission check misses per-field authorization needs. - Correct explanation: Authorization in GraphQL must be enforced per-resolver (or per-field), just as REST must check authorization per-endpoint — the flexibility of a single endpoint doesn't reduce the number of access-control decisions needed, it just moves them inside resolvers.
- Why it's wrong: A single GraphQL query can touch many different types and fields in one request (e.g.
Comparison and Connections
| Concept A | Concept B | Key Difference |
|---|---|---|
| REST | GraphQL | REST exposes many URLs, one per resource, returning fixed shapes; GraphQL exposes one endpoint where the client specifies the exact fields it wants |
| Over-fetching | Under-fetching | Over-fetching means receiving unused data in one response; under-fetching means needing multiple requests to gather related data — both are REST pain points GraphQL targets |
| Query (GraphQL) | Mutation (GraphQL) | A query reads data without side effects; a mutation performs a write/side-effecting operation, analogous to REST's GET vs POST/PUT/DELETE |
| REST caching | GraphQL caching | REST reuses HTTP/CDN caching keyed by URL; GraphQL typically needs application-level caching (e.g. per-object caching by ID) since most requests are POSTs to one URL |
| API versioning (REST) | Schema evolution (GraphQL) | REST commonly versions with new URLs (/v2/users); GraphQL favors adding new fields/types while deprecating old ones, since clients only request fields they use |
| SOAP | REST/GraphQL | SOAP is an older, XML-based, strictly-typed protocol with formal contracts (WSDL); REST and GraphQL are lighter-weight, HTTP-native, and JSON-first by convention |
Practice Questions
Recall
-
What do the letters REST stand for, and who introduced it?
- Answer guidance: Representational State Transfer, introduced by Roy Fielding in his 2000 doctoral dissertation.
-
In GraphQL, what is the difference between a query and a mutation?
- Answer guidance: A query is a read operation that requests data without changing server state; a mutation is a write operation that creates, updates, or deletes data — analogous to REST's
GETversusPOST/PUT/PATCH/DELETE.
- Answer guidance: A query is a read operation that requests data without changing server state; a mutation is a write operation that creates, updates, or deletes data — analogous to REST's
Understanding
-
Explain why REST APIs are easier to cache with standard HTTP infrastructure than GraphQL APIs.
- Answer guidance: REST resources are identified by unique, stable URLs (
GET /users/42), so browsers, CDNs, and proxies can cache responses keyed by that URL. GraphQL typically sends all queries asPOSTrequests to a single endpoint, so the URL alone doesn't identify what was requested — caching must inspect the query body or be implemented at the application layer instead.
- Answer guidance: REST resources are identified by unique, stable URLs (
-
Why does statelessness matter for scaling a REST API across many servers?
- Answer guidance: Because a stateless request carries everything the server needs to process it (e.g. an auth token), any server behind a load balancer can handle any incoming request without needing to know about prior requests from that client. This lets you add or remove servers freely without needing "sticky sessions" tied to a specific server.
Application
-
You're building a mobile app screen that shows a user's profile, their last 5 orders, and each order's shipping status — three nested levels of related data. Would you lean toward REST or GraphQL for this screen's API, and why?
- Answer guidance: GraphQL is a strong fit here: a single query can request
user { orders(last: 5) { status } }in one round trip, avoiding the 1 (user) + 5 (one per order) or more REST calls that under-fetching would otherwise require, which matters especially on slower mobile networks.
- Answer guidance: GraphQL is a strong fit here: a single query can request
-
A public weather API serves the same forecast data to millions of clients and wants to rely heavily on CDN caching to reduce server load. Which style — REST or GraphQL — better supports this goal, and why?
- Answer guidance: REST is the better fit, because
GET /forecast/londonis a fixed, cacheable URL that CDNs and browsers can store and reuse for every client requesting the same forecast, without hitting the origin server again. GraphQL's singlePOSTendpoint bypasses most default HTTP caching.
- Answer guidance: REST is the better fit, because
Analysis
-
Compare how REST and GraphQL each handle the problem of an API evolving over time (adding/removing fields) without breaking existing clients.
- Answer guidance: REST typically handles breaking changes by introducing a new version in the URL (
/v2/users), letting old clients keep using/v1/usersuntil they migrate — this requires maintaining multiple versions in parallel. GraphQL favors additive evolution: new fields can be added to a type without affecting clients that don't request them, and old fields can be marked@deprecatedand eventually removed once no client queries them — schema introspection tools can detect which fields are still in use.
- Answer guidance: REST typically handles breaking changes by introducing a new version in the URL (
-
A team complains that their GraphQL API has become slow because a single client query nests five levels of related objects, each triggering a database call. Analyze the cause and propose at least one mitigation.
- Answer guidance: The cause is that GraphQL's flexibility lets a client request arbitrarily deep, nested data in one query, and if each nested field is resolved with a separate database call (the "N+1 problem"), a single request can trigger dozens of queries. Mitigations include: using a batching/caching layer like DataLoader to combine repeated lookups, setting query depth/complexity limits on the schema, and pre-fetching/joining related data at the resolver level instead of resolving each field independently.
FAQ
Q: Do I need to choose only REST or only GraphQL for my whole application? A: No — many real-world systems use both. A team might expose a public REST API for simple, cacheable integrations while using GraphQL internally for a complex front-end that needs flexible, nested data in one request.
Q: Is GraphQL a database? A: No. GraphQL is a query language and runtime for APIs, not a database. Resolvers behind a GraphQL schema can fetch data from a SQL database, a NoSQL store, another REST API, or any combination — GraphQL just standardizes how the client asks for it.
Q: Why can't REST just add a way to select specific fields, like GraphQL does?
A: Some REST APIs do add ad hoc field-selection query parameters (e.g. ?fields=name,email), but this isn't part of the REST standard and every API implements it differently (if at all), so clients can't rely on it universally. GraphQL standardizes field selection as a core language feature every GraphQL API supports the same way.
Q: Is a GraphQL API always slower than a REST API? A: Not inherently — a well-designed GraphQL query that fetches related data in one request can be faster overall than several separate REST round trips, especially on high-latency networks. Performance problems in GraphQL usually come from unbounded query complexity or unoptimized resolvers (the N+1 problem), not from GraphQL itself.
Q: What is REST's "uniform interface" constraint actually for? A: It means every resource is manipulated the same way — the same HTTP methods, the same status codes, the same conventions — regardless of what the resource represents. This is what lets a developer who has never seen your specific API still predict how to use it correctly, because they already know how HTTP works.
Quick Revision
- API = a contract letting programs request data/services from each other; REST and GraphQL are two common styles for designing APIs.
- REST: resource-based URLs (
/users/42), standard HTTP methods (GET,POST,PUT,PATCH,DELETE), stateless, cacheable via HTTP. - REST's core weaknesses: over-fetching (unused fields returned) and under-fetching (multiple requests needed for related data).
- GraphQL: single endpoint, client sends a query specifying exact fields; server returns exactly that shape.
- GraphQL schema defines
types, aQuerytype (reads), and aMutationtype (writes);Subscriptionhandles real-time pushes. - GraphQL solves over/under-fetching but loses easy HTTP/CDN caching, since most requests are
POSTs to one URL. - REST versions with new URLs (
/v2/...); GraphQL evolves additively, deprecating unused fields instead of versioning URLs. - Statelessness (shared by REST) means every request carries all context needed — no server-side session memory required — enabling easy horizontal scaling.
- GraphQL's N+1 problem: naive resolvers can trigger one database call per nested field; solved with batching tools like DataLoader.
- Authorization must be checked per-endpoint in REST and per-resolver/field in GraphQL — neither style automates access control.
- Choose REST for simple, cacheable, resource-oriented APIs; choose GraphQL when clients need flexible, nested data in one round trip.
Related Topics
Prerequisites
- Introduction to Web Development (client-server model, HTTP basics)
- HTTP methods and status codes
Related Topics
- Web Security Essentials (authentication and authorization for APIs)
- Databases and query optimization (resolvers, the N+1 problem)
Next Topics
- API authentication (OAuth, JWTs, API keys)
- Microservices and service-to-service communication