GraphQL vs REST
Concept
REST is great, but it has a fundamental flaw: the Server dictates exactly what the Client gets.
If a mobile app only needs a user’s name to render a header, it calls GET /users/123. The REST API returns the name, but also the email, address, credit_card_hash, and 50 other fields. This wastes massive amounts of mobile bandwidth.
GraphQL flips the paradigm. The Server defines what data is available, but the Client explicitly requests only what it needs.
Mental Model
The 3 Core GraphQL Concepts
- The Schema (Strong Typing): The server defines a strict graph of types.
type User { id: ID!, name: String!, posts: [Post!]! } type Post { id: ID!, title: String! } - Queries (Reads): The client sends a nested JSON-like structure to ask for data.
query { user(id: "1") { name, posts { title } } } - Mutations (Writes): The client sends a command to alter data (similar to POST/PUT in REST).
mutation { createPost(userId: "1", title: "Hello") { id } }
Trade-Offs
Pros of GraphQL:
- No Over-fetching: Saves massive bandwidth, especially for mobile users on 3G networks.
- No Under-fetching: You can fetch a User, their Posts, and the Comments on those posts in one single network request. In REST, this might require 15 separate
GETrequests. - Excellent Developer Experience: Tools like GraphiQL automatically generate interactive documentation and autocomplete for the frontend team based on the backend schema.
Cons of GraphQL:
- The N+1 Query Problem: Because resolvers are nested, fetching 10 Users and their Posts can accidentally trigger 1 database query for the users, and 10 separate queries for the posts (11 queries total). (Fixed by using Facebook’s
DataLoaderutility to batch queries). - Caching is a Nightmare: In REST,
GET /users/1can be cached seamlessly by Cloudflare or standard CDNs. In GraphQL, everything is aPOST /graphqlrequest with a massive, unique body. Standard CDNs cannot cache this. You have to implement complex Application-level caching.
Real-World Usage
- Facebook: Invented GraphQL to solve the problem of rendering complex mobile news feeds efficiently.
- GitHub: Migrated their public API from REST (v3) to GraphQL (v4) because third-party developers were making thousands of REST calls to calculate simple repository statistics.
Interview Questions
Q: In REST, we use HTTP status codes (like 404 Not Found) to handle errors. How does GraphQL handle errors?
A: GraphQL almost always returns an HTTP 200 OK, even if the query completely failed! Instead of using HTTP status codes, GraphQL returns a JSON payload containing an errors array alongside the data object. The frontend must parse the JSON and inspect the errors array to determine what went wrong. This breaks traditional HTTP monitoring tools.
Q: A malicious user sends a GraphQL query that asks for a User, their Posts, the Author of those Posts, the Posts of that Author… infinitely nesting the query. This will crash your database. How do you prevent this?
A: This is a classic GraphQL DoS attack. You must implement two defenses on your GraphQL server:
- Query Depth Limiting: Reject any query that nests deeper than 5 or 6 levels.
- Query Complexity Analysis (Cost Limiting): Assign a “cost” to fields. A scalar like
namecosts 1 point. A connection likepostscosts 10 points. If the total cost of the incoming query exceeds a maximum threshold (e.g., 1000 points), reject it before executing any resolvers.