Designing Your First REST API: What Really Matters
Resource naming, status codes, error formats, pagination and versioning: the decisions that are easy now and expensive to change later.
Building an API that works is not difficult. Building one that other developers find easy to use, and that you can change later without breaking existing clients, takes more thought. Once a mobile app or a partner integration depends on your API, every decision you made becomes hard to reverse. These are the ones worth getting right early.
Model resources, not actions
Name endpoints after things, using plural nouns: /orders and /orders/42, not /getOrder or /createNewOrder. Let the HTTP method express the action:
GETreads a resource and must not change anything.POSTcreates a resource, or triggers an action that does not fit elsewhere.PUTreplaces a resource andPATCHchanges part of it.DELETEremoves it.
Nested paths such as /orders/42/items are fine for clear parent-child relationships. Avoid going more than two levels deep.
Use status codes accurately
Clients, proxies and monitoring tools all rely on status codes. A few that you will use constantly:
200for a successful read or update,201when something was created,204when there is nothing to return.400for malformed requests and422for well-formed requests that fail validation.401when the caller is not authenticated and403when they are authenticated but not allowed.404when the resource does not exist and409for conflicts, such as a duplicate email.429when the caller is rate limited, and500only for genuine server faults.
A common mistake is returning 200 with an error message in the body. It breaks retry logic and makes failures invisible in your logs.
Make errors predictable
Every error should have the same structure, for example a stable machine-readable code, a readable message, and for validation errors a list of the fields that failed. Clients can then handle errors with code instead of parsing text. Validate input at the edge of your API, and never expose stack traces or database errors to callers.
Plan for growth
- Pagination. Every list endpoint eventually returns too much data. Add it from the start. Offset pagination (
?page=2&limit=20) is simple; cursor-based pagination stays accurate when records are added or removed while someone is paging. - Filtering and sorting. Use query parameters such as
?status=paid&sort=-created_atand keep the naming the same across endpoints. - Versioning. Put a version in the path (
/v1/orders) or a header, so you can make breaking changes without disturbing existing clients. Adding a new field is not breaking; renaming or removing one is. - Idempotency. Networks fail and clients retry.
GET,PUTandDELETEare idempotent by definition. ForPOSToperations such as payments, accept an idempotency key so a retried request does not charge a customer twice.
Security basics
Use HTTPS everywhere. Authenticate every request that is not intentionally public, and check authorisation on the server for each resource, not just at login: a user who changes /orders/42 to /orders/43 must not see someone else's order. Rate limit by client, and never trust values the client sends, including prices and user IDs.
Design the API you would want to be calling at 2 a.m. while debugging a production incident.
Document as you build
An OpenAPI specification describes your endpoints, parameters and responses in one file. From it you can generate interactive documentation, client libraries and request validation. Writing it alongside your code, or generating it from your code, keeps documentation from drifting out of date. Include a real example request and response for every endpoint.
Want to learn Backend properly?
Join a live, mentor-led cohort and build real projects. We reply within one business day.