use axum::response::{IntoResponse, Response};
#[cfg(feature = "serde")]
use axum::http::HeaderValue;
#[cfg(feature = "serde")]
use axum::http::header::{CONTENT_LENGTH, CONTENT_TYPE};
#[cfg(feature = "serde")]
pub struct Json<T>(pub T);
#[cfg(feature = "serde")]
impl<T> IntoResponse for Json<T>
where
T: serde::Serialize,
{
fn into_response(self) -> Response {
let body = serde_json::to_vec(&self.0).unwrap_or_else(|_| {
br#"{"type":"urn:arcature:problem:internal","title":"Internal Server Error","status":500}"#
.to_vec()
});
let len = body.len();
let mut response = body.into_response();
response
.headers_mut()
.insert(CONTENT_TYPE, HeaderValue::from_static("application/json"));
response
.headers_mut()
.insert(CONTENT_LENGTH, HeaderValue::from(len));
response
}
}
pub struct Empty;
impl IntoResponse for Empty {
fn into_response(self) -> Response {
(
axum::http::StatusCode::NO_CONTENT,
axum::body::Body::empty(),
)
.into_response()
}
}
#[cfg(feature = "serde")]
pub struct Page<T>(pub T);
#[cfg(feature = "serde")]
impl<T> IntoResponse for Page<T>
where
T: serde::Serialize,
{
fn into_response(self) -> Response {
Json(self.0).into_response()
}
}
#[cfg(test)]
mod tests {
use super::*;
use axum::http::StatusCode;
#[test]
fn empty_returns_204() {
let response = Empty.into_response();
assert_eq!(response.status(), StatusCode::NO_CONTENT);
}
#[cfg(feature = "serde")]
#[test]
fn json_serializes_body() {
let response = Json(serde_json::json!({"hello": "world"})).into_response();
assert_eq!(response.status(), StatusCode::OK);
assert_eq!(
response
.headers()
.get(CONTENT_TYPE)
.map(|v| v.to_str().unwrap_or("")),
Some("application/json")
);
}
#[cfg(feature = "serde")]
#[test]
fn page_serializes_as_json() {
#[derive(serde::Serialize)]
struct TestData {
value: u32,
}
let response = Page(TestData { value: 42 }).into_response();
assert_eq!(response.status(), StatusCode::OK);
assert_eq!(
response
.headers()
.get(CONTENT_TYPE)
.map(|v| v.to_str().unwrap_or("")),
Some("application/json")
);
}
}