GraphQL API vs REST API

By

Tagged: GraphQL

Compare GraphQL and REST APIs: a single endpoint versus many, requesting exactly the fields you need versus over-fetching, and free HTTP caching REST gives you.

Since REST is such a popular approach to building APIs, and much more widespread than GraphQL, it’s fair to assume you are familiar with it, so let’s see the differences between GraphQL and REST.

REST is a concept

REST is a de-facto architecture standard but it actually has no specification and tons of unofficial definitions. GraphQL has a specification with released editions (the latest is September 2025), and it’s a Query Language instead of an architecture, with a well defined set of tools built around it (and a flourishing ecosystem).

While REST is built on top of an existing architecture, which in the most common scenarios is HTTP, GraphQL on the other hand is building its own set of conventions. REST still gets HTTP caching for free. GraphQL queries sent with GET can use that too, often through persisted queries.

A single endpoint

GraphQL has only one endpoint, where you send all your queries. With a REST approach, you create multiple endpoints and use HTTP verbs to distinguish read actions (GET) and write actions (POST, PUT, DELETE). GraphQL operations are typed by the query itself (query, mutation, subscription), not by the HTTP verb. Over HTTP you send queries with GET or POST, and mutations with POST only. The GraphQL over HTTP spec is still a draft, and it says mutations must not run over GET.

Tailored to your needs

With REST, you generally cannot choose what the server returns back to you, unless the server implements partial responses using sparse fieldsets, and clients use that feature. The API maintainer cannot enforce such filtering.

The API will usually return you much more information than what you need, unless you control the API server as well, and you tailor your responses for each different request.

With GraphQL you explicitly request just the information you need, you don’t “opt out” from the full response default, but it’s mandatory to pick the fields you want.

This helps saving resources on the server, since you most probably need less processing, and also network savings, since the payload to transfer is smaller.

A great way to visualize this is an example of a Pizza endpoint (I’m Italian, a Pizza example is perfect).

If you call GET /pizza/margherita, you will get the a pizza Margherita. If you call GET /pizza/napoli, you will get a pizza Napoli.

If you have 30 different flavors, you’ll have 30 endpoints (unless you pass the pizza name as a parameter to GET /pizza, for example)

But maybe you want a specific kind of pizza, but without one ingredient you don’t like. That’s easy to ask to the waiter, but kinda hard to express to a REST endpoint.

A GraphQL endpoint would let you call /pizza, and you ask for specific ingredients, to build the perfect pizza you want.

A REST call returns the whole pizza:

GET /pizza/margherita
{
  "name": "margherita",
  "price": 8,
  "ingredients": ["tomato", "mozzarella", "basil"],
  "allergens": ["milk"],
  "available": true
}

A GraphQL query asks for the two fields you need:

{
  pizza(name: "margherita") {
    name
    ingredients
  }
}
{
  "data": {
    "pizza": {
      "name": "margherita",
      "ingredients": ["tomato", "mozzarella", "basil"]
    }
  }
}

GraphQL makes it easy to monitor for fields usage

With REST usually there is no way to determine if a field is needed by the client, so when it comes to refactoring or deprecating, it’s impossible to determine actual usage.

GraphQL makes it possible to track which fields are used by clients.

Access nested data resources

GraphQL allows to generate a lot less network calls.

Let’s do an example: you need to access the names of the friends of a person. If your REST API exposes a /person endpoint, which returns a person object with a list of friends, you generally first get the person information by doing GET /person/1, which contains a list of ID of its friends.

Unless the list of friends of a person already contains the friend name, with 100 friends you’d need to do 101 HTTP requests to the /person endpoint, which is a huge time cost, and also a resource intensive operation.

With GraphQL, you need only one request, which asks for the names of the friends of a person:

{
  person(id: 1) {
    name
    friends {
      name
    }
  }
}

The server still has to load those friends. If the resolver calls the database once per friend, you just moved the N+1 problem to the server. DataLoader or a similar batch is how you avoid that.

Types

GraphQL’s type system is built into the spec. A REST API is often JSON, and types live in a separate description like OpenAPI (JSON Schema). The OpenAPI to TypeScript tool turns that description into interfaces in the browser.

Which one is better?

Organizations around the world are questioning their API technology choices and they are trying to find out if migrating from REST to GraphQL is best for their needs.

GraphQL is a perfect fit when you need to expose complex data representations, and when clients might need only a subset of the data, or they regularly perform nested queries to get the data they need.

REST is the simpler pick for a resource that always looks the same. A file download, a webhook, a CRUD record you cache by URL. Those stay cheap with HTTP verbs and HTTP caching.

As with programming languages, there is no single winner, it all depends on your needs.

Also, there’s a point I want to make: you can use both.

You can mix and match REST and GraphQL depending on your needs, and sometimes it’s the best thing to do.

Want me to talk about your product? You can sponsor this site.

Related posts about graphql: