ResponseEntity
IntermediateWraps the response body, HTTP status code, and headers in a single return type, giving full control over every aspect of the HTTP response.
Overview
ResponseEntity<T> is a Spring wrapper that bundles the HTTP response body, status code, and headers into a single return type from a controller method. By default @RestController returns 200 OK with the method's return value as the body — when you need to customise the status code, add response headers (Location, ETag, Cache-Control), or return empty bodies (204 No Content), you use ResponseEntity. Common patterns: return 201 Created with a Location header after creating a resource, return 204 No Content for deletes, return 404 Not Found when a resource is absent. ResponseEntity integrates naturally with Optional and reactive types.
Common response patterns
ResponseEntity.ok(body) is shorthand for 200 OK. Use ResponseEntity.created(uri) for 201, ResponseEntity.noContent() for 204, ResponseEntity.notFound() for 404. The builder API (ResponseEntity.status(status).header(...).body(...)) gives full control for more complex responses.
@RestController
@RequestMapping("/orders")
public class OrderController {
private final OrderService orderService;
// 200 OK with body
@GetMapping("/{id}")
public ResponseEntity<Order> getOrder(@PathVariable Long id) {
return orderService.findById(id)
.map(ResponseEntity::ok) // 200 OK
.orElse(ResponseEntity.notFound().build()); // 404 Not Found, no body
}
// 201 Created with Location header
@PostMapping
public ResponseEntity<Order> createOrder(@RequestBody @Valid OrderRequest req) {
Order created = orderService.create(req);
URI location = ServletUriComponentsBuilder
.fromCurrentRequest()
.path("/{id}")
.buildAndExpand(created.getId())
.toUri();
return ResponseEntity.created(location).body(created);
// Response: 201 Created, Location: /orders/42, body: {"id":42,...}
}
// 204 No Content — update/delete returns nothing
@DeleteMapping("/{id}")
public ResponseEntity<Void> deleteOrder(@PathVariable Long id) {
orderService.delete(id);
return ResponseEntity.noContent().build(); // 204, no body
}
}Adding response headers
Use ResponseEntity.ok().header(name, value) or HttpHeaders to add custom headers. Common headers: Location (after create), ETag (for conditional requests), Cache-Control (for caching), and custom correlation headers. Return HttpHeaders via BodyBuilder for multi-header responses.
// Custom headers on response
@GetMapping("/{id}")
public ResponseEntity<Order> getOrderWithCaching(@PathVariable Long id) {
Order order = orderService.findById(id).orElseThrow(NotFoundException::new);
String etag = '"' + Integer.toHexString(order.hashCode()) + '"';
return ResponseEntity.ok()
.header(HttpHeaders.ETAG, etag)
.header(HttpHeaders.CACHE_CONTROL, "max-age=60, must-revalidate")
.header("X-Request-Id", MDC.get("requestId"))
.body(order);
}
// Using HttpHeaders object for multiple headers
@PostMapping("/orders")
public ResponseEntity<Order> createWithHeaders(@RequestBody OrderRequest req) {
Order created = orderService.create(req);
HttpHeaders headers = new HttpHeaders();
headers.setLocation(URI.create("/orders/" + created.getId()));
headers.set("X-Order-Number", created.getOrderNumber());
headers.set("X-Rate-Limit-Remaining", "99");
return new ResponseEntity<>(created, headers, HttpStatus.CREATED);
}Error responses and @ExceptionHandler
Rather than returning ResponseEntity<Object> with error details from every method, use @ExceptionHandler or @ControllerAdvice to centralise error mapping. @ControllerAdvice catches exceptions thrown from any controller and maps them to structured error ResponseEntity responses. Spring Boot's ProblemDetail (RFC 7807) provides a standardised error response structure.
// Centralised error handling — cleaner than try/catch in every controller
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(OrderNotFoundException.class)
public ResponseEntity<ProblemDetail> handleNotFound(OrderNotFoundException ex,
HttpServletRequest req) {
ProblemDetail problem = ProblemDetail.forStatusAndDetail(
HttpStatus.NOT_FOUND, ex.getMessage());
problem.setTitle("Order Not Found");
problem.setInstance(URI.create(req.getRequestURI()));
return ResponseEntity.status(HttpStatus.NOT_FOUND).body(problem);
// {"type":"about:blank","title":"Order Not Found","status":404,
// "detail":"Order 42 not found","instance":"/orders/42"}
}
@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity<ProblemDetail> handleValidation(
MethodArgumentNotValidException ex) {
ProblemDetail problem = ProblemDetail.forStatus(HttpStatus.BAD_REQUEST);
problem.setTitle("Validation Failed");
Map<String, String> errors = ex.getBindingResult()
.getFieldErrors().stream()
.collect(toMap(FieldError::getField, FieldError::getDefaultMessage));
problem.setProperty("errors", errors);
return ResponseEntity.badRequest().body(problem);
}
}Key Points to Remember
- 1ResponseEntity.ok(body) = 200, .created(uri) = 201 + Location, .noContent() = 204, .notFound() = 404
- 2Always return 201 Created with a Location header pointing to the new resource URI after POST
- 3ResponseEntity.status(code).header(name, value).body(obj) provides full control over every response aspect
- 4@ControllerAdvice + @ExceptionHandler centralises error-to-ResponseEntity mapping across all controllers
- 5ProblemDetail (Spring Boot 3 / RFC 7807) provides a standardised JSON error structure with type, title, status, detail
- 6Return ResponseEntity<Void> for 204 No Content — avoids Jackson trying to serialise a null body
Interview Questions
Sign in to ask AriaWhy would you use ResponseEntity<Order> instead of just returning Order from a @RestController method?
How do you return a 201 Created response with a Location header in Spring Boot?
What is ProblemDetail and how does it standardise error responses?
How does @ControllerAdvice improve error handling compared to try-catch in every controller?
How would you implement ETag-based conditional GET responses with ResponseEntity?
Ask Aria about ResponseEntity
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.