Skip to main content

arcly_http/web/
responses.rs

1//! Success response shapes beyond `Json<T>`.
2//!
3//! Each type implements `axum::response::IntoResponse` and is recognised by
4//! the route macro's return-type walker so its inner payload type contributes
5//! to the OpenAPI response schema and its status code becomes the operation's
6//! default success code.
7
8use axum::http::{HeaderValue, StatusCode};
9use axum::response::{IntoResponse, Response};
10use serde::Serialize;
11
12/// `201 Created` with an optional `Location` header.
13pub struct Created<T> {
14    pub body: T,
15    pub location: Option<&'static str>,
16}
17
18impl<T> Created<T> {
19    #[inline]
20    pub fn new(body: T) -> Self {
21        Self {
22            body,
23            location: None,
24        }
25    }
26    #[inline]
27    pub fn at(body: T, location: &'static str) -> Self {
28        Self {
29            body,
30            location: Some(location),
31        }
32    }
33}
34
35impl<T: Serialize> IntoResponse for Created<T> {
36    fn into_response(self) -> Response {
37        let mut r = (StatusCode::CREATED, axum::Json(self.body)).into_response();
38        if let Some(loc) = self.location {
39            if let Ok(v) = HeaderValue::from_str(loc) {
40                r.headers_mut().insert("Location", v);
41            }
42        }
43        r
44    }
45}
46
47/// `204 No Content`. Carries no body.
48pub struct NoContent;
49impl IntoResponse for NoContent {
50    fn into_response(self) -> Response {
51        StatusCode::NO_CONTENT.into_response()
52    }
53}
54
55/// `202 Accepted` — for async / queued work.
56pub struct Accepted<T>(pub T);
57impl<T: Serialize> IntoResponse for Accepted<T> {
58    fn into_response(self) -> Response {
59        (StatusCode::ACCEPTED, axum::Json(self.0)).into_response()
60    }
61}