GraphQL is a query language for APIs. Instead of many endpoints each returning a fixed shape, there is one endpoint and the client describes exactly which fields it wants. It is worth the extra complexity when several very different clients consume the same data.
What is GraphQL?
With a REST API, the server decides what each endpoint returns. A mobile app that needs three fields from an object with forty downloads all forty, and a screen that needs data from three objects makes three round trips. On a fast connection nobody notices; on 4G in a lift, both problems are the reason the app feels slow.
GraphQL moves that decision to the client. There is one endpoint, and a request states exactly which fields of which objects it wants, however deeply nested. The response matches the request shape exactly.
The schema is typed and introspectable, which means tooling can generate client code and documentation from the server automatically — the same benefit FastAPI gives, applied to a graph of data rather than a list of endpoints.
When we choose GraphQL
When a web app, a mobile app and a partner integration all read the same data but need different slices of it. Maintaining a REST endpoint per client is where APIs go to accumulate cruft, and GraphQL removes that pressure.
When mobile bandwidth genuinely matters. Sending only the requested fields is a real saving on a phone in a basement car park, and that is the environment much of the GCC actually uses apps in.
When we do not use GraphQL
For most projects. A single web front end talking to its own backend has nothing to gain: REST is simpler, cacheable by default, and every developer already understands it. Adding GraphQL there is complexity bought for no benefit, and we will say so even when a client has arrived asking for it.
It also breaks HTTP caching. REST responses can be cached by a CDN trivially; GraphQL requests are POSTs with varying bodies and need a caching strategy built deliberately. On a read-heavy public API that trade is usually bad.
What we build with GraphQL
One API for web, mobile and partners
Where three clients need overlapping but different data. Each asks for its own shape against one schema, so adding a field for the mobile team does not require a new endpoint or risk breaking the web app.
A layer over several existing systems
Where data lives in an ERP, a CRM and a database, GraphQL can present it as one graph so the front end asks one question instead of orchestrating three calls and merging the results itself.
APIs consumed by several clients
A web app, a mobile app and a partner integration reading the same schema, each asking only for the fields it needs. This is the case where GraphQL clearly beats maintaining three REST variants.
Mobile apps on poor connections
One request returning exactly the fields a screen renders, instead of four REST calls each carrying data the screen throws away. On a 3G connection in a basement car park, that difference is visible.
How we ship GraphQL projects
With query depth and complexity limits from day one. An open GraphQL endpoint lets a client request a deeply nested query that costs the database an enormous amount of work, and that is a denial-of-service vector rather than a theoretical concern.
With batched loading for related records, or a simple query becomes hundreds of database round trips — the single most common way a GraphQL API ends up slower than the REST one it replaced.
What GraphQL costs you
It is more moving parts. A schema, resolvers, batching, depth limits and a caching strategy all have to be built and maintained, and every one is somewhere a bug can live.
Debugging is harder too. A slow REST endpoint is one URL to investigate; a slow GraphQL query could be slow because of any field in it, and finding out which needs tracing that has to be set up in advance.
Caching is genuinely harder than with REST. A REST endpoint has a URL a CDN can cache; a GraphQL query is a POST body, which most caching layers will not touch without extra work.
Rate limiting is also less obvious — a single request can ask for an enormous amount of data, so limiting by request count protects nothing. Query cost analysis is the answer, and it needs building rather than switching on.
GraphQL questions we get asked
Only if REST is causing a specific, describable problem — usually a mobile app fetching far more data than it needs, or a proliferation of near-duplicate endpoints. If you cannot name the pain, the migration will cost more than it returns and we will advise against it.
REST unless you have several different clients with genuinely different data needs. For one web front end talking to one backend, REST is simpler to build, simpler to cache and simpler for the next developer to understand.
It can be, if the resolvers are naive — one query asking for a list and a related field each triggers a database call per row. That is a known pattern with a known fix, and it needs to be handled deliberately rather than discovered under load.
Yes, and it is a reasonable way to modernise without a rewrite. The GraphQL layer calls the existing endpoints and presents one schema to clients. It adds a hop, so it is worth doing when the client-side simplification is genuinely worth that cost.
No — it is an HTTP request and any client can send one. Dedicated libraries add caching and code generation from the schema, which is worth having on a large front end and unnecessary for a partner integration that calls three queries.