Table Of Contents
    Share
    AI Summary

    Four REST API decisions, naming, errors, pagination and versioning, decide how fast your frontend and mobile developers can ship. Here are the rules we follow and why.

    API Design Rules That Save Your Frontend Team Time

    api designrestbackendpaginationerror handling
    Last Update:20 October 2026
    API Design Rules That Save Your Frontend Team Time

    Most API pain is not a backend problem. It shows up in the frontend as a loading spinner that never stops, an error toast that says "Something went wrong", or a list that duplicates rows when a user scrolls. The cause is usually a decision made in the first week of the API: a vague name, an error shape that changes by endpoint, a pagination style that cannot survive new data.

    This post is for product teams building a REST API that a web app and a mobile app will both use. It covers four areas where small rules save the most time: naming, errors, pagination and versioning. Write them into a one-page style guide that new developers read on day one.

    Naming: make the URL predictable

    A frontend developer should be able to guess an endpoint before reading the docs. That only works if naming is boring and consistent.

    • Use plural nouns for collections. GET /orders returns a list. GET /orders/42 returns one order.
    • Use nouns, not verbs, in the path. POST /orders creates an order. Avoid /createOrder or /getOrderList.
    • Nest only one level. GET /orders/42/items is fine. GET /customers/7/orders/42/items/3/options is a sign the item should be addressable on its own.
    • Pick one casing and keep it. If JSON fields are snake_case, every field is snake_case. Mixing createdAt and updated_at in one response costs every client a mapping layer.
    • Name booleans as statements. is_active, has_unread_messages. Avoid status: 1.
    • Use the same word for the same thing everywhere. If the database says customer and the app says user, the API should pick one and hold to it.

    Dates, money and IDs

    Three field types cause more bugs than any others.

    • Dates: send ISO 8601 with a time zone, such as 2026-03-14T09:30:00Z. Never send a locale-formatted string. Let the client format it.
    • Money: send the amount as an integer in the smallest unit (cents, paisa) plus a currency code. Floating point amounts will eventually print 19.990000000000002 somewhere.
    • IDs: treat them as opaque strings in the contract, even if they are integers today. If you move to UUIDs later, clients do not break.

    Errors: one shape, always

    When a request fails, the client needs three things: whether to retry, what to show the user, and which field to highlight. A single consistent error body gives all three.

    Here is a shape we like:

    {
      "error": {
        "code": "validation_failed",
        "message": "Some fields need attention.",
        "request_id": "req_8f3a1c",
        "details": [
          { "field": "email", "code": "invalid_format", "message": "Enter a valid email address." }
        ]
      }
    }

    The rules behind it:

    1. Use the correct HTTP status. 400 for malformed input, 401 for not signed in, 403 for not allowed, 404 for not found, 409 for a conflict, 422 for valid syntax but failed business rules, 429 for rate limits, 5xx only when the server is at fault. A 200 with { "success": false } hides failures from every monitoring tool and every HTTP client library.
    2. Give every error a stable machine code. The code is for the program, the message is for a human. Frontend developers write if (error.code === "email_taken") and show their own localized copy. If they have to match on message text, you can never reword a message.
    3. Return field-level details for validation. Send all failing fields in one response, not the first one found. Otherwise users fix one field, resubmit, and meet the next error.
    4. Include a request ID. When a user reports a problem, support can paste the ID into the logs. This costs one line of middleware.
    5. Never leak internals. No stack traces, no SQL fragments, no file paths in the body. Log them on the server.

    A mistake we see often: a different error shape per framework layer, so the auth middleware returns { "msg": "..." } and the controller returns { "error": "..." }. Fix it with one error-handling layer at the edge that converts everything into the shared shape.

    Pagination: choose cursors for anything that changes

    Any list that can grow needs pagination from day one. Adding it later is a breaking change.

    There are two common styles.

    Offset pagination uses ?page=3&limit=20. It is easy to build and easy to jump to page 50. The weakness: if a new row is inserted while the user is on page 2, page 3 repeats an item or skips one. Large offsets are also slow in many databases, because the engine still counts past all the skipped rows.

    Cursor pagination uses ?limit=20&after=eyJpZCI6MTIzfQ. The server returns an opaque token pointing to the last item seen. Inserts and deletes do not shift results. It is the better fit for feeds, activity logs, chat history and any infinite scroll on mobile.

    Our decision rule:

    • Use cursors when the list changes often or is shown as infinite scroll.
    • Use offset when users need to jump to a page number, such as an admin table with a few thousand rows that rarely changes.

    Whichever you choose, the response should say what to do next:

    {
      "data": [ ... ],
      "page": {
        "next_cursor": "eyJpZCI6MTQzfQ",
        "has_more": true
      }
    }

    The client should never have to compute the next URL or guess whether it reached the end. Set a sensible default limit (for example 20) and a maximum (for example 100), and document both. Also decide the default sort order. An unsorted list is a bug waiting for a database upgrade.

    Placeholder image: Side-by-side diagram of offset vs cursor pagination, showing a new row inserted between page 1 and page 2 causing a duplicate in the offset version and no duplicate in the cursor version

    Filtering and sorting

    Keep query parameters flat and named after fields: ?status=paid&sort=-created_at. Return 400 for a filter you do not support, rather than silently ignoring it.

    Versioning: plan to be wrong

    You will change the API. The question is whether you break old clients when you do. This matters most for mobile apps, because users run old app versions for months and you cannot force an update instantly.

    A practical approach:

    1. Put the major version in the path: /v1/orders. It is visible in logs, easy to route, and easy to test with a link.
    2. Treat additive changes as non-breaking. New optional fields, new endpoints and new enum values are safe if clients are told to ignore what they do not recognise. Write that rule into the guide.
    3. Treat these as breaking: removing or renaming a field, changing a type, changing the meaning of a value, making an optional parameter required, tightening validation.
    4. Deprecate before removing. Announce the change, add a Deprecation or Sunset response header, and log which clients still call the old endpoint. Remove it only when the logs show nobody is using it.
    5. Keep versions few. Supporting v1, v2 and v3 at once multiplies testing. Aim for two live versions at most.

    For mobile, add one more safeguard: a minimum supported app version the server can check, so you can show a "please update" screen when an old build can no longer work.

    FAQ

    Should we use REST or GraphQL?

    Neither is wrong. REST with the rules above is simpler to cache, monitor and onboard people onto. GraphQL helps when many different clients need very different shapes of the same data. For a typical product with one web app and one mobile app, start with REST and revisit when the pain is real.

    How early should the frontend developer see the API?

    Before it is built. Agree the request and response examples in a pull request or a shared document, then let the frontend work against a mock while the backend is built. Disagreements are cheap to fix while they are still text.

    Talk to us

    If your team is planning an API for a new product, or your current one is slowing down the frontend, we are happy to review it with you. Email hello@risingstation.com or reach us at risingstation.com/contact-us.

    Md Kabir Hossain

    Md Kabir Hossain

    Co-Founder & CTO

    Subscribe for the Weekly Updates

    We value your privacy. Review our Privacy Policy for more details.

    Find the right solution with our experts

    API Design Rules That Save Your Frontend Team Time | Rising Station