The Ultimate Guide to HTTP Status Codes in REST APIs

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


βœ… Be consistent: If you use 201 for resource creation in one endpoint, don’t switch to 200 in another.
βœ… Don’t overuse 200: Returning 200 OK for every response defeats the purpose of HTTP status codes.
βœ… Provide meaningful error responses: Include a JSON body with code, message, and optionally details.
βœ… Follow REST conventions: Avoid creating custom semantics when a standard code exists.

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.


Continue reading...
 


Join 𝕋𝕄𝕋 on Telegram
Channel PREVIEW:
Back
Top