Designing Clean API Response Wrappers for Spring MVC Controllers
This article explains how to structure API responses in a micro‑service architecture, defines a unified JSON format with status codes, shows how to use annotations and interceptors to automatically wrap results, and demonstrates code refactoring for cleaner, more maintainable controller logic.
Introduction
In today’s mobile‑first, distributed, micro‑service world, most projects adopt a micro‑service framework with front‑end separation. A typical system architecture is shown below.
Some readers may think the diagram is too simple because it omits gateways, caches, or message middleware; the focus here is on API interfaces, and other modules can be added as needed.
Interface Interaction
The front‑end sends requests to the server using agreed URL paths and parameters, the server processes the business logic and returns data to the front‑end.
URL paths follow RESTful conventions and include common request headers such as app_version, api_version, device, etc.
Return Format
Responses are usually returned as JSON objects with the following structure:
{
"code": integer, // status code
"message": string, // description
"data": object // payload
}Code Status
The code field is a custom status code. Adding codes ad‑hoc (e.g., 101 for permission errors, 102 for data errors) quickly becomes chaotic.
It is better to follow the design of HTTP status codes.
200 - Request succeeded
301 - Resource permanently moved
404 - Resource not found
500 - Internal server errorWe can group error types into ranges, for example:
#1000‑1999 Parameter errors
#2000‑2999 User errors
#3000‑3999 Interface exceptionsThis allows developers to quickly locate the error type based on the code range.
Message
When an error occurs, a friendly message should accompany the code, making troubleshooting easier.
Data
The data field contains the business‑specific JSON payload.
Controller Layer
Controllers handle business requests and return results. Previously, a Result wrapper was used, which added boilerplate code.
By adding static helper methods to the result class, the code becomes more readable and concise.
Elegant Optimization
Issues with the Result wrapper:
1. Every method returns a generic Result without business meaning. 2. Success and failure are both wrapped, adding unnecessary verbosity. 3. Manual null checks duplicate validation frameworks like Hibernate Validator.
The preferred approach is to return the actual business object directly.
Implementation Plan
Key steps:
1. Define a custom annotation @ResponseResult to mark methods whose return values need wrapping. 2. Intercept requests to detect the presence of the annotation. 3. Implement ResponseBodyAdvice and ControllerAdvice to wrap the return value when required.
Annotation Class
The annotation indicates whether a method’s return value should be wrapped.
Interceptor
The interceptor checks if the current request’s handler method carries @ResponseResult and sets a flag accordingly.
Rebuilding the Response Body
If wrapping is needed, the advice creates a unified response object for successful results; exception handling follows a similar pattern.
Controller Refactoring
Apply @ResponseResult at the class or method level, and let the framework handle the response wrapping automatically.
This approach yields cleaner, more elegant controller code while maintaining a consistent API contract.
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.
21CTO
21CTO (21CTO.com) offers developers community, training, and services, making it your go‑to learning and service platform.
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.
