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:

  1. 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.
  2. Under-fetching (and the N+1 problem): You hit /api/posts to 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/id for 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.