Request & Response
Beginner@RequestBody deserializes the HTTP request body into a Java object; ResponseEntity gives you full control over status, headers, and body. These two are the backbone of every REST interaction.
Overview
Spring MVC uses HttpMessageConverters to translate between HTTP bodies and Java objects. MappingJackson2HttpMessageConverter handles JSON (the default). @RequestBody tells Spring to deserialize the request body into the method parameter. ResponseEntity<T> wraps the response with explicit status code and optional headers — use it when the status varies at runtime. For standardized error responses, Spring Boot 3+ supports RFC 7807 ProblemDetail natively.
@RequestBody and Deserialization
Jackson deserializes JSON request bodies to Java records or classes. With @Valid, Bean Validation constraints are checked before the method is invoked — violations throw MethodArgumentNotValidException which Spring Boot maps to a 400 response.
// DTO as a Java record (Java 16+) — immutable, no boilerplate
public record CreateOrderRequest(
@NotBlank String customerId,
@NotEmpty List<@Valid OrderItemDto> items,
@NotBlank String deliveryAddress
) {}
public record OrderItemDto(
@NotBlank String productId,
@Min(1) int quantity
) {}
@RestController
@RequestMapping("/api/v1/orders")
public class OrderController {
@PostMapping
@ResponseStatus(HttpStatus.CREATED)
public OrderDto createOrder(@RequestBody @Valid CreateOrderRequest request) {
// Jackson has already deserialized JSON → CreateOrderRequest
// @Valid has already checked constraints
// If validation fails → MethodArgumentNotValidException → 400
return orderService.create(request);
}
}
// Example JSON request body:
// {
// "customerId": "usr_123",
// "items": [{ "productId": "prod_456", "quantity": 2 }],
// "deliveryAddress": "123 Main St"
// }ResponseEntity — Control Status and Headers
ResponseEntity.ok() is shorthand for 200 OK with a body. Use the builder API for custom status, headers, or conditional responses. The Location header on 201 Created responses is a REST best practice.
@PostMapping
public ResponseEntity<OrderDto> createOrder(@RequestBody @Valid CreateOrderRequest req) {
OrderDto order = orderService.create(req);
// Build the Location URI for the created resource
URI location = ServletUriComponentsBuilder
.fromCurrentRequest()
.path("/{id}")
.buildAndExpand(order.id())
.toUri();
return ResponseEntity
.created(location) // 201 Created + Location header
.body(order);
}
@GetMapping("/{id}")
public ResponseEntity<OrderDto> getOrder(@PathVariable String id) {
return orderService.findById(id)
.map(order -> ResponseEntity.ok()
.header("X-Order-Status", order.status())
.body(order))
.orElse(ResponseEntity.notFound().build()); // 404
}
// Conditional response — 304 Not Modified if ETag matches
@GetMapping("/{id}")
public ResponseEntity<OrderDto> getOrderConditional(
@PathVariable String id,
@RequestHeader(value = "If-None-Match", required = false) String ifNoneMatch) {
OrderDto order = orderService.findById(id).orElseThrow();
String etag = '"' + Integer.toHexString(order.hashCode()) + '"';
if (etag.equals(ifNoneMatch)) {
return ResponseEntity.status(HttpStatus.NOT_MODIFIED).build(); // 304
}
return ResponseEntity.ok().eTag(etag).body(order);
}RFC 7807 ProblemDetail — Standard Error Responses
Spring Boot 3+ supports ProblemDetail (RFC 7807) natively. It provides a standard JSON error body with type, title, status, detail, and instance fields — consistent across all error cases.
// Spring Boot 3+ — enable in application.yml
// spring.mvc.problemdetails.enabled=true
// Now MethodArgumentNotValidException, NoSuchElementException etc.
// automatically return application/problem+json responses
// Custom error using ProblemDetail in @ControllerAdvice
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(OrderNotFoundException.class)
public ProblemDetail handleOrderNotFound(OrderNotFoundException ex,
HttpServletRequest request) {
ProblemDetail problem = ProblemDetail
.forStatusAndDetail(HttpStatus.NOT_FOUND, ex.getMessage());
problem.setTitle("Order Not Found");
problem.setInstance(URI.create(request.getRequestURI()));
problem.setProperty("orderId", ex.getOrderId()); // custom extension
return problem;
}
}
// Response body (application/problem+json):
// {
// "type": "about:blank",
// "title": "Order Not Found",
// "status": 404,
// "detail": "Order ord_999 does not exist",
// "instance": "/api/v1/orders/ord_999",
// "orderId": "ord_999"
// }Key Points to Remember
- 1@RequestBody uses HttpMessageConverter (Jackson) to deserialize the request body into a Java object.
- 2Always pair @RequestBody with @Valid to trigger Bean Validation before the method executes.
- 3ResponseEntity<T> lets you set status code, headers, and body — use it for conditional or non-200 responses.
- 4Return Location header on 201 Created responses — use ServletUriComponentsBuilder to build it from the current request.
- 5Spring Boot 3+ supports ProblemDetail (RFC 7807) natively — consistent error response format across all endpoints.
- 6Use @ResponseStatus on the method for fixed status codes; use ResponseEntity when the status is dynamic.
Interview Questions
Sign in to ask AriaWhat does @RequestBody do and which converter processes JSON by default?
What is the difference between @ResponseBody and ResponseEntity?
What is RFC 7807 ProblemDetail and why is it useful in REST APIs?
How would you add a Location header to a 201 Created response?
How does Spring handle content negotiation between JSON and XML responses?
Ask Aria about Request & Response
Your personal AI tutor — ask anything about this concept
Revision Status
Personal Notes
Sign in to save personal notes for this topic.
Discussion
Sign in to join the discussion.