Standardizing Spring Boot API Responses to Eliminate Inconsistent Interfaces
The article explains why unifying API return formats in Spring Boot prevents front‑end confusion, introduces a simple Result wrapper with code/message/data, shows manual and automatic (ResponseBodyAdvice) usage, and offers practical tips for clean, predictable backend contracts.
Why Standardize Responses
API contracts are the foundation of front‑end/back‑end interaction. When each endpoint uses a different success/failure indicator—e.g., {"code":0,"data":{}}, {"success":true,"result":{}}, plain true, or raw HTTP 500—front‑end developers must write many conditional checks, leading to bugs and wasted integration time.
The goal is to make all endpoints look the same .
{
"code": 0,
"message": "ok",
"data": { ... }
}Using the three‑field pattern ( code for status, message for a human‑readable description, and data for the payload) provides a clear, predictable contract.
Result Utility Class
A minimal, reusable wrapper is defined as follows:
@Data
public class Result<T> {
private int code;
private String message;
private T data;
public static <T> Result<T> ok(T data) {
Result<T> r = new Result<>();
r.code = 0;
r.message = "ok";
r.data = data;
return r;
}
public static <T> Result<T> fail(int code, String msg) {
Result<T> r = new Result<>();
r.code = code;
r.message = msg;
return r;
}
}Controller methods can return the wrapper directly:
@GetMapping("/{id}")
public Result<User> get(@PathVariable Long id) {
return Result.ok(userService.findById(id));
}This approach yields clean, uniform responses.
Can We Omit Explicit Result.ok() ?
Writing Result.ok(...) for every method can feel repetitive. Spring's ResponseBodyAdvice can automatically wrap non‑Result objects:
@RestControllerAdvice
public class ResultAdvice implements ResponseBodyAdvice<Object> {
@Override
public boolean supports(MethodParameter p, Class c) { return true; }
@Override
public Object beforeBodyWrite(Object body, ...) {
if (body instanceof Result) return body;
return Result.ok(body);
}
}With this advice, a controller can simply return the domain object:
@GetMapping("/{id}")
public User get(@PathVariable Long id) {
return userService.findById(id);
}The resulting JSON is identical, but the controller code stays cleaner.
Practical Tips (Learned from Pitfalls)
Use an integer for code instead of a string enum. Front‑end checks are simpler with numbers.
Reserve code ranges for modules. For example, user‑related errors 1000‑1999, order‑related errors 2000‑2999, which aids troubleshooting.
Do not put stack traces in message . Stack traces belong in logs; users should see a friendly message.
Avoid nested Result<Result<XX>> structures. When using the advice, ensure it skips wrapping an object that is already a Result.
Conclusion
Consistent API response formats are a baseline for team collaboration. A small three‑field wrapper saves significant integration effort and makes debugging more efficient.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
