Our services

If you can think it, we can make it brainsoft.

Choosing between REST and GraphQL for an internal API

Written By: BrainSoft In Backend

Internal APIs are a different animal from public ones. You control every consumer, so you can change a contract and ship the fix in the same afternoon. That freedom cuts both ways: it removes the main reason people reach for GraphQL (letting strangers query whatever they want) and it makes the cost of a bad choice land entirely on your own team. I've built both, and the deciding factors are usually boring ones like caching, tooling, and how many shapes one endpoint has to return.

Short answer: pick REST when you have one or two consumers, simple resource reads, and want HTTP caching and boring debugging. Pick GraphQL when several clients need different slices of the same graph, or when one screen would otherwise fan out into five round trips. Below is the checklist I actually run through, plus the hybrid that often wins.

Start with who is calling and how many shapes they need

Count the consumers first. A mobile app, a web dashboard, and a couple of background jobs hitting the same service is normal. If all three need roughly the same data, REST endpoints map cleanly and everyone reads the same docs. The trouble starts when the dashboard wants a summary list and the mobile app wants the same list plus per-item detail plus a count. Now you either build three endpoints or one endpoint with a ?expand= parameter that grows teeth.

  • One or two consumers, similar payloads: REST wins by default.
  • Three or more consumers with genuinely different payloads: GraphQL starts paying for itself.
  • Consumers you do not control (partners, external teams): REST is easier to version and support.

A quick test I use: write down the fields each consumer needs from the main resource. If the union is small and the overlap is large, REST. If each consumer needs a distinct subset and you keep adding query params, that is the signal.

The operational stuff nobody puts in the comparison posts

Caching is the biggest practical gap. A REST GET sits behind an HTTP cache, a CDN, or a reverse proxy with zero application code. GraphQL is usually a POST to a single endpoint, so a shared cache sees one URL and one method. You end up doing persisted queries, cache hints, or client-side normalization to get some of that back. For internal APIs on a private network, that may not matter. If you have heavy read traffic and a proxy already in place, it matters a lot.

Debugging differs too. With REST you can curl a URL and read the response. With GraphQL you paste a query into a client, and errors come back inside a 200 response, so your monitoring has to parse the body instead of trusting the status code. Neither is hard, but the second one changes how you write alerts.

curl -s https://api.internal/v1/orders/42
# status code tells you what happened

curl -s https://api.internal/graphql \
  -H 'content-type: application/json' \
  -d '{"query":"{ order(id:42){ id status } }"}'
# 200 even when the query failed; check "errors"

Schema ownership is the long game. A REST contract is a set of URLs and payloads that people copy into their code. A GraphQL schema is a typed artifact you can lint, diff, and check for breaking changes in CI. If your team already runs codegen and wants compile-time safety across languages, GraphQL gives you that for free. If not, adding it is real work.

Where I land, and the hybrid that usually wins

Most internal systems I have worked on end up as REST for writes and commands, GraphQL for reads on the messy aggregate. Mutations in REST are easy to reason about: one endpoint, one resource, idempotency keys, clear status codes. Reads are where clients complain about over-fetching, so that is where a query layer earns its keep.

  • REST for auth, webhooks, file uploads, and anything with side effects.
  • GraphQL for the read-heavy dashboard that pulls from several services.
  • A thin BFF in front if you want one entry point for clients.

Do not start with GraphQL because it sounds modern. Start with REST, and when you catch yourself adding the fourth query parameter to the same endpoint, that is the moment to introduce a query layer. If you want a second opinion on an existing API, get in touch and we can look at the traffic and the consumer list together.

Frequently asked questions

Is GraphQL always slower than REST?

No. A single GraphQL query can replace several REST round trips and be faster overall. The risk is unbounded queries that hit the database hard, so you need depth limits, query cost analysis, and a timeout.

Can we run REST and GraphQL on the same backend?

Yes, and it is common. Keep REST for writes and simple resources, and put a GraphQL layer over the read paths that clients keep asking you to reshape. Both can share the same service layer underneath.

How do we version a GraphQL schema for internal clients?

Prefer additive changes and deprecate fields with the @deprecated directive. Run a schema diff in CI so a removed field fails the build before it reaches another team.


#Backend