Lesson 5
Handling Invalid Requests with ResponseEntity
Introduction

Welcome to this lesson! Previously, you've focused on handling standard scenarios when building REST APIs with Spring Boot. Now, you'll delve into how to manage situations where users make invalid requests, such as trying to access resources that do not exist. To achieve this, you'll utilize ResponseEntity in Spring Boot. This allows you to return meaningful HTTP status codes, which indicate the success or failure of the operations, making your APIs more reliable and user-friendly.

HTTP Status Codes Overview

To begin, familiarize yourself with HTTP status codes. When a server responds to a request, it includes a status code that indicates the outcome. A status code is a 3-digit number, such as 200 or 404. HTTP status codes are categorized into five groups:

  • 1xx (Informational): Request received; continuing process.
  • 2xx (Successful): The request was successfully received, understood, and accepted.
  • 3xx (Redirection): Further action needs to be taken to complete the request.
  • 4xx (Client Error): The request contains bad syntax or cannot be fulfilled.
  • 5xx (Server Error): The server failed to fulfill an apparently valid request.
Common HTTP Status Codes

Next, focus on the most commonly used status codes that you’ll be dealing with in this lesson:

Status CodeDescription
200OK - The request has succeeded.
201Created - The request has been fulfilled, resulting in the creation of a new resource.
204No Content - The server successfully processed the request but is not returning any content.
400Bad Request - The server could not understand the request due to invalid syntax.
401Unauthorized - The client must authenticate itself to get the requested response.
404Not Found - The server cannot find the requested resource.
500Internal Server Error - The server has encountered a situation it doesn't know how to handle.
Understanding ResponseEntity

In Spring Boot, returning appropriate HTTP status codes is crucial for building robust APIs. The ResponseEntity class helps streamline this process. It provides a way to return not only the status code but also the HTTP headers and the body of the response. This makes the responses more informative and standardized.

ResponseEntity in Action

Let’s apply this concept to a practical example. You'll see how ResponseEntity can be used in your CRUD operations for the Recipe application. Start by handling a GET request to retrieve a recipe by its ID:

Kotlin
1@GetMapping("/recipes/{id}") 2fun getRecipeById(@PathVariable id: UUID): ResponseEntity<RecipeItem> { 3 val recipe = recipeRepository.findById(id) 4 return if (recipe == null) { 5 ResponseEntity(HttpStatus.NOT_FOUND) // Returns 404 Not Found if the item doesn't exist. 6 } else { 7 ResponseEntity(recipe, HttpStatus.OK) // Returns 200 OK if the item exists. 8 } 9}

In this example, the getRecipeById method checks if the requested recipe exists. If it does, it returns ResponseEntity(recipe, HttpStatus.OK), which corresponds to an HTTP 200 OK status. If the item doesn't exist, it returns ResponseEntity(HttpStatus.NOT_FOUND), which corresponds to an HTTP 404 Not Found status.

ResponseEntity Methods

In addition to using the constructor, you can also utilize various methods provided by the ResponseEntity class for a cleaner and more expressive syntax. Here's how you can rewrite the previous example using these methods:

Kotlin
1@GetMapping("/recipes/{id}") 2fun getRecipeById(@PathVariable id: UUID): ResponseEntity<RecipeItem> { 3 val recipe = recipeRepository.findById(id) 4 return if (recipe == null) { 5 ResponseEntity.status(HttpStatus.NOT_FOUND).build() // Returns 404 Not Found if the item doesn't exist. 6 } else { 7 ResponseEntity.ok(recipe) // Returns 200 OK if the item exists. 8 } 9}

In this version, instead of using the constructor, use ResponseEntity.status(HttpStatus.NOT_FOUND).build() to return a 404 status code when the item is not found. For a successful response, use ResponseEntity.ok(recipe) to return a 200 status code along with the recipe item. This approach can make your code more readable and concise.

Using the ResponseEntity Builder Pattern

In the previous example, you saw the construct: ResponseEntity.status(HttpStatus.NOT_FOUND).build(). Let's explore this concept in more detail.

The ResponseEntity class in Spring Boot uses the builder pattern, enabling you to construct response objects in a flexible and readable manner. By using various builder methods, you can set the status, headers, and body of the response in a step-by-step fashion. The terminal .build() method finalizes the object creation and returns the constructed ResponseEntity.

Here are some common builder methods available for ResponseEntity:

  • .status(HttpStatus status): Sets the HTTP status code.
  • .body(T body): Sets the body of the response.
  • .header(String headerName, String... headerValues): Adds headers to the response.
  • .contentType(MediaType mediaType): Sets the Content-Type header.
  • .location(URI location): Sets the Location header, commonly used in responses to POST requests that create new resources.
  • .build(): Finalizes the ResponseEntity construction and returns the object.

For further reading on the builder pattern, you can refer to this guide on the builder pattern.

Other ResponseEntity Methods

To further familiarize yourself with ResponseEntity, here are some of the most frequently used methods in the ResponseEntity class:

  • ResponseEntity.ok(T body) – Returns status code 200 (OK) with the specified body.
  • ResponseEntity.status(HttpStatus.CREATED).body(T body) – Returns status code 201 (Created) with a body containing the newly created resource.
  • ResponseEntity.noContent() – Returns status code 204 (No Content).
  • ResponseEntity.badRequest().body(T error) – Returns status code 400 (Bad Request) with the specified error message or object.
  • ResponseEntity.unauthorized().build() – Returns status code 401 (Unauthorized).
  • ResponseEntity.notFound().build() – Returns status code 404 (Not Found).
  • ResponseEntity.accepted().body(T body) – Returns status code 202 (Accepted) indicating that the request has been accepted for processing, but the processing is not yet complete.
  • ResponseEntity.unprocessableEntity().body(T body) – Returns status code 422 (Unprocessable Entity) indicating that the server understands the content type of the request entity but was unable to process the contained instructions.
Summary

In this lesson, you've explored how to make your APIs more reliable by handling scenarios where users try to access non-existent resources. You also learned to return meaningful HTTP status codes using the ResponseEntity class. This helps in effectively communicating the outcome of requests to clients, leading to the creation of robust, user-friendly APIs.

Enjoy this lesson? Now it's time to practice with Cosmo!
Practice is how you turn knowledge into actual skills.