Skip to main content

Welcome to a Grasp lesson

Create a free account to keep studying and create your own study path.

Lesson 21

Consuming and Producing JSON with @RequestBody

Recommended resources

Introduction

Hello! In our previous lesson, we mastered how to extract data from a URL's path and query string using @PathVariable and @RequestParam. This is perfect for identifying or filtering resources. Now, we'll turn our attention to the data payload itself—the body of an HTTP request.

Today's learning outcome is to handle JSON request bodies with @RequestBody and return JSON responses. This is the mechanism you'll use constantly when creating new resources (via POST) or updating existing ones (via PUT or PATCH) in your REST APIs.

We'll cover how Spring automatically converts incoming JSON into Java objects and vice-versa, a process powered by a library called Jackson. You'll learn the central role of the @RequestBody annotation and how to craft structured JSON responses, giving you full control over the data your API consumes and produces.

JSON Request and Response Flow in REST with Spring Annotations
This diagram illustrates the core concept of this lesson: a client sends a JSON payload in an HTTP request body, which Spring maps to a Java object using `@RequestBody`. The controller then processes the request and returns another Java object, which Spring automatically converts back into a JSON response.

JSON, Serialization, and Deserialization

Before we see how Spring handles JSON, let's quickly review the core concepts. JSON (JavaScript Object Notation) is a lightweight, text-based format for data interchange. Its language-independent nature makes it the de facto standard for communication between microservices and between web clients and servers.

The process involves two key operations:

  • Serialization: Converting a Java object into a JSON string.
  • Deserialization: Converting a JSON string into a Java object.

In the Java world, one of the most popular libraries for this is Jackson. While you can use Jackson manually, Spring Boot integrates it so seamlessly that most of this happens automatically. To appreciate Spring's automation, it's useful to see what the manual process looks like.

Intro to JSON and Jackson's ObjectMapper | Parse JSON in Java | Convert Object to JSON | Geekific

The video 'Intro to JSON and Jackson's ObjectMapper' by Geekific gives a great overview of JSON and how Jackson's core class, ObjectMapper, works. We'll watch a short segment to understand the basic mechanics of serialization and deserialization.

Watch from the beginning to 03:55. Focus on: The brief refresher on JSON syntax. How writeValueAsString() serializes a Java object to a JSON string. How readValue() deserializes a JSON string into a Java object. This will give you a solid mental model of what Spring is doing for you behind the scenes.

With that foundation, let's see how Spring automates this process within a REST controller.


Handling Incoming JSON with @RequestBody

When a client sends an HTTP POST or PUT request with a JSON payload, you need a way to capture that payload and convert it into a useful Java object. This is precisely what the @RequestBody annotation does.

