omnia_sdk/api/reply.rs
1use std::fmt::Debug;
2use std::ops::Deref;
3
4use http::{HeaderMap, StatusCode};
5
6use crate::api::Body;
7
8/// Top-level response data structure common to all handlers.
9#[derive(Debug)]
10pub struct Reply<B>
11where
12 B: Body,
13{
14 /// HTTP status code.
15 pub status: StatusCode,
16
17 /// HTTP headers, if any.
18 pub headers: HeaderMap,
19
20 /// Response body.
21 pub body: B,
22}
23
24impl<B: Body> Reply<B> {
25 /// Create a success response
26 #[must_use]
27 pub fn ok(body: B) -> Self {
28 Self {
29 status: StatusCode::OK,
30 headers: HeaderMap::new(),
31 body,
32 }
33 }
34
35 /// Create a created response (201)
36 #[must_use]
37 pub fn created(body: B) -> Self {
38 Self {
39 status: StatusCode::CREATED,
40 headers: HeaderMap::new(),
41 body,
42 }
43 }
44
45 /// Create an accepted response (202)
46 #[must_use]
47 pub fn accepted(body: B) -> Self {
48 Self {
49 status: StatusCode::ACCEPTED,
50 headers: HeaderMap::new(),
51 body,
52 }
53 }
54
55 /// Check if response is successful (2xx)
56 #[must_use]
57 pub fn is_success(&self) -> bool {
58 self.status.is_success()
59 }
60
61 /// Create a success response with a specific status code.
62 #[must_use]
63 pub const fn status(mut self, status: StatusCode) -> Self {
64 self.status = status;
65 self
66 }
67
68 /// Add headers to the response.
69 #[must_use]
70 pub fn headers(mut self, headers: HeaderMap) -> Self {
71 self.headers = headers;
72 self
73 }
74}
75
76impl<B: Body> From<B> for Reply<B> {
77 fn from(body: B) -> Self {
78 Self {
79 status: StatusCode::OK,
80 headers: HeaderMap::new(),
81 body,
82 }
83 }
84}
85
86impl<B: Body> Deref for Reply<B> {
87 type Target = B;
88
89 fn deref(&self) -> &Self::Target {
90 &self.body
91 }
92}
93
94// /// Implemented by the `Reply::body` to convert itself into a body compatible with
95// /// `[IntoResponse]`.
96// pub trait IntoBody: Body {
97// /// Convert into a body + content type.
98// ///
99// /// # Errors
100// ///
101// /// Returns an error if the body cannot be encoded (for example, if JSON
102// /// serialization fails).
103// fn into_body(self) -> anyhow::Result<Vec<u8>>;
104// }
105
106// impl<T> IntoResponse for Reply<T>
107// where
108// T: IntoBody,
109// {
110// fn into_response(self) -> Response {
111// let body = match self.body.into_body() {
112// Ok(v) => v,
113// Err(e) => {
114// return (StatusCode::INTERNAL_SERVER_ERROR, format!("body encoding error: {e}"))
115// .into_response();
116// }
117// };
118
119// let mut hm = self.headers;
120// if !hm.contains_key(header::CONTENT_TYPE) {
121// hm.insert(header::CONTENT_TYPE, HeaderValue::from_static("text/plain; charset=utf-8"));
122// }
123
124// let status = self.status;
125// (status, hm, body).into_response()
126// }
127// }