use crate::Error;
use axum::{
http::StatusCode,
response::{IntoResponse, Response},
Json,
};
impl IntoResponse for Error {
fn into_response(self) -> Response {
let status = StatusCode::from_u16(self.status).unwrap_or(StatusCode::INTERNAL_SERVER_ERROR);
let retry_after = self.retry_after;
let trace_id = self.trace_id.clone();
let mut response = (status, Json(self)).into_response();
if let Some(duration) = retry_after {
let seconds = duration.as_secs().max(1);
response
.headers_mut()
.insert("Retry-After", seconds.to_string().parse().unwrap());
}
if let Some(trace_id) = trace_id {
if let Ok(header_value) = trace_id.parse() {
response.headers_mut().insert("X-Request-Id", header_value);
}
}
response
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::Code;
use std::time::Duration;
#[tokio::test]
async fn test_into_response() {
let err = Error::new(Code::NotFound, 404, "user not found");
let response = err.into_response();
assert_eq!(response.status(), StatusCode::NOT_FOUND);
}
#[tokio::test]
async fn test_with_retry_after() {
let err =
Error::rate_limited("too many requests").with_retry_after(Duration::from_secs(30));
let response = err.into_response();
assert_eq!(response.status(), StatusCode::TOO_MANY_REQUESTS);
assert!(response.headers().contains_key("Retry-After"));
}
#[tokio::test]
async fn test_with_trace_id() {
let err = Error::not_found("user not found").with_trace_id("abc-123");
let response = err.into_response();
assert!(response.headers().contains_key("X-Request-Id"));
}
}