refactor(api): 统一 HTTP 200 响应契约

This commit is contained in:
2026-08-01 10:17:20 +08:00
parent f2e8935dbc
commit cad6c37af4
45 changed files with 689 additions and 289 deletions
@@ -38,7 +38,6 @@ public class MerchantWarehouseController {
)
@ApiResponses({
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "200", description = "Query succeeded / 查询成功"),
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "400", description = "Invalid query / 查询参数无效"),
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "401", description = "Authentication required / 需要登录")
})
@GetMapping
@@ -55,7 +54,6 @@ public class MerchantWarehouseController {
@ApiResponses({
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "200", description = "Query succeeded / 查询成功"),
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "401", description = "Authentication required / 需要登录"),
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "404", description = "Warehouse not found in current tenant / 当前租户下仓库不存在")
})
@GetMapping("/{id}")
public ApiResponse<WarehouseDetailResponse> detail(
@@ -46,7 +46,6 @@ public class PlatformExpressCompanyController {
@Operation(summary = "分页查询快递公司", description = "按目标租户、关键字和状态分页查询快递公司")
@ApiResponses({
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "200", description = "查询成功"),
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "400", description = "查询条件无效"),
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "401", description = "需要登录"),
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "403", description = "需要平台快递公司查询权限")
})
@@ -46,7 +46,6 @@ public class PlatformPartnerController {
@Operation(summary = "分页查询往来单位", description = "按目标租户、关键字、类型和状态分页查询往来单位")
@ApiResponses({
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "200", description = "查询成功"),
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "400", description = "查询条件无效"),
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "401", description = "需要登录"),
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "403", description = "需要平台往来单位查询权限")
})
@@ -48,9 +48,7 @@ public class PlatformWarehouseController {
)
@ApiResponses({
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "200", description = "Created successfully / 创建成功"),
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "400", description = "Invalid request / 请求参数无效"),
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "403", description = "Platform access required / 需要平台端权限"),
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "409", description = "Warehouse code already exists / 仓库编码已存在")
})
@PostMapping
public ApiResponse<Long> create(@AuthenticationPrincipal AuthenticatedUser user,
@@ -66,10 +64,7 @@ public class PlatformWarehouseController {
)
@ApiResponses({
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "200", description = "Updated successfully / 更新成功"),
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "400", description = "Invalid request / 请求参数无效"),
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "403", description = "Platform access or tenant validation failed / 平台权限或租户校验失败"),
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "404", description = "Warehouse not found / 仓库不存在"),
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "409", description = "Warehouse code already exists / 仓库编码已存在")
})
@PutMapping("/{id}")
public ApiResponse<Void> update(
@@ -91,7 +86,6 @@ public class PlatformWarehouseController {
)
@ApiResponses({
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "200", description = "Query succeeded / 查询成功"),
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "400", description = "Invalid query / 查询参数无效"),
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "403", description = "Platform access required / 需要平台端权限")
})
@GetMapping
@@ -112,7 +106,6 @@ public class PlatformWarehouseController {
@ApiResponses({
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "200", description = "Query succeeded / 查询成功"),
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "403", description = "Platform access required / 需要平台端权限"),
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "404", description = "Warehouse not found / 仓库不存在")
})
@GetMapping("/{id}")
public ApiResponse<WarehouseDetailResponse> detail(
@@ -132,9 +125,7 @@ public class PlatformWarehouseController {
)
@ApiResponses({
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "200", description = "Status changed / 状态变更成功"),
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "400", description = "Invalid status / 状态无效"),
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "403", description = "Platform access required / 需要平台端权限"),
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "404", description = "Warehouse not found / 仓库不存在")
})
@PatchMapping("/{id}/status")
public ApiResponse<Void> status(
@@ -13,7 +13,7 @@ import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
/** 仓储数据库不可用或结构漂移时返回可识别的 503,并保留完整链路日志。 */
/** 仓储数据库不可用或结构漂移时返回可识别的业务码,并保留完整链路日志。 */
@Order(Ordered.HIGHEST_PRECEDENCE)
@RestControllerAdvice(basePackages = "com.baiyue.warehouse.controller")
public class WarehouseDataAccessExceptionHandler {
@@ -25,7 +25,7 @@ public class WarehouseDataAccessExceptionHandler {
String traceId = CorrelationContext.traceId(request);
log.error("Warehouse data access failure requestId={} traceId={}", requestId, traceId, exception);
ResultCode code = ResultCode.SERVICE_UNAVAILABLE;
return ResponseEntity.status(code.httpStatus()).body(ApiResponse.failure(code,
return ResponseEntity.ok(ApiResponse.failure(code,
"仓储数据库暂不可用,请检查数据源和数据库迁移", requestId, traceId));
}
}
@@ -13,7 +13,7 @@ import static org.mockito.Mockito.when;
@DisplayName("仓库数据访问异常处理器")
class WarehouseDataAccessExceptionHandlerTest {
@Test
@DisplayName("数据源故障统一返回503并保留请求标识")
@DisplayName("数据源故障统一返回HTTP 200与S0503业务码并保留请求标识")
void shouldReturnServiceUnavailableAndPreserveRequestIdsForDataSourceFailure() {
HttpServletRequest request = mock(HttpServletRequest.class);
when(request.getAttribute("requestId")).thenReturn("request-1");
@@ -22,7 +22,7 @@ class WarehouseDataAccessExceptionHandlerTest {
var response = new WarehouseDataAccessExceptionHandler().handle(
new DataAccessResourceFailureException("database unavailable"), request);
assertThat(response.getStatusCode().value()).isEqualTo(503);
assertThat(response.getStatusCode().value()).isEqualTo(200);
assertThat(response.getBody()).isNotNull();
assertThat(response.getBody().code()).isEqualTo(ResultCode.SERVICE_UNAVAILABLE.code());
assertThat(response.getBody().message()).contains("数据库");