Spring Boot Requests and Responses
Handling HTTP requests and responses is a core aspect of building any web application. In the Spring Boot ecosystem, this is primarily managed by the Spring MVC framework. By leveraging a powerful set of annotations, developers can map incoming HTTP requests to specific Java methods and transform the resulting data into structured HTTP responses.
Understanding the nuances of parameter binding, request body parsing, and response customization is essential for designing robust, scalable RESTful APIs.
Spring Boot simplifies the process of routing HTTP requests using a variety of mapping annotations. At the heart of this is @RequestMapping, a versatile annotation that can be configured to filter requests based on URL paths, HTTP methods, headers, and more.
To streamline development, Spring provides specialized composed annotations that correspond to standard HTTP verbs:
@GetMapping: Used for retrieving resources.@PostMapping: Used for creating new resources.@PutMapping: Used for updating existing resources.@DeleteMapping: Used for removing resources.
For REST APIs, the @RestController annotation is typically used. This is a convenience annotation that combines @Controller and @ResponseBody, ensuring that the return value of every method is automatically serialized into the response body (usually as JSON) rather than being interpreted as a view name for a template engine.
Extracting Request Data
Depending on how the client sends data, Spring Boot provides several annotations to bind request parameters to method arguments.
URI and Query Parameters
@PathVariable: Extracts values directly from the URI path. For example, in/users/{id}, the{id}segment is captured using this annotation.@RequestParam: Captures query parameters (e.g.,?lang=en) or form-submitted data. It allows for optional parameters via therequiredattribute and provides adefaultValueto ensure stability.
Metadata and Headers
@RequestHeader: Accesses specific HTTP headers, which is useful for authentication tokens or tracing IDs.@CookieValue: Retrieves values from the client's cookies.
Request Payloads
@RequestBody: This is the most critical annotation for REST APIs. It tells Spring to deserialize the incoming request body (typically JSON or XML) into a Java object using anHttpMessageConverter.@ModelAttribute: Used primarily for traditional HTML form submissions, binding form fields to a POJO.@RequestPart/MultipartFile: Specifically designed for handling multi-part requests, such as file uploads.
Implementation Example
@RestController
@RequestMapping("/api/users")
public class UserController {
@GetMapping("/{id}")
public UserVO getUser(
@PathVariable Long id,
@RequestParam(defaultValue = "en") String lang,
@RequestHeader(value = "X-Trace-Id", required = false) String traceId) {
// Business logic to fetch user
return new UserVO(id, "Alice");
}
}
In this example, a request to GET /api/users/1?lang=en would bind 1 to the id and "en" to the lang variable.
Handling Request Bodies and Validation
When dealing with POST or PUT requests, the payload is usually a JSON object. By using @RequestBody, Spring Boot automatically maps the JSON fields to the fields of a Java record or class.
To ensure data integrity, Spring integrates with the Bean Validation API. By adding the @Valid annotation to the request body, Spring will automatically validate the object based on constraints (like @NotBlank or @Min) defined in the DTO.
public record UserCreateDTO(@NotBlank String name) {}
@PostMapping
@ResponseStatus(HttpStatus.CREATED)
public UserVO createUser(@Valid @RequestBody UserCreateDTO dto) {
return new UserVO(1L, dto.name());
}
If validation fails, Spring throws a MethodArgumentNotValidException. Rather than letting the application crash or return a generic error, this can be intercepted by a global exception handler to provide a user-friendly error message.
Constructing the Response
While returning a POJO from a @RestController method is the simplest way to send a response, there are times when you need finer control over the HTTP status code, headers, and the body.
Using ResponseEntity
The ResponseEntity class represents the entire HTTP response. It allows you to dynamically set the status code and add custom headers.
@GetMapping("/{id}")
public ResponseEntity<UserVO> getUserDetail(@PathVariable Long id) {
UserVO user = new UserVO(id, "Alice");
return ResponseEntity.ok()
.header("X-App-Version", "1.0.0")
.body(user);
}
Controlling Status Codes and Media Types
@ResponseStatus: Used to define a fixed status code for a method (e.g.,HttpStatus.CREATEDfor a successful POST).producesandconsumes: These attributes in mapping annotations restrict the media types the method can handle. For instance,produces = "application/json"ensures the client receives JSON.
Global Exception Handling and Content Negotiation
Centralized Error Handling
To avoid duplicating try-catch blocks across every controller, Spring Boot provides @RestControllerAdvice. This allows you to define a global interceptor for exceptions, ensuring that all errors follow a consistent API response format.
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(MethodArgumentNotValidException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public Map<String, String> handleValidationErrors(MethodArgumentNotValidException ex) {
String errorMsg = ex.getBindingResult()
.getFieldError()
.getDefaultMessage();
return Map.of("error", errorMsg);
}
}
Content Negotiation
Content negotiation is the process by which the server and client agree on the data format (JSON, XML, etc.). The client expresses its preference via the Accept header. Spring Boot uses HttpMessageConverters to select the appropriate format based on the produces attribute and the available libraries on the classpath (e.g., adding Jackson XML dependency to support XML).
Testing the API
Once the endpoints are implemented, you can verify them using tools like curl. For a JSON-based creation endpoint:
curl -X POST http://localhost:8080/api/users \
-H "Content-Type: application/json" \
-d '{"name":"Bob"}'
Expected Response:
{
"id": 1,
"name": "Bob"
}
Summary
Mastering requests and responses in Spring Boot involves five key pillars:
- Routing: Using mapping annotations to define endpoints.
- Binding: Extracting data from paths, queries, headers, and bodies.
- Validation: Ensuring incoming data is correct using
@Valid. - Response Control: Using
ResponseEntityand@ResponseStatusfor precise HTTP communication. - Consistency: Implementing
@RestControllerAdvicefor unified error handling and leveraging content negotiation for flexible data formats.
By following these patterns, you can build professional, maintainable, and standard-compliant RESTful services.