You place @RequestBody on a method parameter in your controller. Spring then does the following:

  1. Reads the HTTP request body.
  2. Uses an HttpMessageConverter (we'll discuss this more later) to deserialize the body into the Java type of the annotated parameter.
  3. Passes the resulting object to your method.

The following video provides a step-by-step walkthrough of implementing a POST endpoint that accepts a JSON payload.

REST API with Spring Boot - Read HTTP Request Body with @RequestBody Annotation

The video 'REST API with Spring Boot - Read HTTP Request Body' by Sergey Kargopolov demonstrates the entire workflow of handling a JSON request.

Watch the segment from 01:04 to 05:16. The key steps shown are: Defining the Data Model (02:08): A new Java class (UserDetailsRequestModel) is created with fields that match the keys in the incoming JSON payload. This class is often called a Data Transfer Object (DTO). Using @RequestBody (04:11): The @RequestBody annotation is added to a parameter of this new class type in the controller's createUser method.

Let's summarize the pattern. If you expect a JSON payload like this:

{
  "firstName": "Alex",
  "lastName": "Miller",
  "email": "alex.miller@example.com"
}

You would create a corresponding Java class:

// This is a simple Java class (a POJO) to hold the request data.
// It could be a record for more concise code.
public class CreateUserRequest {
    private String firstName;
    private String lastName;
    private String email;

    // Getters and setters are required for Jackson to work.
    // ...getters and setters...
}

And your controller method would use @RequestBody to bind the incoming JSON to an instance of this class:

@RestController
@RequestMapping("/users")
public class UserController {

    @PostMapping
    public User createNewUser(@RequestBody CreateUserRequest userRequest) {
        // At this point, userRequest is a fully populated Java object.
        // You can now use it to create a user in your system.
        System.out.println("Creating user: " + userRequest.getFirstName());
        // ... business logic ...
        // We'll see how to return a response next.
        return someCreatedUserObject;
    }
}

This is a powerful and declarative way to handle complex data inputs without writing any parsing code yourself.

Spring Boot Employee REST Controller Code Example
This code snippet shows a complete controller method using `@RequestBody` to process a JSON payload for creating an employee. Notice the `@Valid` annotation as well, which we'll cover in our next lesson on input validation.

Returning JSON Responses

Just as Spring simplifies reading JSON, it also automates writing it. When using a @RestController, any plain Java object (or collection) you return from a method is automatically serialized into a JSON response by Spring.

Let's continue with the video from Sergey Kargopolov to see this in action.

REST API with Spring Boot - Read HTTP Request Body with @RequestBody Annotation

Now, let's see how to return a JSON response and test the complete request-response cycle.

Watch from 06:58 to 08:19. This part demonstrates returning a response object from the controller method and verifying with Postman that the client receives a JSON payload.

As you saw, if your method returns a User object, Spring will automatically:

  1. Serialize the User object to a JSON string.
  2. Set the Content-Type header of the HTTP response to application/json.
  3. Write the JSON string into the response body.
  4. Return an HTTP 200 OK status by default.

Gaining More Control with ResponseEntity

While automatic serialization is convenient, sometimes you need more control over the HTTP response. For example, when a resource is created, REST best practices suggest returning a 201 Created status code instead of 200 OK, along with a Location header pointing to the URL of the newly created resource.

For this, you can wrap your response object in a ResponseEntity. This class gives you full control over the response status, headers, and body.

RestController Guide in Spring Boot - Step-by-Step CRUD

The article 'RestController Guide in Spring Boot' provides an excellent explanation of when and why you should use ResponseEntity.

Read the subsections 'ResponseEntity', 'When should you use ResponseEntity?', and 'Why not use ResponseEntity<?>?' under the 'Controller' heading. Focus on: The explanation that Spring handles serialization and status codes automatically for direct object returns. The two main use cases for ResponseEntity: setting dynamic status codes and adding custom headers. The best practice of using a specific type like ResponseEntity<CustomerDTO> instead of a generic ResponseEntity<?>.

Here's an example of using ResponseEntity to return a 201 Created status:

@PostMapping
public ResponseEntity<User> createNewUser(@RequestBody CreateUserRequest userRequest) {
    // 1. Logic to save the user and get back the created user object
    User createdUser = userService.create(userRequest);

    // 2. Build the URI for the new resource
    URI location = ServletUriComponentsBuilder.fromCurrentRequest()
            .path("/{id}")
            .buildAndExpand(createdUser.getId())
            .toUri();

    // 3. Return a ResponseEntity with status 201 and the new object in the body
    return ResponseEntity.created(location).body(createdUser);
}

Under the Hood: HttpMessageConverter

You might be wondering how Spring knows to use Jackson for JSON. This mechanism is a great example of smart, extensible system design. Spring uses an abstraction called HttpMessageConverter. When a request comes in, Spring inspects the Content-Type header.

  • If the header is application/json, Spring selects the MappingJackson2HttpMessageConverter.
  • If it were application/xml, it would pick an XML-based converter.
  • If it were text/plain, it would use StringHttpMessageConverter.

This same logic applies in reverse for responses, using the Accept header from the client request to negotiate the response format.

Spring JSON Serialization - CodingNomads

The article 'JSON Serialization in Spring' from CodingNomads provides a concise explanation of this underlying mechanism.

Read the sections 'Default Message Converters', 'Jackson JSON Mapping', 'How Does Spring Know Which Converter to Use?', and 'Heads Up Headers'. These sections explain: The list of default converters Spring Boot configures. The role of MappingJackson2HttpMessageConverter. How the Content-Type header on a request and the Accept header for a response guide the selection of the right converter.

Understanding this content negotiation mechanism is valuable, especially in a microservices architecture where services need to communicate clearly about the data formats they support.


Conclusion

In this lesson, we bridged the gap between raw HTTP request data and structured Java objects, a critical function of any web framework. You now have the tools to build robust API endpoints that can create and update resources using the web's standard data format, JSON.

Key Takeaways:

  • @RequestBody is the key annotation for deserializing an incoming JSON request body into a Java object.
  • Spring Boot uses the Jackson library by default for all JSON serialization and deserialization.
  • When using @RestController, any Java object returned from a method is automatically serialized into a JSON response with a 200 OK status.
  • For fine-grained control over the response status and headers, you can wrap your return object in a ResponseEntity.
  • The magic behind this is Spring's HttpMessageConverter system, which uses headers like Content-Type and Accept to select the appropriate data converter.

In our next lesson, we'll address a crucial follow-up question: now that we can accept data, how do we ensure it's valid? We will explore input validation using Jakarta Bean Validation annotations like @Valid, @NotNull, and @Size.