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, 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:
- Reads the HTTP request body.
- Uses an
HttpMessageConverter(we'll discuss this more later) to deserialize the body into the Java type of the annotated parameter. - 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.
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:
- Serialize the
Userobject to a JSON string. - Set the
Content-Typeheader of the HTTP response toapplication/json. - Write the JSON string into the response body.
- Return an HTTP
200 OKstatus 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 theMappingJackson2HttpMessageConverter. - If it were
application/xml, it would pick an XML-based converter. - If it were
text/plain, it would useStringHttpMessageConverter.
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:
@RequestBodyis 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 a200 OKstatus. - 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
HttpMessageConvertersystem, which uses headers likeContent-TypeandAcceptto 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.