后端重写提交
This commit is contained in:
@@ -1,25 +1,15 @@
|
||||
use axum::Json;
|
||||
use serde::Serialize;
|
||||
use serde_json::{Value, json};
|
||||
use serde_json::Value;
|
||||
#[cfg(test)]
|
||||
use serde_json::json;
|
||||
use shared_contracts::api::{
|
||||
API_VERSION, ApiErrorEnvelope, ApiErrorPayload, ApiResponseMeta, ApiSuccessEnvelope,
|
||||
LegacyApiErrorResponse,
|
||||
};
|
||||
use time::{OffsetDateTime, format_description::well_known::Rfc3339};
|
||||
|
||||
use crate::{http_error::ApiErrorPayload, request_context::RequestContext};
|
||||
|
||||
pub const API_VERSION: &str = "2026-04-08";
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
struct ApiResponseMeta {
|
||||
#[serde(rename = "apiVersion")]
|
||||
api_version: &'static str,
|
||||
#[serde(rename = "requestId", skip_serializing_if = "Option::is_none")]
|
||||
request_id: Option<String>,
|
||||
#[serde(rename = "routeVersion")]
|
||||
route_version: &'static str,
|
||||
operation: Option<String>,
|
||||
#[serde(rename = "latencyMs")]
|
||||
latency_ms: u64,
|
||||
timestamp: String,
|
||||
}
|
||||
use crate::request_context::RequestContext;
|
||||
|
||||
// 当前阶段先把成功响应 envelope helper 准备好,后续 `/healthz` 与业务 handler 会直接复用这里的输出逻辑。
|
||||
#[allow(dead_code)]
|
||||
@@ -30,12 +20,13 @@ where
|
||||
if let Some(context) = request_context
|
||||
&& context.wants_envelope()
|
||||
{
|
||||
return Json(json!({
|
||||
"ok": true,
|
||||
"data": data,
|
||||
"error": null,
|
||||
"meta": build_api_response_meta(Some(context)),
|
||||
}));
|
||||
return Json(
|
||||
serde_json::to_value(ApiSuccessEnvelope::new(
|
||||
data,
|
||||
build_api_response_meta(Some(context)),
|
||||
))
|
||||
.unwrap_or(Value::Null),
|
||||
);
|
||||
}
|
||||
|
||||
Json(serde_json::to_value(data).unwrap_or(Value::Null))
|
||||
@@ -48,33 +39,30 @@ pub fn json_error_body(
|
||||
let meta = build_api_response_meta(request_context);
|
||||
|
||||
if request_context.is_some_and(RequestContext::wants_envelope) {
|
||||
return Json(json!({
|
||||
"ok": false,
|
||||
"data": null,
|
||||
"error": error,
|
||||
"meta": meta,
|
||||
}));
|
||||
return Json(
|
||||
serde_json::to_value(ApiErrorEnvelope::new(error.clone(), meta)).unwrap_or(Value::Null),
|
||||
);
|
||||
}
|
||||
|
||||
Json(json!({
|
||||
"error": error,
|
||||
"meta": meta,
|
||||
}))
|
||||
Json(
|
||||
serde_json::to_value(LegacyApiErrorResponse::new(error.clone(), meta))
|
||||
.unwrap_or(Value::Null),
|
||||
)
|
||||
}
|
||||
|
||||
fn build_api_response_meta(request_context: Option<&RequestContext>) -> ApiResponseMeta {
|
||||
ApiResponseMeta {
|
||||
api_version: API_VERSION,
|
||||
request_id: request_context.map(|context| context.request_id().to_string()),
|
||||
route_version: API_VERSION,
|
||||
operation: request_context.map(|context| context.operation().to_string()),
|
||||
latency_ms: request_context
|
||||
ApiResponseMeta::new(
|
||||
API_VERSION,
|
||||
request_context.map(|context| context.request_id().to_string()),
|
||||
API_VERSION,
|
||||
request_context.map(|context| context.operation().to_string()),
|
||||
request_context
|
||||
.map(RequestContext::elapsed)
|
||||
.unwrap_or_default(),
|
||||
timestamp: OffsetDateTime::now_utc()
|
||||
OffsetDateTime::now_utc()
|
||||
.format(&Rfc3339)
|
||||
.unwrap_or_else(|_| "1970-01-01T00:00:00Z".to_string()),
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@@ -122,7 +110,7 @@ mod tests {
|
||||
fn error_body_returns_legacy_shape_without_envelope_header() {
|
||||
let request_context = build_request_context(false);
|
||||
let error = ApiErrorPayload {
|
||||
code: "NOT_FOUND",
|
||||
code: "NOT_FOUND".to_string(),
|
||||
message: "资源不存在".to_string(),
|
||||
details: None,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user