This overview reflects widely shared professional practices as of May 2026; verify critical details against current official guidance where applicable.
Most API developers start with GET and POST—the workhorses of HTTP. But as systems grow, the need for precise semantics, idempotent updates, partial modifications, and informative error responses becomes critical. Relying solely on GET and POST leads to ambiguous APIs, fragile clients, and missed opportunities for optimization. This guide moves beyond the basics, covering the full spectrum of HTTP methods and status codes that enable robust, self-descriptive REST APIs. We'll explore when to use PUT vs. PATCH, how DELETE should behave, and what status codes like 201, 204, 409, and 422 actually mean in practice.
Why Standard HTTP Methods Matter Beyond GET and POST
HTTP methods define the intent of a request. Using the correct method makes your API self-documenting and allows intermediaries (caches, proxies, gateways) to act intelligently. For example, a GET request is safe and idempotent—caches can serve stale responses without side effects. POST, on the other hand, is neither safe nor idempotent; it's designed for non-idempotent actions like creating a resource or triggering a process. When developers misuse POST for updates or deletions, they lose these guarantees and create confusion.
Safety and Idempotency: The Foundation
Safety means a request has no side effects—repeated GETs don't change server state. Idempotency means making the same request multiple times produces the same result as making it once. GET, HEAD, OPTIONS, and TRACE are safe and idempotent. PUT and DELETE are idempotent but not safe. POST and PATCH are neither safe nor idempotent (though PATCH can be made idempotent with careful design). Understanding these properties is crucial for building reliable clients and handling retries.
Consider a payment API: using POST to create a charge is appropriate because each request creates a new charge. But if you accidentally send the same POST twice, you might charge the customer twice. Using an idempotency key (a unique client-generated token) mitigates this. In contrast, PUT to update a resource with a full representation is idempotent—sending the same PUT twice results in the same state. This distinction directly impacts error recovery and user experience.
Another common mistake is using POST for operations that should be idempotent, like deleting a resource. While POST /deleteResource works, DELETE /resource is semantically clearer and allows clients to safely retry on network failures. The HTTP specification encourages using the most specific method available.
When GET and POST Are Not Enough
As APIs evolve, you'll encounter scenarios where GET and POST feel awkward. For example, updating a single field of a large resource: sending the entire resource via PUT is wasteful, but POST /updateField is vague. PATCH with a JSON Patch or JSON Merge Patch document solves this elegantly. Similarly, checking if a resource exists without transferring its body is what HEAD is for. OPTIONS lets clients discover allowed methods dynamically. These methods aren't just academic—they reduce bandwidth, improve cache efficiency, and make APIs more self-descriptive.
In a typical project, a team I read about used POST for all write operations, including updates and deletes. The API worked, but clients had to read documentation to understand each endpoint's behavior. After migrating to PUT, PATCH, and DELETE, the API became intuitive: a DELETE request clearly indicated the intent, and clients could safely retry on timeouts. The team also added HEAD for resource existence checks, reducing unnecessary data transfer by 40% in some workflows.
Deep Dive into Advanced HTTP Methods
This section examines each method beyond GET and POST, focusing on semantics, use cases, and implementation considerations. We'll cover PUT, PATCH, DELETE, HEAD, OPTIONS, and briefly touch on TRACE and CONNECT.
PUT: Full Replacement with Idempotency
PUT is used to replace a resource entirely with the request payload. It is idempotent: sending the same PUT request multiple times has the same effect as sending it once. This makes PUT ideal for updates where the client sends a complete representation. However, PUT requires the client to know all fields, which can be problematic for large resources. If the resource doesn't exist, PUT can create it (though POST is more common for creation).
Implementation tip: Always return 200 OK with the updated representation, or 201 Created if the resource was newly created. Avoid returning 204 No Content unless you have a good reason—clients often need the updated state. One pitfall: if you use PUT for partial updates, you break idempotency because missing fields might be interpreted as deletion. Use PUT only for full replacement.
PATCH: Partial Modifications
PATCH applies a partial update to a resource. Unlike PUT, PATCH is not inherently idempotent—applying the same patch twice might have different effects depending on the current state. For example, a PATCH that increments a counter is not idempotent. However, you can design idempotent patches using conditional logic or by sending absolute values. The request body typically uses a patch format like JSON Patch (RFC 6902) or JSON Merge Patch (RFC 7396).
JSON Patch uses an array of operations (add, remove, replace, copy, move, test) and is more expressive but verbose. JSON Merge Patch is simpler: you send a partial object, and the server merges it with the current resource. Choose based on your needs: JSON Patch for complex transformations, JSON Merge Patch for simple field updates. Always return 200 OK with the updated resource or 204 No Content if no body is returned.
DELETE: Removing Resources
DELETE removes a resource identified by the URI. It is idempotent: deleting a resource that doesn't exist returns the same response (usually 404) as deleting it twice. However, the server may choose to return 200 OK if the deletion is successful and includes a body, or 204 No Content for no body. Some APIs return 202 Accepted if deletion is asynchronous. Important: DELETE should not be used for soft deletes—use a separate endpoint or a PATCH to set a 'deleted' flag. Also, ensure that DELETE is idempotent; if the first request succeeds and the second returns 404, that's fine because the state is the same (resource gone).
Common mistake: returning 200 OK with the deleted resource in the body. This can confuse clients that expect the resource to still exist. Stick with 204 No Content for successful deletions.
HEAD and OPTIONS: Metadata and Discovery
HEAD is identical to GET but returns only headers—no body. It's useful for checking resource existence, last-modified time, or content length without transferring the entire response. For example, a client can use HEAD to check if a cached resource is stale before downloading it. OPTIONS returns the allowed HTTP methods for a resource, often in the Allow header. This enables clients to discover available operations dynamically, supporting HATEOAS principles. Both methods are safe and idempotent.
Implementation: Ensure your framework supports HEAD automatically (many do). For OPTIONS, return an Allow header listing methods like GET, PUT, PATCH, DELETE, HEAD, OPTIONS. You can also return additional metadata in the body, but headers suffice.
Navigating HTTP Status Codes for REST APIs
Status codes are the language of API responses. Using them correctly makes your API self-explanatory and helps clients handle errors programmatically. This section covers the most important codes beyond 200 and 404, organized by category.
2xx Success Codes: Beyond 200 OK
200 OK is the default success code, but it's not always the best choice. 201 Created should be used for POST requests that create a resource, with a Location header pointing to the new resource. 202 Accepted is for asynchronous operations—the request has been accepted but not yet processed. 204 No Content is for successful requests that return no body, such as DELETE or a PUT that updates without returning the resource. Using these codes precisely improves client logic.
For example, a POST /users endpoint should return 201 Created with the user object and a Location header. A DELETE /users/123 should return 204 No Content. A PATCH that updates a resource and returns the full object should return 200 OK. Avoid returning 200 OK with an empty body—use 204 instead.
3xx Redirection: When Resources Move
Redirection codes are less common in REST APIs but important for evolving APIs. 301 Moved Permanently indicates the resource has a new URI; clients should update their bookmarks. 302 Found is temporary; clients should continue using the original URI. 307 Temporary Redirect and 308 Permanent Redirect preserve the HTTP method (unlike 301/302 which may change POST to GET). Use 307/308 when you need to ensure the same method is used for the redirect.
Example: If you rename a resource endpoint, return 301 Moved Permanently with the new location. Clients that follow redirects will automatically use the new URI.
4xx Client Errors: Meaningful Feedback
Beyond 400 Bad Request and 404 Not Found, several codes provide specific feedback. 401 Unauthorized means authentication is required or failed. 403 Forbidden means the server understands the request but refuses to authorize it. 405 Method Not Allowed indicates the HTTP method is not supported for the resource. 409 Conflict is used when the request conflicts with the current state (e.g., version conflict). 422 Unprocessable Entity (from WebDAV) is widely used for validation errors—the request is syntactically correct but semantically invalid. 429 Too Many Requests signals rate limiting.
Choosing between 400 and 422: Use 400 for malformed syntax (e.g., invalid JSON), and 422 for semantic errors (e.g., missing required field). Include a descriptive error message and optionally a machine-readable error code in the response body.
5xx Server Errors: Honesty and Retry
500 Internal Server Error is a catch-all for unexpected server failures. 502 Bad Gateway and 503 Service Unavailable indicate upstream issues or temporary overload. 504 Gateway Timeout is for upstream timeouts. For 5xx errors, clients should implement retry logic with exponential backoff. Avoid returning 500 for client errors—use appropriate 4xx codes instead. Also, ensure your API returns consistent error formats (e.g., JSON with 'error' and 'message' fields).
Practical Workflows: Combining Methods and Status Codes
This section provides step-by-step workflows for common scenarios, demonstrating how to combine methods and status codes effectively.
Workflow 1: Creating a Resource with Conditional Creation
Suppose you want to create a user only if the email doesn't exist. Use POST /users with the user data. If the email already exists, return 409 Conflict with a message. If successful, return 201 Created with Location header. This avoids the need for a separate existence check. Alternatively, use PUT /users/{email} for idempotent creation—if the resource exists, update it; if not, create it. This is common in RESTful designs where the client chooses the URI.
Workflow 2: Partial Update with Optimistic Locking
To prevent lost updates, use conditional requests with ETags. First, GET the resource to obtain the ETag. Then, send a PATCH with the If-Match header containing that ETag. If the resource has changed, the server returns 412 Precondition Failed. The client can then re-fetch and retry. This ensures that updates are applied to the correct version.
Workflow 3: Asynchronous Deletion with Polling
For long-running deletions, return 202 Accepted with a Location header pointing to a status resource. The client polls that resource with GET until it returns 200 OK (completed) or 404 (deleted). The status resource can include progress information. This pattern is common for deleting large datasets or triggering background jobs.
Common Pitfalls and How to Avoid Them
Even experienced developers fall into traps. Here are the most frequent mistakes and their mitigations.
Misusing POST for Everything
The most common pitfall is using POST for all write operations. This breaks idempotency and makes APIs harder to understand. Solution: map operations to the correct method—PUT for full updates, PATCH for partial, DELETE for removal. If you must use POST for non-standard operations, prefix the endpoint with a verb (e.g., POST /users/123/activate) but prefer standard methods.
Ignoring Idempotency for PUT and DELETE
Some APIs return different status codes for repeated DELETE requests (e.g., 200 first time, 404 second time). While this is technically acceptable (the state is the same), it can confuse clients that expect idempotent responses. Better: always return 204 for successful DELETE, regardless of whether the resource existed. For PUT, ensure that the same request always results in the same state.
Overusing 200 OK for Errors
Returning 200 OK with an error code in the body defeats the purpose of status codes. Clients must parse the body to detect errors, which is error-prone. Always use the appropriate 4xx or 5xx status code. For example, if a resource is not found, return 404, not 200 with {error: 'not found'}.
Neglecting HEAD and OPTIONS
Many APIs omit HEAD and OPTIONS, missing opportunities for optimization and discoverability. Implement HEAD for every GET endpoint—it's usually automatic in frameworks. Implement OPTIONS to return allowed methods, which helps clients adapt to changes.
Decision Framework: Choosing the Right Method and Status Code
Use the following decision tree to select the appropriate HTTP method and status code for your endpoint.
Method Selection
- Retrieve data without side effects? → GET (or HEAD if only headers needed).
- Create a new resource with server-generated URI? → POST, return 201.
- Create or replace a resource with client-defined URI? → PUT, return 200 or 201.
- Update part of a resource? → PATCH, return 200.
- Remove a resource? → DELETE, return 204.
- Discover allowed methods? → OPTIONS, return 200 with Allow header.
Status Code Selection for Errors
- Malformed request syntax? → 400 Bad Request.
- Authentication required? → 401 Unauthorized.
- Authorization denied? → 403 Forbidden.
- Resource not found? → 404 Not Found.
- Method not allowed? → 405 Method Not Allowed.
- Conflict (e.g., duplicate)? → 409 Conflict.
- Validation error? → 422 Unprocessable Entity.
- Rate limit exceeded? → 429 Too Many Requests.
When to Use Non-Standard Methods
While standard methods cover most scenarios, sometimes you need custom actions (e.g., approve, archive). In such cases, use POST with a verb in the URI (e.g., POST /orders/123/approve). Avoid creating new HTTP methods—they won't be supported by intermediaries. Alternatively, model the action as a sub-resource (e.g., POST /orders/123/approvals).
Synthesis and Next Steps
Mastering advanced HTTP methods and status codes transforms your API from a basic CRUD interface into a robust, self-descriptive system. By using PUT, PATCH, DELETE, HEAD, and OPTIONS correctly, you enable idempotent retries, partial updates, and dynamic discovery. Precise status codes make errors transparent and actionable. Start by auditing your existing API: identify endpoints that misuse POST, replace generic 400s with specific codes, and implement HEAD/OPTIONS. Document your method and status code conventions to ensure consistency across your team. As you design new endpoints, refer to the decision framework above. Over time, these practices become second nature, leading to APIs that are easier to use, maintain, and evolve.
Remember that HTTP is a protocol designed for the web—leveraging its full vocabulary makes your API more aligned with web architecture. For further reading, consult the HTTP specification (RFC 7230-7235) and resources like the RESTful Web Services Cookbook. The investment in learning these details pays off in reduced integration effort and fewer bugs.
Comments (0)
Please sign in to post a comment.
Don't have an account? Create one
No comments yet. Be the first to comment!