Designing API Interfaces with a Unified Response Format for Backend Services
This article explains how to design a unified API response format in backend development, covering JSON structure, status‑code conventions, controller refactoring, annotation‑based response wrapping, and practical implementation steps to achieve clean, maintainable, and user‑friendly API outputs.
Introduction
In the era of mobile internet, distributed systems, and micro‑services, most projects now adopt a micro‑service architecture with front‑end separation. The front‑end has evolved into a mature "big front‑end" ecosystem, and its technical stack is well‑established.
A typical system architecture is shown below (image omitted).
Although the diagram omits gateways, caches, and message middleware, the focus here is on API design, leaving other modules for readers to supplement.
Interface Interaction
The front‑end sends requests to the server using agreed‑upon URLs and parameters; the server processes the business logic and returns data to the front‑end.
Common RESTful URL conventions and shared request headers such as app_version, api_version, and device are assumed to be known.
How does the back‑end return data to the front‑end?
Return Format
We usually return JSON objects with the following structure:
{
// return status code
code: integer,
// description message
message: string,
// actual data payload
data: object
}CODE Status Codes
The code field can be defined arbitrarily, but ad‑hoc additions quickly become chaotic. It is better to follow the HTTP status‑code philosophy.
Common HTTP status codes:
200 – Request succeeded
301 – Resource permanently moved
404 – Resource not found
500 – Internal server error
We can adopt a similar range‑based design:
1000‑1999 – Parameter errors
2000‑2999 – User errors
3000‑3999 – Interface exceptions
Front‑end developers can quickly locate the error type based on the range and the accompanying message.
Information
When an error occurs, a friendly prompt should be shown together with the code, as illustrated in the following diagram (image omitted).
Data
The data field contains a JSON body that varies according to business needs. A generic result class is shown below (image omitted).
Controller Layer
In the controller we handle business requests and return results, e.g., using orderorder as an example (image omitted).
After obtaining the order object, we wrap it with a result constructor, which can feel cumbersome.
Beautification
We can add static helper methods to the result class for clearer usage (image omitted).
Now the controller code becomes more concise and readable (image omitted).
Elegant Optimization
Although the static‑method approach simplifies the code, several issues remain:
All methods return a generic Result object, which lacks business meaning.
Successful paths call Result.success and error paths call Result.failure, which is redundant.
Null‑check logic for IDs could be replaced by Hibernate validation instead of manual checks.
The best practice is to return the real business object directly, as shown in the following diagram (image omitted).
Implementation Plan
To achieve this, we need to perform the following steps:
Define an annotation @ResponseResult to mark endpoints that require response wrapping.
Create an interceptor that detects whether the current request is annotated with @ResponseResult.
Implement ResponseBodyAdvice together with @ControllerAdvice to wrap the return value when needed.
Annotation Class
The annotation indicates whether a method’s return value should be wrapped (image omitted).
Interceptor
The interceptor checks at runtime if the request’s handler method carries @ResponseResult (image omitted).
Rebuilding the Response Body
If wrapping is required, the advice creates a unified response object. It handles normal success cases; exception handling can be added by checking if the body is an exception type (image omitted).
Controller Refactoring
Apply @ResponseResult on controller classes or methods (image omitted). After this, the API automatically returns a clean, unified response.
Further optimizations, such as caching the annotation lookup to avoid repeated reflection, can be added as needed.
Source: Internet
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.
Selected Java Interview Questions
A professional Java tech channel sharing common knowledge to help developers fill gaps. Follow us!
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.
