Designing One API for Both a Web Dashboard and a Mobile App

TIL that a REST API originally shaped around the web dashboard's screens needed real redesign, not just new endpoints, once a React Native app started consuming it too.

2 min read

Sabin Shrestha

Full-Stack Developer — Next.js, React & React Native

The Problem #

The API started life serving one dispatch dashboard, so endpoints were shaped around exactly what that dashboard's screens needed — a single /orders endpoint that returned every field the dashboard table displayed, including several the driver app would never use and one field the driver app couldn't get any other way.

Context #

Once a React Native driver app needed the same data, it became clear the API wasn't a neutral data layer — it was an extension of the dashboard's UI, just returned as JSON instead of HTML.

What I Tried #

Adding driver-specific fields onto the existing /orders response and having the mobile app ignore what it didn't need.

What Went Wrong #

The response payload grew for a client (mobile, often on a weaker connection) that needed less data than the client (web, on broadband) it was originally designed for. Any change to serve the dashboard better risked silently breaking a field the driver app depended on, because both were reading the same undocumented, implicit contract.

The Solution #

Split the endpoint by client intent rather than by "resource name": a lean /driver/orders shaped around exactly what the driver app's one core screen needs, and a fuller /dashboard/orders for the dispatcher view — both reading from the same underlying data model, but with distinct, explicit response shapes.

// Same underlying order, two intentionally different views
app.get("/driver/orders", (req, res) => res.json(toDriverView(orders)));
app.get("/dashboard/orders", (req, res) => res.json(toDashboardView(orders)));

Why It Works #

A shared backend doesn't require a shared response shape. Treating "the API" as one endpoint per resource conflates the data model (which genuinely should be shared) with the response contract (which shouldn't be, once two clients have meaningfully different needs).

Lessons Learned #

An API design that looks clean for one client can quietly become a liability the moment a second, differently-shaped client depends on it. The fix isn't to make one endpoint serve both — it's to stop assuming "one resource, one endpoint" in the first place.

What I Would Do Differently #

I'd design the response shape per client need from the start, even with only one client, so adding a second client later is a new endpoint, not a renegotiation of an existing one.

Backend-for-frontend (BFF) pattern, API versioning, client-specific response shaping.