What is ResponseEntity, and when should you use it over returning a plain object?

7 minintermediateresponseentityhttp-statusspring-mvc

Quick Answer

ResponseEntity<T> wraps a response body together with explicit control over the HTTP status code and headers, whereas returning a plain object from a handler method always implies a 200 OK (or 201/204 in narrower framework-specific cases) with no easy way to customize headers. Use ResponseEntity whenever the status code needs to vary based on outcome (404 for not found, 201 with a Location header for creation, 204 for a successful deletion with no body) rather than always being a flat 200.

Detailed Answer

Returning a plain object from an @RestController method always results in an HTTP 200 OK (aside from a few framework-level conventions, like a void method combined with certain annotations), with no direct way to customize the status code or add response headers from within that return statement:

@GetMapping("/orders/{id}")
Order getOrder(@PathVariable Long id) {
    return repository.findById(id).orElse(null); // always 200, even if null body is returned!
}

ResponseEntity<T> wraps the response body together with an explicit status code and headers, giving full control over the actual HTTP response:

@GetMapping("/orders/{id}")
ResponseEntity<Order> getOrder(@PathVariable Long id) {
    return repository.findById(id)
        .map(ResponseEntity::ok)                          // 200 with the order
        .orElse(ResponseEntity.notFound().build());        // 404, no body
}

@PostMapping("/orders")
ResponseEntity<Order> createOrder(@RequestBody @Valid CreateOrderRequest request) {
    Order created = service.create(request);
    URI location = URI.create("/orders/" + created.getId());
    return ResponseEntity.created(location).body(created); // 201 + Location header
}

@DeleteMapping("/orders/{id}")
ResponseEntity<Void> deleteOrder(@PathVariable Long id) {
    service.delete(id);
    return ResponseEntity.noContent().build();              // 204, no body
}

When to reach for ResponseEntity: whenever the status code should genuinely vary based on outcome (200 vs. 404 vs. 201 vs. 204), or when you need to set specific response headers (Location, ETag, Cache-Control) explicitly. For simple, always-successful endpoints where a flat 200 with a JSON body is genuinely all that's needed, returning the plain object directly is simpler and perfectly idiomatic — ResponseEntity is a tool for when the response's metadata (status/headers) needs to be a first-class, controllable part of the method's logic, not a default you should reach for on every single endpoint regardless of need.