Spring Boot
REST API
ResponseEntity
Error Handling
Java

What is the best way to return different types of ResponseEntity in Spring-Boot Error Handling for REST with Spring

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

In Spring Boot REST APIs, the cleanest error-handling approach is usually not to return many unrelated ResponseEntity body types from the same controller method. A better design is to let successful responses return their domain type, centralize errors in @RestControllerAdvice, and use one consistent error body shape for failures.

Why Many ResponseEntity Types Become Messy

A method that sometimes returns a domain object, sometimes a string, and sometimes a validation list is hard for both clients and maintainers to reason about. Java lets you hide this behind ResponseEntity<?>, but that does not mean it is a good API contract.

A more maintainable design separates:

  • normal success payloads
  • structured error payloads
  • status-code mapping logic

That way, every client sees predictable error fields even when different exceptions occur.

A Good Baseline Design

Let a controller return the success type directly or as ResponseEntity<T> when it needs header or status control.

java
1@RestController
2@RequestMapping("/users")
3public class UserController {
4
5    @GetMapping("/{id}")
6    public ResponseEntity<UserDto> getUser(@PathVariable long id) {
7        UserDto user = findUser(id);
8        return ResponseEntity.ok(user);
9    }
10
11    private UserDto findUser(long id) {
12        throw new ResourceNotFoundException("User not found: " + id);
13    }
14}

The controller focuses on the happy path. Errors are handled elsewhere.

Centralize Error Handling With @RestControllerAdvice

A global handler gives you one place to turn exceptions into consistent HTTP responses.

java
1@RestControllerAdvice
2public class ApiExceptionHandler {
3
4    @ExceptionHandler(ResourceNotFoundException.class)
5    public ResponseEntity<ApiError> handleNotFound(ResourceNotFoundException ex) {
6        ApiError error = new ApiError("NOT_FOUND", ex.getMessage());
7        return ResponseEntity.status(404).body(error);
8    }
9
10    @ExceptionHandler(MethodArgumentNotValidException.class)
11    public ResponseEntity<ApiError> handleValidation(MethodArgumentNotValidException ex) {
12        ApiError error = new ApiError("VALIDATION_ERROR", "Request validation failed");
13        return ResponseEntity.badRequest().body(error);
14    }
15}

Now all failures share the same general structure even though the triggering exceptions differ.

Example Error DTO

Keep the error body small, explicit, and stable.

java
1public class ApiError {
2    private final String code;
3    private final String message;
4
5    public ApiError(String code, String message) {
6        this.code = code;
7        this.message = message;
8    }
9
10    public String getCode() { return code; }
11    public String getMessage() { return message; }
12}

You can extend this later with fields such as timestamp, path, or validation details without changing the controller structure.

When ResponseEntity<?> Is Acceptable

ResponseEntity<?> is not wrong by itself. It is acceptable when the framework or a handler method truly needs flexibility. The problem is when it becomes a substitute for API design.

For example, an exception handler method often naturally returns ResponseEntity<ApiError>, not an unconstrained wildcard.

In controller methods, prefer explicit success types when possible because they document the contract more clearly.

Validation Errors Need Structure Too

Validation is a common place where teams start returning many ad hoc types. Instead, keep validation errors inside the same error envelope.

That gives clients one predictable contract for every failure category.

Common Pitfalls

The most common mistake is returning plain strings for some errors and JSON objects for others. That forces clients to branch on body shape instead of just status codes and error codes.

Another mistake is putting all error-building logic directly inside controller methods. That duplicates code and mixes transport concerns with business flow.

A third issue is using ResponseEntity<?> everywhere and calling the design "flexible" when it is really just underspecified.

Summary

  • Prefer explicit success response types in controllers.
  • Centralize failure handling with @RestControllerAdvice.
  • Use one consistent error DTO shape across exceptions.
  • 'ResponseEntity<?> is possible, but it should not replace a stable API contract.'
  • Good REST error handling is mostly about consistency, not about returning many unrelated body types.

Course illustration
Course illustration

All Rights Reserved.