Currently Available: Need a skilled Software Developer for your next project?
Categories
APIs

Designing RESTful APIs: Naming, Methods, and Error Handling

When you design an HTTP API, clients need to know which address identifies a resource, which HTTP method tells the server what to do, and how the server reports success or failure. A RESTful API organizes its interface around resources that clients can address, such as orders or customers. It uses HTTP methods to describe what clients want to do with those resources. A resource’s representation is the data the server returns or accepts, often in JSON.

Give clients a consistent public contract with clear resource paths and HTTP methods that follow their defined meanings. Match each status code to the result. Add structured error details when a status code alone does not tell the client how to respond. These choices help clients make requests and interpret results without depending on how the server stores its data.

Name resources in the URI

Use nouns for the things clients address, then use HTTP methods to express common operations. For an order API, /orders can identify a collection and /orders/{orderId} a specific order. The {orderId} segment stands for an identifier supplied in the request.

Plural collection names are a common convention, and HTTP leaves the choice to API designers. Choose a naming pattern and apply it consistently. Microsoft’s API design guidance recommends noun-based paths and plural collection names; Google’s resource-oriented guidance also uses consistent collection names. Neither convention requires every API to use the same URI grammar.

Name public resources after concepts clients understand, such as orders and customers. Avoid exposing database table names or internal service boundaries in paths. Those details can change independently of the API contract, and tying public names to them makes internal changes harder to separate from client-facing changes. Google’s resource-oriented design guidance describes this separation.

Use a nested path when a relationship is central to how clients use a resource. For example, /customers/{customerId}/orders represents orders associated with a customer. Limit nesting because a deeply nested URI ties the resource’s address to a particular relationship. Use a direct resource path when clients also need to address that resource independently.

Match methods to their HTTP meaning

HTTP methods tell the server what the client wants to do with the resource identified by the URI. The HTTP Semantics standard defines their meanings; an API should preserve those meanings rather than use familiar method names as loose synonyms.

Method Intended use Design detail
GET Retrieve a resource or collection. Treat it as a read request. Do not use it to trigger a change.
POST Submit data for processing by the target resource. A common pattern creates a resource at a collection, such as POST /orders.
PUT Replace the target resource’s current representation. Use it for a full replacement, and document any required fields.
PATCH Apply a patch document containing changes to a resource. Document the patch format and what each change means.
DELETE Remove the target resource’s current representation. Make clear which resource the URI identifies and what deletion means for clients.

PUT and PATCH have different semantics. A PUT /orders/{orderId} request supplies a replacement representation. A PATCH request supplies changes to apply, and the server applies the patch atomically: if it cannot complete the patch, it should not leave only part of it applied. The PATCH standard also recommends conditional requests, such as If-Match with an entity tag, when clients need to detect changes made since they last read the resource.

Two properties help clients understand what requests do and when they can repeat them. A safe method does not ask the server to change the target resource; GET is safe. An idempotent method has the same intended effect when repeated as it does when applied once. PUT and DELETE are idempotent under HTTP semantics. Their repeated responses do not have to be identical.

POST and PATCH are not inherently idempotent. If a client loses its connection before receiving a response, it may not know whether the server completed the request. The client should account for this uncertainty before repeating the request. For example, a client can safely repeat an idempotent PUT to set a resource to a known representation; repeating a POST that creates a new order could create another order unless the API defines a way to prevent duplicates.

Some operations do not fit the standard methods cleanly. Prefer a resource and standard method when their semantics fit. When an operation such as archiving a resource needs a custom action, document its effect and use an action path consistently. Google’s custom-method guidance describes this option for operations that do not map naturally to standard methods.

Return status codes that match the outcome

The HTTP status code communicates the broad result of a request. Return a success code when the request succeeds, a client-error code when the server cannot fulfill the request as sent, and a server-error code when the server cannot fulfill a valid request. A response body can add detail, but it should not contradict the status code.

For common outcomes, 200 OK indicates success with a response representation. 201 Created indicates that the request created a resource; the server identifies it with a Location header when supplied, or otherwise with the target URI. Use 202 Accepted when the server has accepted work that is not complete yet, and provide a way for the client to check its status. Use 204 No Content when the request succeeded and the response has no body.

For failures, 400 Bad Request fits a request the server cannot process because it is malformed or invalid at the request level. 404 Not Found indicates that the requested resource was not found. 405 Method Not Allowed means the method is recognized but not allowed for that resource; 501 Not Implemented means the server does not implement the method. Use 409 Conflict when the request conflicts with the resource’s current state, and 412 Precondition Failed when a request condition such as If-Match is false.

When a client exceeds a rate limit, return 429 Too Many Requests. A Retry-After header can tell the client when to try again. A server experiencing temporary unavailability can return 503 Service Unavailable and use the same header to suggest when the client should retry. The HTTP status-code standards define these retry-related cases.

Give errors useful, consistent details

A status code may be enough for a simple failure. When clients need to know which input failed or how to correct it, return a structured error body. RFC 9457 Problem Details defines a standard format for carrying that information with the response’s HTTP status. JSON responses use the media type application/problem+json.

A problem-details response can include a type URI that identifies the problem, a short title, the HTTP status, a case-specific detail, and an instance URI that identifies this occurrence. An API can add fields for details such as invalid input locations. Because those extra fields are specific to the API’s contract, document them and design clients to ignore fields they do not recognize.

For example, a validation response could identify the invalid field and explain what the client should change:

HTTP/1.1 422 Unprocessable Content
Content-Type: application/problem+json
{
  "type": "https://api.example.com/problems/validation-error",
  "title": "The request is not valid.",
  "status": 422,
  "detail": "One or more fields need correction.",
  "errors": [
    {
      "detail": "Must be a positive integer.",
      "pointer": "#/quantity"
    }
  ]
}

The errors field and its structure are part of this example API’s contract, not a universal validation schema. Keep error details actionable and safe: explain what the client can correct, but do not expose stack traces, credentials, internal hostnames, or other implementation details. Google’s error-message guidance likewise emphasizes messages that help technical users resolve a problem.

Problem Details is optional. Use it when a consistent error format helps clients; keep an existing domain-specific response when it serves the API better. In either case, return an HTTP status code that accurately describes the outcome.

What I'm building

Delegate tasks. Get software.

Give Vroni a GitHub issue, bug report, spec, or rough idea. It reads the repo, plans the change, writes code, runs checks, and works toward a review-ready pull request.

Take a look at vroni.com

Email updates

Usually a new article and a few links I found interesting.

No spam. Unsubscribe with one click.

Leave a Reply

Your email address will not be published. Required fields are marked *