Architecture

Designing APIs for mobile clients

Back to Blog

Mobile changes the API contract

A mobile client may be suspended mid-request, move between networks, remain several releases behind, and need to present useful state while offline. Those constraints should appear in the API contract rather than being left for client code to infer.

A phone on a cellular network deals with high latency, limited bandwidth, and a battery that drains with every network call. Users switch between WiFi and LTE mid-request. They walk into elevators. They close the app and reopen it thirty seconds later expecting the same state.

The best API review includes backend and mobile engineers together. They can agree on retry safety, compatibility, pagination, errors, caching, and observability before either side builds around an assumption.

Measure payload and round-trip cost

Payload size matters, but so do request count, latency, parsing cost, and cacheability. Record response sizes and timings on a constrained network profile and a representative device. Optimize the endpoints that affect user journeys instead of imposing one arbitrary size limit everywhere.

Pagination done right: cursor-based, not offset

Offset-based pagination breaks on mobile. A user scrolls through a feed, the dataset shifts underneath them, and suddenly they see duplicate items or miss entries entirely. This is not a theoretical problem. It happens constantly in production.

Cursor-based pagination solves this. Instead of saying "give me page 5," the client says "give me the next 20 items after this cursor." The cursor is an opaque token that points to a stable position in the dataset.

A good pagination response includes three things: the data array, a next cursor, and a has_more flag. Nothing else is needed.

Error responses mobile clients can actually parse

Returning a raw 500 with an HTML error page is not helpful to a mobile client trying to show a toast message. Mobile apps need structured, predictable error responses they can parse programmatically and present to the user in context.

Every error response should follow the same shape. We use a simple structure across all our projects:

Mobile engineers should never have to regex-match an error message to figure out what went wrong.

Versioning that does not break old app versions

Web apps deploy instantly. You push a change and every user gets it. Mobile apps do not work that way. Users on version 2.1 of your app might not update for months. Some never will. Your API has to support them all.

Path, header, and media-type versioning can all work. More important is a compatibility policy the team can test. Prefer additive changes within a version, observe which app versions still call an endpoint, and define how a breaking change is introduced and retired.

Caching headers and ETags for mobile

Caching can reduce latency and unnecessary transfers, but the policy depends on the resource. Public reference data, private account state, and a one-time command should not share the same cache rules.

With ETags, a mobile client can make a conditional request. If the data has not changed, the server returns a 304 Not Modified with no body. That saves bandwidth, battery, and time. For data that changes infrequently, like user profiles or app configuration, this is a massive win.

GraphQL vs REST for mobile: a practical take

GraphQL lets mobile clients request exactly the data they need. No over-fetching. No under-fetching. In theory, it is perfect for mobile. In practice, it depends.

GraphQL shines when your mobile app has many screens with different data requirements hitting the same underlying models. Instead of building dozens of bespoke REST endpoints, you expose a graph and let the client query what it needs.

REST wins when your API surface is small and well-defined. It is simpler to cache at the HTTP layer. It is easier to monitor and rate-limit. The tooling is more mature.

Pick the tool that matches your team and your problem. Do not pick GraphQL because it is trendy. Do not avoid it because it is unfamiliar.

In our projects, we often use REST for straightforward CRUD operations and introduce GraphQL selectively for screens that aggregate data from multiple sources. Pragmatism beats purity.

Build APIs with mobile in mind from day one

Retrofitting mobile-friendliness into an existing API is painful and expensive. The best time to think about payload size, pagination, caching, and versioning is before you write the first endpoint.

If you are building a product that will have a mobile client, involve a mobile engineer in your API design review. They will catch problems that backend engineers simply do not think about.

Before implementation, write down the offline boundary, retry semantics, supported app versions, and error model. Those four decisions prevent more client-side workarounds than a fashionable transport choice.

Contact DEVSFLOW for a mobile-side review of an API contract or an existing failure trace.

Ali Assad

Ali Assad

Full Stack Engineer at DEVSFLOW Technologies