Designing a Unified API Response Structure with Annotations and Interceptors in Java Spring
This article explains how to design a consistent JSON response format for Java Spring APIs, covering status codes, messages, data payloads, and how to use a custom @ResponseResult annotation together with an interceptor and ResponseBodyAdvice to automatically wrap controller results, while also discussing potential improvements and best practices.
The author introduces a typical system architecture diagram and focuses on the API interaction between front‑end and back‑end, where the front‑end calls a URL with parameters and the back‑end processes the request and returns data.
The response format is defined as a JSON object containing three fields: { // return status code code: integer, // return message description message: string, // return value data: object } . The code field should follow a structured convention similar to HTTP status codes, e.g., 200 for success, 301 for permanent redirect, 404 for not found, 500 for server error, and custom ranges such as 1000‑1999 for parameter errors, 2000‑2999 for user errors, 3000‑3999 for interface exceptions.
To avoid scattering status‑code definitions across the codebase, the article proposes using an annotation @ResponseResult to mark controller methods whose return values need to be wrapped. An interceptor checks whether the current request has this annotation and sets a flag accordingly.
A ResponseBodyAdvice implementation then examines the flag; if wrapping is required, it replaces the original return object with the unified Result structure (containing code , message , and data ). The advice also handles exceptions by detecting if the body is an exception type and wrapping it similarly.
In the controller layer, the author shows how to simplify code by using static helper methods in the Result class (e.g., Result.success(data) , Result.failure(code, message) ) and how the final controller method can directly return the business object (e.g., an Order ) without manual wrapping.
The article points out drawbacks of the initial approach—such as every method returning a generic Result and redundant success/failure calls—and suggests returning real business objects for clarity. It also mentions possible optimizations like caching the annotation lookup to avoid reflection on every request.
Finally, the author summarizes the solution: define a unified response format, create the @ResponseResult annotation, implement an interceptor to detect it, use ResponseBodyAdvice to wrap responses, and apply the annotation on controllers to achieve clean, consistent API outputs.
Java Architect Essentials
Committed to sharing quality articles and tutorials to help Java programmers progress from junior to mid-level to senior architect. We curate high-quality learning resources, interview questions, videos, and projects from across the internet to help you systematically improve your Java architecture skills. Follow and reply '1024' to get Java programming resources. Learn together, grow together.
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.