HTTP Methods, Status Codes, and Headers in API Design

Choose HTTP methods that match the operation, return status codes clients can act on, and use headers for metadata, caching, and safe retries.

published: reading time: 9 min read author: GeekWorkBench
Quick Summary

HTTP methods, status codes, and headers give API clients consistent signals about requests and their outcomes. This guide explains safe and idempotent method behavior, common success and error codes, and headers for content negotiation, caching, resource locations, and conditional updates. It also shows how idempotency keys and clear retry guidance help prevent duplicate work after timeouts. Use these rules to make an API easier to integrate with and safer to operate.

HTTP Methods, Status Codes, and Headers in API Design

Introduction

An API client needs more than a URL and a JSON body to understand a request. The HTTP method communicates the requested action, the status code reports the outcome, and headers carry metadata that changes how the request or response should be handled. These parts work together: a POST that creates an order should normally return 201 Created and a Location header pointing to the new order.

If these signals are consistent, clients can retry, cache, and recover without endpoint-specific guesswork. The HTTP and HTTPS protocol guide explains the wire protocol in more depth; here we focus on API design decisions.

Methods express intent

Choose a method that describes the operation, then keep its behavior consistent across routes. Safe methods do not ask the server to change business state; idempotent methods have the same intended effect when repeated, even if the response differs.

Method Typical use Safe Idempotent
GET Read a resource or collection Yes Yes
POST Create a resource or run a command No No, unless the API defines deduplication
PUT Replace a resource at a known URL No Yes
PATCH Apply a partial update No Depends on the patch operation
DELETE Remove a resource No Yes

For example, GET /orders/ord_803 reads an order, while POST /orders creates one. A client can safely repeat a PUT replacement after a timeout, but a repeated POST may create a duplicate unless the API supports an idempotency key.

Status codes help clients decide what to do

Use a small, predictable set. 200 OK fits a successful response with a representation, 201 Created signals creation, and 204 No Content means success with no body. 202 Accepted means work was accepted but is not complete. On errors, distinguish authentication (401), authorization (403), missing resources (404), state conflicts (409), invalid request syntax (400), and semantically invalid fields (422) according to the API’s documented policy. 429 should represent throttling and usually include Retry-After. Reserve 500 for unexpected server faults; do not turn every failure into 200 with { "success": false }.

A status code is not a full error explanation. Pair it with a stable error body containing a machine-readable code and a safe human-readable message. Avoid returning stack traces or internal database details.

Headers carry shared rules

Content-Type tells the receiver how to parse the body. Accept tells the server what representation the caller can consume. Authorization carries credentials; Cache-Control governs reuse; ETag and If-None-Match support conditional requests; Location identifies a newly created resource or redirect target. Use standard headers where they fit instead of inventing X- fields for ordinary HTTP behavior.

POST /api/orders HTTP/1.1
Content-Type: application/json
Accept: application/json
Idempotency-Key: 7da7e4b9-6f33-4ac2-a63d-8cb3e9f7db31

{"sku":"kbd-42","quantity":1}

HTTP/1.1 201 Created
Content-Type: application/json
Location: /api/orders/ord_803
Cache-Control: no-store

{"id":"ord_803","status":"pending"}

Request handling flow

sequenceDiagram
    participant C as Client
    participant A as API
    participant D as Data store
    C->>A: Method, path, headers, body
    A->>A: Authenticate and validate
    A->>D: Apply operation
    D-->>A: Result or known failure
    A-->>C: Status, headers, representation

When to use and when not to use

Use HTTP semantics for public web APIs, browser-facing services, and integrations that benefit from standard clients, proxies, and observability. Do not overload GET to trigger business actions, and do not add custom headers for concepts already covered by HTTP. For a command that does not map cleanly to resource state, a clearly documented action endpoint can still use POST; forcing every action into a misleading PUT is worse than a small exception.

Trade-Off Table

Choice Strength Cost
Standard status codes Familiar client behavior Teams must agree on edge cases
Idempotency key on retryable POST Prevents duplicate effects Requires key storage, expiry, and request matching
Conditional headers and ETags Saves bandwidth and avoids lost updates Cache validators add implementation work
Custom status or header conventions Can fit a local system Every client needs special handling

Implementation snippet

A handler should choose the status and headers at the point where it knows the outcome. Framework syntax differs, but the contract can stay stable:

async function createOrder(request: Request): Promise<Response> {
  const input = await request.json();
  const order = await orders.create(validateOrder(input));

  return Response.json(order, {
    status: 201,
    headers: {
      Location: `/api/orders/${order.id}`,
      "Cache-Control": "no-store",
    },
  });
}

