G
Gianfranco Coppola
Guest
The Ultimate Guide to HTTP Status Codes in REST APIs
When building REST APIs, HTTP status codes play a crucial role in communication between the client and the server. They arenβt just numbers; they provide valuable context about what happened with a requestβwhether it succeeded, failed, or needs further action.
In this guide, youβll learn:
- Why status codes matter for REST APIs.
- The main HTTP status code categories.
- Which codes to use and when.
- Best practices for consistent responses.
- Practical Spring Boot examples to implement them.
- How to handle errors properly with custom responses.
Why HTTP Status Codes Matter
Status codes are more than formalitiesβthey enhance client-server communication and developer experience. When used correctly:
- Clients know how to respond (e.g., retry, show an error message).
- APIs are self-descriptive, reducing the need for extra documentation.
- Debugging becomes easier, as error codes indicate the exact problem.
Incorrect usage can confuse API consumers and lead to bad UX. For example, returning
200 OK
for an invalid request hides the real issue.Categories of HTTP Status Codes
HTTP status codes are grouped into five categories:
1xx β Informational
- Indicates the request was received and is being processed.
- Rarely used in REST APIs.
- Example:
100 Continue
.
2xx β Success
- Indicates the request was successfully processed.
- Common codes:
- 200 OK β Generic success response.
- 201 Created β Resource successfully created.
- 202 Accepted β Request accepted but processing is asynchronous.
- 204 No Content β Action successful, no body returned.
3xx β Redirection
- Indicates further action is needed (usually another URL).
- Common in browsers, rarely in APIs.
- Example:
301 Moved Permanently
.
4xx β Client Errors
- The client sent an invalid request.
- Common codes:
- 400 Bad Request β Invalid input or missing parameters.
- 401 Unauthorized β Authentication required or failed.
- 403 Forbidden β Authenticated, but no permission.
- 404 Not Found β Resource doesnβt exist.
- 409 Conflict β Request conflicts with the current state.
- 422 Unprocessable Entity β Validation error.
5xx β Server Errors
- Something went wrong on the server side.
- Common codes:
- 500 Internal Server Error β Generic server error.
- 503 Service Unavailable β Server temporarily down.
Most Common HTTP Status Codes and When to Use Them
Hereβs a quick guide to avoid confusion:
200 OK
- Use when the request succeeds and returns data.
Code:{ "id": 1, "name": "John Doe" }
201 Created
- Use after successfully creating a resource.
- Example: POST request creating a user.
202 Accepted
- Use when the request has been accepted for processing but the operation is asynchronous.
- Example: triggering a background job, processing a file upload, sending an email.
Code:{ "code": 202, "message": "Processing started", "details": "You will receive a callback when the job completes" }
204 No Content
- Use for successful operations without a response body (e.g., DELETE).
400 Bad Request
- Use when the client sends invalid input.
- Example: Missing required fields.
401 Unauthorized vs 403 Forbidden
- 401 β The client must authenticate.
- 403 β The client is authenticated but not allowed.
404 Not Found
- Resource not found (e.g., wrong ID).
409 Conflict
- Use when thereβs a resource state conflict (e.g., duplicate username).
422 Unprocessable Entity
- Validation passed structurally but semantically invalid (e.g., age < 0).
500 Internal Server Error
- Unexpected server failureβshould be avoided as much as possible.
Best Practices for Choosing the Right Status Code

201
for resource creation in one endpoint, donβt switch to 200
in another.
200 OK
for every response defeats the purpose of HTTP status codes.
code
, message
, and optionally details
.
Practical Examples with Spring Boot
Using ResponseEntity
to Set Status Codes
Spring Boot makes it easy to control status codes via
ResponseEntity
.
Code:
// GET
@GetMapping("/users/{id}")
public ResponseEntity<User> getUser(@PathVariable Long id) {
Optional<User> user = userService.findById(id);
return user.map(ResponseEntity::ok)
.orElseGet(() -> ResponseEntity.notFound().build());
}
// POST
@PostMapping("/users")
public ResponseEntity<User> createUser(@RequestBody User user) {
User createdUser = userService.save(user);
URI location = URI.create("/users/" + createdUser.getId());
return ResponseEntity.created(location).body(createdUser);
}
// PUT
@PutMapping("/users/{id}")
public ResponseEntity<User> updateUser(@PathVariable Long id, @RequestBody User user) {
Optional<User> updatedUser = userService.update(id, user);
return updatedUser.map(ResponseEntity::ok)
.orElseGet(() -> ResponseEntity.notFound().build());
}
// DELETE
@DeleteMapping("/users/{id}")
public ResponseEntity<Void> deleteUser(@PathVariable Long id) {
userService.delete(id);
return ResponseEntity.noContent().build();
}
// ASYNC example with 202
@PostMapping("/process")
public ResponseEntity<String> startProcess() {
processService.startBackgroundJob();
URI statusUri = URI.create("/process/status/123");
return ResponseEntity.accepted()
.location(statusUri)
.body("Processing started");
}
Error Handling and Custom Responses
Instead of returning raw error messages, structure your error responses.
Global Exception Handling with @ControllerAdvice
Code:
@ControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(ResourceNotFoundException.class)
public ResponseEntity<ErrorResponse> handleNotFound(ResourceNotFoundException ex) {
ErrorResponse error = new ErrorResponse(404, "Resource not found", ex.getMessage());
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(error);
}
}
Example Error Response
Code:
{
"code": 404,
"error": "Resource not found",
"message": "User with id 123 not found"
}
This approach makes your API predictable and easier to debug.
Conclusion
HTTP status codes are essential for building robust, self-descriptive APIs. Choosing the right one improves communication, reduces confusion, and makes your API a joy to consume.
Use the correct code for each scenario.
Be consistent and follow REST conventions.
Provide meaningful error messages.
Check out the GitHub repository for more examples and full implementations. And if you want to go further, read my next article βChoosing the Right HTTP Method for Your REST APIβ, or discover my Pro Starter Kit on Gumroad.
- Spring Boot API Starter Kit (Lite) on GitHub
- Choosing the Right HTTP Method for Your REST API
- Pro Starter Kit on Gumroad
Continue reading...