22.06.2026 • 4 min read

DesignFlix 7: Compare REST and GraphQL With One Screen

The mobile course page needs a title and three lessons. The desktop page wants those plus reviews and an instructor summary. Should they call fixed endpoints, or ask for their own combinations of fields?

That's a more useful starting point for REST versus GraphQL than counting which one has more enthusiastic fans. Both can support the page. They put different responsibilities into the API contract, client and server.

Let's build the same course screen both ways and see where the work ends up.

Everything Everywhere All at Once scene

I asked for a name, not the multiverse.

Everything Everywhere All at Once · Tenor · Adapted dialogue

A resource-oriented API gives us defined responses

An HTTP API might expose /courses/17, /courses/17/lessons and /courses/17/reviews. Each route has a documented response and can use appropriate HTTP methods, status codes and cache rules.

The mobile client could read course details and the first lesson page. The desktop client could also fetch reviews. Those are understandable contracts, but the client may need more than one request to assemble the screen.

That isn't an unavoidable REST limitation. We could offer an expanded course representation or a dedicated page view, with query parameters controlling supported options. The trade-off becomes how many response shapes we want to design and maintain.

The original REST and GraphQL comparison

GraphQL lets the client select fields from a schema

A GraphQL API defines available types and fields. Within that schema, the client chooses what it needs. For an illustrative course schema, the mobile query could be:

query MobileCourse {
  course(id: "17") {
    title
    lessons(first: 3) {
      title
      durationMinutes
    }
  }
}

The server resolves those fields and returns the requested shape. The desktop query can ask for reviews and instructor details if the schema exposes them, without requiring a new endpoint just for that combination.

This is a concrete advantage when clients need many evolving combinations. It isn't access to arbitrary database columns: the schema and resolvers define what's available. The GraphQL query guide explains field selection and nested queries.

One network request can still mean many backend queries

Our GraphQL query is one client request. Its course, lessons, reviews and instructor fields may still require several database or service lookups.

If each review resolves its author with a separate query, a list of a hundred reviews can trigger a hundred author lookups. This is the N+1 problem: a main query followed by repeated related queries. A REST handler can make the same mistake.

Batching, appropriate joins and request-scoped loaders can reduce that repeated work. Measure backend queries and latency rather than treating a single HTTP request as proof of efficient execution. GraphQL's performance guidance covers this distinction.

Cache around the contract, not the label

A public course response delivered with GET and suitable cache headers can fit browser, proxy and CDN caching well. Personalized enrolment or purchase data needs a different policy.

GraphQL isn't impossible to cache. Applications can use normalized client caches, persisted operations and appropriate server-side caching. GraphQL over HTTP can also support GET for queries under its transport rules. The HTTP serving guide explains the available request forms.

The challenge is that flexible operations produce different field combinations and may include different authorization contexts. Plan cache identity, freshness and access boundaries explicitly. Never let a convenient cache turn one student's private data into another student's response.

Flexibility needs a cost boundary

A schema can allow a valid query that asks for far more work than the application wants to perform. Deep nesting, large lists and many repeated fields can be expensive.

Set pagination, size and complexity policies appropriate to the API. Limit the work an operation may request, and enforce authorization on the relevant data, not just on reaching a /graphql endpoint. The GraphQL security guide explains these controls.

What does this operation cost after the server starts resolving its fields?

For resource-oriented APIs, expensive expansions and oversized pages need similar attention. Fixed routes reduce some choices, but don't guarantee cheap or authorized queries.

Queries, mutations and subscriptions have different roles

GraphQL queries retrieve data. Mutations expose supported changes, such as enrolling in a course. Subscriptions can provide updates over a supported long-lived delivery mechanism.

None of that removes business validation. An enrolment mutation must still check the account and course rules. A subscription requires server, transport and client support; writing a subscription-shaped operation doesn't automatically create real-time delivery.

REST-style HTTP APIs can also work alongside separate streaming or notification mechanisms. Choose those interactions by the feature's needs rather than making the entire system fit one comparison table.

Choose around the clients you actually have

For one stable course client, defined HTTP responses may be easy to document, cache and operate. For several clients with changing data needs, GraphQL's field selection may reduce the number of bespoke response shapes we maintain.

Try the mobile and desktop screens with realistic data. Count client requests, backend work, response sizes and the effort needed to add a field safely. The better design is the one that makes those screens easier to build and run under their real requirements.

Try it yourself

A GraphQL screen makes one HTTP request but loads one hundred reviews and then queries each author's profile separately. Has using one endpoint solved its performance problem?

A possible solution

No. The client round trip and backend work are different costs. This resolver design can produce an N+1 lookup pattern. Batch related reads or use suitable request-scoped loaders and data access, enforce pagination and authorization, and measure actual database or service calls. A REST handler can suffer the same underlying problem.

Share this article with your friends

Know someone who would enjoy this? Send it their way.

WhatsAppLinkedInXEmail