When designing or modifying REST API response structures, prevent common design flaws.
Pitfall #1: Generic Method Overload Ambiguity
Scenario: When the return type is String, Java overload resolution may match the wrong method
Root Cause
During Java method overload resolution,String type parameters will preferentially match success(String message) rather than success(T data), causing data to enter the wrong field.
Incorrect Example
// ApiResponse 有两个重载:
public static <T> ApiResponse<T> success(T data)
public static <T> ApiResponse<T> success(String message, T data)
// ❌ 错误: String 类型匹配到 success(String message)
String avatarUrl = "http://example.com/avatar.jpg";
return ApiResponse.success(avatarUrl);
// 结果: {"code":200, "message":"http://...", "data":null}
// 前端 data.data 拿到 null,导致功能异常
Correct Approach
// ✅ 方案1: 明确指定 message 参数(推荐)
return ApiResponse.success("上传成功", avatarUrl);
// 结果: {"code":200, "message":"上传成功", "data":"http://..."}
// ✅ 方案2: 使用泛型明确类型
return ApiResponse.<String>success(avatarUrl);
// ✅ 方案3: 包装为 DTO(复杂场景推荐)
return ApiResponse.success(new UploadResult(avatarUrl));
Checklist
- When returning the String type, is the message parameter explicitly specified
- Are there overloaded methods with one parameter and two parameters
- Does the frontend correctly parse the
datafield (rather thanmessage) - Are there unit tests to verify the response structure
Pitfall #2: Unclear Response Field Semantics
Scenario: message and data field responsibilities are confused
Specification
| Field | Purpose | Type | Example |
|---|---|---|---|
code |
Business status code | int | 200, 400, 500 |
message |
User-readable prompt message | String | "Upload successful", "Invalid parameters" |
data |
Business data | T | {"url": "..."}, [...] |
timestamp |
Response timestamp | String | ISO 8601 format |
Incorrect Example
// ❌ 错误: 把业务数据放在 message
return ApiResponse.success("avatars/2026-04/xxx.jpeg");
// ❌ 错误: message 包含技术细节
return ApiResponse.error("NullPointerException at line 42");
Correct Approach
// ✅ message 是用户提示,data 是业务数据
return ApiResponse.success("上传成功", avatarUrl);
// ✅ 错误信息对用户友好
return ApiResponse.error("文件格式不支持,请上传 JPG/PNG 格式");
Pitfall #3: Inconsistent Null Handling
Scenario: Return when there is no data null、{}、[] is not consistent
Specification
| Scenario | Recommended Return | Description |
|---|---|---|
| Single object does not exist | data: null |
Frontend checks if (!data) |
| Empty list | data: [] |
Frontend can iterate directly |
| Empty paginated data | data: {list: [], total: 0} |
Maintain consistent structure |
Incorrect Example
// ❌ 错误: 有时返回 null,有时返回空对象
if (user == null) {
return ApiResponse.success(null); // 不一致
}
return ApiResponse.success(new UserVO());
Correct Approach
// ✅ 统一返回 null 表示不存在
if (user == null) {
return ApiResponse.success(null);
}
return ApiResponse.success(userVO);
// ✅ 列表统一返回空数组
List<UserVO> users = userService.list();
return ApiResponse.success(users); // 永远不返回 null
Pitfall #4: Confusing HTTP Status Codes with Business Status Codes
Scenario: Return HTTP 500 when business fails
Specification
| Scenario | HTTP Status Code | Business code | Description |
|---|---|---|---|
| Success | 200 | 200 | Normal response |
| Parameter error | 200 | 400 | Business layer validation failed |
| Unauthorized | 401 | - | Authentication failed |
| No permission | 403 | - | Authorization failed |
| Resource does not exist | 200 | 404 | Business resource does not exist |
| Server error | 500 | - | Code exception |
Incorrect Example
// ❌ 错误: 业务失败返回 HTTP 500
if (user == null) {
throw new RuntimeException("用户不存在"); // HTTP 500
}
Correct Approach
// ✅ 业务失败返回 HTTP 200 + 业务 code
if (user == null) {
return ApiResponse.error(404, "用户不存在"); // HTTP 200
}
// ✅ 只有代码异常才返回 HTTP 500
@ExceptionHandler(Exception.class)
public ResponseEntity<ApiResponse<?>> handleException(Exception e) {
log.error("服务器错误", e);
return ResponseEntity.status(500)
.body(ApiResponse.error("服务器错误,请稍后重试"));
}
Checklist (API Design)
Return Value Design:
- When returning the String type, is the message parameter explicitly specified
-
messageDoes the field contain only user-readable prompt messages -
dataDoes the field contain only business data - Is null handling consistent (null / [] / {})
Status Code Design:
- Are HTTP status codes used only for the transport layer (200/401/403/500)
- Is the business status code in the response body's
codefield - Does business failure return HTTP 200 + business code
Frontend-backend protocol:
- Does the frontend correctly parse the
datafield - Does the frontend handle the
data: nullcase - Is there API documentation or interface testing
Scope of application
- Java: Spring Boot REST API
- Go: Gin/Echo REST API
- Node.js: Express/Koa REST API
- Python: FastAPI/Flask REST API
Rule traceability
> 📋 本回复遵循:`api-design-safety` - API 设计安全规范