In production, validate Content-Type before parsing, validate the body, and ensure the idempotency policy is implemented by the service rather than only by the client.

Production failure scenarios and mitigations

A proxy retries a timed-out POST after the first request committed. Use idempotency keys for operations with costly side effects and scope each key to the authenticated caller. A client treats every 4xx as permanent, but the server used 429 for throttling; publish retry guidance and Retry-After. A successful delete returns a JSON body with 204; some clients reject it. Make body behavior match the status and cover it in contract tests.

Observability checklist

  • Record method, route template, status class, latency, and request ID; avoid raw query values that may contain secrets.
  • Track rates of 4xx, 5xx, 429, and idempotency replays separately.
  • Alert on unexpected status shifts and elevated retry volume.
  • Preserve Retry-After and correlation IDs in logs so support can trace client reports.

Security and Compliance Notes

Never put bearer tokens or private data in URLs, where logs and referrers can expose them. Treat Origin, forwarding, and cache headers as untrusted input unless a trusted proxy sets them. Ensure shared caches do not store personalized responses; use suitable Cache-Control directives. Require HTTPS for credentials and sensitive data, and redact authorization and idempotency values from logs. For regulated data, document which response fields and audit events are retained, who can access them, and how long they remain available; the applicable rules depend on the data and jurisdiction.

Common Pitfalls / Anti-Patterns

State-changing GET routes can be triggered by crawlers, prefetching, or retries that assume safe methods have no side effects. Returning 200 for errors makes client retry and monitoring logic unreliable. Leaking framework exceptions can expose implementation details, while using 401 when an authenticated user lacks permission (403) sends the wrong recovery signal. Avoid sending a body with 204 No Content, and do not assume a retry is safe unless the operation is idempotent or protected by an idempotency key.

Quick Recap Checklist

  • Keep safe methods free of requested state changes and document which methods are idempotent.
  • Choose status codes that match whether work completed, failed, or was accepted for later processing.
  • Set Content-Type for request and response bodies and use Accept for response negotiation.
  • Document cache, authentication, and retry-related headers as part of the API contract.

Interview Questions

1. What is the difference between a safe method and an idempotent method?
A safe method does not request a business-state change; an idempotent method has the same intended effect when repeated. PUT is idempotent but not safe, while GET is expected to be both.
2. When should an API return 202 instead of 200?
Return 202 Accepted when the request is accepted for asynchronous processing but the work has not finished. Give the client a way to check progress, such as a status resource or documented callback.
3. How do idempotency keys prevent duplicate payment requests?
The server stores the result associated with a key and caller. A retry with that same key returns the stored outcome instead of repeating the charge; the server must reject reuse of the key with a different request payload.
4. How do PUT and PATCH differ when updating a resource?
PUT replaces the representation at the target URL and should be idempotent. PATCH applies a partial change, so its behavior depends on the patch format and operation; repeating it is not automatically safe.
5. When should an API return 401 versus 403?
Use 401 when valid authentication credentials are missing or not accepted. Use 403 when the caller is authenticated but lacks permission for the requested action.
6. What should a client do when it receives 429 Too Many Requests?
Respect the server's Retry-After guidance when present, then retry with bounded backoff. Avoid immediate repeated requests that can extend the rate limit or add load.
7. Why should an API avoid returning 200 OK for an unsuccessful operation?
Clients, monitoring tools, and proxies use status codes to classify outcomes. A 200 response can make a failure look successful and cause retry or alerting logic to behave incorrectly.
8. What is the purpose of the Location header after creating a resource?
With a 201 Created response, Location identifies the new resource so the client can fetch or address it without constructing the URL from assumptions.
9. How do Content-Type and Accept differ?
Content-Type describes the representation in the message body. Accept tells the server which response media types the client can handle.
10. How can ETag and If-Match help prevent lost updates?
The server returns an ETag as a version validator. A client can send that value in If-Match when updating; if the resource changed meanwhile, the server rejects the stale update instead of overwriting newer data.

Further Reading

Conclusion

HTTP already provides a shared vocabulary for API intent and outcomes. Use it consistently, document the exceptions, and make retry and cache behavior explicit so clients can act safely.

Category

Related Posts

API Request, Response, and Error Shapes Clients Can Trust

Design consistent API request and response envelopes, validation errors, and problem details so client developers can handle success and failure reliably.

#api-design #http #error-handling

API Resource Names, Relationships, and Collections

Model API URLs around stable resources and relationships, with clear collection behavior that clients can navigate without learning server internals.

#api-design #rest #resource-modeling

API Filtering, Sorting, Pagination, and Field Selection

Build collection endpoints that let clients narrow, order, page through, and shape results without slow queries or unstable response behavior.

#api-design #pagination #rest