Back to articles
APIEngineering

What Frontend Devs Wish Backend APIs Did Differently

An opinionated wishlist from the consuming end — consistent response shapes, errors you can actually act on, pagination that works, and versioning that doesn't break me on a Tuesday. The small decisions that make an API a joy or a tax.

Yash Thakur
4 min read
What Frontend Devs Wish Backend APIs Did Differently

The short answer: what frontend devs want from your API is boring consistency — one response envelope used everywhere, errors that tell me what to do and not just that something broke, pagination that actually works, and versioning that won't break my client on a random Tuesday.

I've spent eight years on the consuming end of other people's APIs, and I've built plenty of my own to pay it back. Most API pain isn't about REST versus GraphQL or which framework you picked. It's a hundred small shape decisions that either make my client code boring or make it a minefield. Here's the wishlist I'd hand every backend team, written from the side of the fence that has to render your JSON.

Keep the response shape consistent

The single most expensive thing an API can do is return a different shape depending on the weather. One endpoint wraps data in { data: [...] }, the next returns a bare array, a third returns { results, items } for reasons lost to history. Now every fetch in my app needs a bespoke unwrap, and no abstraction survives contact with the inconsistency.

Pick one envelope and use it everywhere, including for a single resource.

When the shape is predictable, I write one unwrap() and move on. When it isn't, I write defensive code at every call site forever.

Errors should tell me what to do, not just that something broke

A 500 with an empty body is a dead end. I can't tell the user anything useful, I can't retry intelligently, and I can't log anything actionable. What I need is a machine-readable code I can branch on, a human-readable message I'd be comfortable showing a user, and enough field-level detail to light up a form.

With a stable code, my client can decide: show the field errors, trigger a token refresh on TOKEN_EXPIRED, or back off and retry on RATE_LIMITED. A bare status code forces me to guess, and guessing in error handling is how you ship a spinner that spins forever.

And please — use the status codes as designed. 200 with { "success": false } in the body means every HTTP tool, cache, and retry layer thinks the request worked. Return the 4xx.

Pagination that actually scales

Offset pagination (?page=3&limit=20) is fine until the dataset is both large and changing. Someone inserts a row while the user is on page 2, and now page 3 silently skips an item or shows a duplicate. For anything that grows, give me cursor pagination and tell me, in the response, how to get the next page.

Hand me a next_cursor and a has_more boolean and my infinite-scroll code is five lines. Make me compute page = Math.ceil(offset / limit) + 1 myself and I'll get it subtly wrong at the boundary.

Give me dates and money I can't misinterpret

Return timestamps as ISO 8601 with a timezone (2024-08-11T14:30:00Z), always UTC, and let the client localize. A bare "08/11/2024" has started a dozen bugs over whether it's August or November. For money, send an integer count of the smallest unit ("amount_cents": 4999) plus a currency code — never a float, because 0.1 + 0.2 is not 0.3 and your invoicing shouldn't depend on it.

Version so you can evolve without breaking me

You will need to change the API. That's healthy. What's not healthy is changing it under a client that's already in production. Put the version in the path (/v1/guests) or a header, and treat removing or renaming a field as a breaking change that earns a new version — not a Tuesday deploy.

The kindest thing a backend team ever did for me was announce a field deprecation in the response itself, with a Sunset header and a date, months before it went away. I migrated on my schedule instead of waking up to a production incident.

None of this is exotic. It's consistency, honesty in errors, pagination that respects a moving dataset, unambiguous primitives, and change you can plan around. Get those five right and your API stops being a tax my team pays on every feature — and starts being the boring, dependable thing I never have to think about. From the frontend, that's the highest compliment there is.

Written by Yash Thakur

Senior React Developer · 8+ years building for the web

More articles

Keep reading