π ResponseEntity<T> β Springβs HTTP Response Wrapper Cheatsheet¶
Essence:
ResponseEntityrepresents the entire HTTP response: β status code + headers + body (T) Itβs a generic container returned by controller methods to give precise control over what the client receives.
1. Where It Lives¶
- Package:
org.springframework.http - Implements:
HttpEntity<T>(adds HTTP status on top) - Used in: Spring MVC and Spring WebFlux
2. Why Use It¶
| Use case | Alternative | Problem | Solution with ResponseEntity |
|---|---|---|---|
| You need to set custom status | return object directly | Always returns 200 OK | ResponseEntity.status(201) |
| You need to send headers | @ResponseBody |
Canβt customize headers | .header("X-Custom", "value") |
| You need conditional responses | void or object | No fine-grained control | .notFound(), .noContent() |
| You want to return generic DTO or error JSON | ResponseBody |
Limited flexibility | ResponseEntity<?> handles both |
3. Basic Forms¶
@GetMapping("/user/{id}")
public ResponseEntity<User> getUser(@PathVariable Long id) {
Optional<User> user = repo.findById(id);
return user.map(ResponseEntity::ok)
.orElseGet(() -> ResponseEntity.notFound().build());
}
Equivalent results:
| Return type | Effect |
|---|---|
User |
β 200 OK (body = User, default headers) |
ResponseEntity<User> |
β 200, 404, 204, etc. (custom) |
4. Factory Methods (Static Builders)¶
| Method | HTTP Status | Example |
|---|---|---|
ok(T body) |
200 OK | ResponseEntity.ok(user) |
ok() |
200 OK, no body | ResponseEntity.ok().build() |
created(URI location) |
201 Created | ResponseEntity.created(uri).build() |
accepted() |
202 Accepted | ResponseEntity.accepted().build() |
noContent() |
204 No Content | ResponseEntity.noContent().build() |
badRequest() |
400 Bad Request | ResponseEntity.badRequest().body(error) |
status(HttpStatus) |
custom | ResponseEntity.status(HttpStatus.FORBIDDEN).build() |
notFound() |
404 Not Found | ResponseEntity.notFound().build() |
5. Builder Pattern API¶
return ResponseEntity.status(HttpStatus.CREATED)
.header("Location", "/api/user/42")
.contentType(MediaType.APPLICATION_JSON)
.body(savedUser);
- Chaining allows combining headers, content type, and body in one statement.
- Immutable β each call produces a new instance.
6. Anatomy of a ResponseEntity¶
Itβs a simple value object β no side effects or thread context.
7. Examples by Common Scenarios¶
β Success (200)¶
β Created (201)¶
URI location = URI.create("/api/users/" + user.getId());
return ResponseEntity.created(location).body(user);
π« No Content (204)¶
β οΈ Bad Request (400)¶
π Forbidden (403)¶
β Not Found (404)¶
βοΈ Custom Headers¶
8. Relationship with HttpEntity and RequestEntity¶
| Type | Represents | Direction | Includes |
|---|---|---|---|
HttpEntity<T> |
Only headers + body | both request/response | β headers, β body |
RequestEntity<T> |
HTTP request metadata | request | + method + URI |
ResponseEntity<T> |
Full HTTP response | response | + status code |
All three share the same base idea: wrap HTTP metadata with body generically.
9. Working with ResponseEntity<Void>¶
Use Void when you want no body:
10. Headers in Depth¶
Headers are stored in an immutable HttpHeaders map.
return ResponseEntity.ok()
.headers(h -> {
h.setCacheControl("no-cache");
h.add("X-Trace-Id", traceId);
})
.body(data);
Or build manually:
HttpHeaders headers = new HttpHeaders();
headers.set("X-Rate-Limit", "100");
return new ResponseEntity<>(data, headers, HttpStatus.OK);
11. Error Handling¶
Spring automatically serializes the body of a ResponseEntity β even for errors:
Use consistent DTOs:
record ApiError(String message, Instant timestamp) {}
return ResponseEntity.status(404)
.body(new ApiError("User not found", Instant.now()));
12. Content Negotiation¶
Spring respects the Accept header automatically:
ResponseEntity.ok().body(user)β returns JSON or XML depending on theAccepttype.contentType(MediaType.APPLICATION_JSON)overrides it explicitly.
13. Using in Reactive Stack (WebFlux)¶
Same class, different behavior β itβs non-blocking:
@GetMapping("/reactive")
public Mono<ResponseEntity<User>> reactive() {
return userService.findAsync()
.map(ResponseEntity::ok)
.defaultIfEmpty(ResponseEntity.notFound().build());
}
The ResponseEntity is wrapped in a Mono, not returned directly.
14. Integration with Exception Handling¶
When thrown from controllers, custom exceptions can produce ResponseEntity responses via:
@ControllerAdvice
public class ApiExceptionHandler {
@ExceptionHandler(UserNotFoundException.class)
public ResponseEntity<ApiError> handleUserNotFound(UserNotFoundException ex) {
return ResponseEntity.status(HttpStatus.NOT_FOUND)
.body(new ApiError(ex.getMessage(), Instant.now()));
}
}
15. Testing with MockMvc¶
mockMvc.perform(get("/user/42"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.id").value(42));
Or unit test directly:
ResponseEntity<User> res = controller.getUser(42L);
assertEquals(HttpStatus.OK, res.getStatusCode());
assertNotNull(res.getBody());
16. Generics Power¶
Spring handles serialization for the list automatically.
17. Typical Usage Pattern¶
@GetMapping("/api/items")
public ResponseEntity<List<Item>> getAll() {
List<Item> items = service.findAll();
if (items.isEmpty())
return ResponseEntity.noContent().build();
return ResponseEntity.ok(items);
}
Concise, readable, fully controlled.
18. Immutable Design¶
- Once built, a
ResponseEntitycanβt be modified. - Each chained method produces a new instance.
- This makes it thread-safe and predictable inside Springβs dispatching.
19. Common Pitfalls¶
| Mistake | Problem | Fix |
|---|---|---|
Returning null instead of ResponseEntity |
500 Internal Server Error | Use .noContent() or .notFound() |
Forgetting .build() after header/status chain |
Compilation error | Always end chain with .build() or .body() |
Using wrong generic (e.g. ResponseEntity<Object>) |
Type confusion, serialization warnings | Use concrete type or <?> |
Adding headers after .build() |
Immutable β no effect | Add before .build() |
| Mixing reactive and MVC types | Mono<ResponseEntity> vs ResponseEntity |
Match controller type (WebFlux vs MVC) |
20. Quick Reference Summary¶
| Action | Code |
|---|---|
| OK (200) | ResponseEntity.ok(body) |
| Created (201) | ResponseEntity.created(uri).body(body) |
| Accepted (202) | ResponseEntity.accepted().build() |
| No Content (204) | ResponseEntity.noContent().build() |
| Bad Request (400) | ResponseEntity.badRequest().body(error) |
| Unauthorized (401) | ResponseEntity.status(HttpStatus.UNAUTHORIZED).build() |
| Forbidden (403) | ResponseEntity.status(HttpStatus.FORBIDDEN).build() |
| Not Found (404) | ResponseEntity.notFound().build() |
| Custom Status | ResponseEntity.status(HttpStatus.I_AM_A_TEAPOT) |
| Add Header | .header("X-Foo", "bar") |
| Set Content Type | .contentType(MediaType.APPLICATION_JSON) |
21. Mind Model Summary¶
Controller method
β returns
ResponseEntity<T>
β
[Status] β HttpStatus
[Headers] β HttpHeaders
[Body] β T (auto-serialized)
Spring converts it into a real HTTP response at the framework boundary.
22. Conceptual Links¶
| Related Concept | Role |
|---|---|
HttpEntity<T> |
Base class without status |
RequestEntity<T> |
HTTP request counterpart |
HttpStatus |
Enum for standard codes |
HttpHeaders |
Collection of header values |
@ResponseBody |
Annotation for direct serialization |
ResponseBodyAdvice |
Interceptor for modifying responses globally |
23. Real-World Pattern¶
Spring REST APIs often structure controller responses as:
return ResponseEntity
.status(HttpStatus.CREATED)
.body(Map.of("id", savedId, "timestamp", Instant.now()));
Framework glue (e.g. @RestController) serializes it to JSON β sets status/headers β writes to network.
24. Bonus β Declarative vs Imperative Style¶
Declarative:
Imperative (using ResponseEntity):
@GetMapping("/user/{id}")
public ResponseEntity<User> createUser(...) {
return ResponseEntity.status(HttpStatus.CREATED).body(user);
}
Declarative is simpler.
Imperative (ResponseEntity) gives precision and dynamic control.
25. Final Mind Model¶
@ResponseBody return value βββΊ HttpMessageConverter
β
βΌ
ResponseEntity<T>
βββββββββββββββββββββββ
β status: HttpStatus β
β headers: HttpHeadersβ
β body: T β
βββββββββββ¬ββββββββββββ
βΌ
Serialized β HTTP
ResponseEntity is the universal adapter between Java objects and raw HTTP semantics β the final step in the Spring request pipeline.