ayun_server/response/
builder.rs1use crate::ServerResult;
2use axum::{
3 body::Body,
4 http::{header, response::Builder, HeaderName, HeaderValue, StatusCode},
5 response::Response,
6};
7use std::any::Any;
8
9pub struct ResponseBuilder {
10 inner: Builder,
11}
12
13impl Default for ResponseBuilder {
14 fn default() -> Self {
15 Self::new()
16 }
17}
18
19impl ResponseBuilder {
20 fn new() -> Self {
21 Self {
22 inner: Builder::new().status(StatusCode::OK),
23 }
24 }
25
26 pub fn builder(self) -> Builder {
27 self.inner
28 }
29
30 pub fn status<T>(self, status: T) -> Self
31 where
32 StatusCode: TryFrom<T>,
33 <StatusCode as TryFrom<T>>::Error: Into<axum::http::Error>,
34 {
35 Self {
36 inner: self.inner.status(status),
37 }
38 }
39
40 pub fn header<K, V>(self, key: K, value: V) -> Self
41 where
42 HeaderName: TryFrom<K>,
43 <HeaderName as TryFrom<K>>::Error: Into<axum::http::Error>,
44 HeaderValue: TryFrom<V>,
45 <HeaderValue as TryFrom<V>>::Error: Into<axum::http::Error>,
46 {
47 Self {
48 inner: self.inner.header(key, value),
49 }
50 }
51
52 pub fn extension<T>(self, extension: T) -> Self
53 where
54 T: Clone + Any + Send + Sync + 'static,
55 {
56 Self {
57 inner: self.inner.extension(extension),
58 }
59 }
60
61 pub fn etag(self, etag: &str) -> ServerResult<Self> {
62 Ok(Self {
63 inner: self
64 .inner
65 .header(header::ETAG, HeaderValue::from_str(etag)?),
66 })
67 }
68
69 #[cfg(feature = "response-cookie")]
70 pub fn cookies(
71 self,
72 cookies: &[axum_extra::extract::cookie::Cookie<'_>],
73 ) -> ServerResult<Self> {
74 let mut resp = self.inner;
75
76 for cookie in cookies {
77 let header_value = cookie.encoded().to_string().parse::<HeaderValue>()?;
78 resp = resp.header(header::SET_COOKIE, header_value);
79 }
80
81 Ok(Self { inner: resp })
82 }
83
84 pub fn text(self, content: &str) -> ServerResult<Response> {
85 Ok(self
86 .inner
87 .header(
88 header::CONTENT_TYPE,
89 HeaderValue::from_static(mime::TEXT_PLAIN_UTF_8.as_ref()),
90 )
91 .body(Body::from(content.to_string()))?)
92 }
93
94 pub fn empty(self) -> ServerResult<Response> {
95 Ok(self.inner.body(Body::empty())?)
96 }
97
98 pub fn html(self, content: &str) -> ServerResult<Response> {
99 Ok(self
100 .inner
101 .header(
102 header::CONTENT_TYPE,
103 HeaderValue::from_static(mime::TEXT_HTML_UTF_8.as_ref()),
104 )
105 .body(Body::from(content.to_string()))?)
106 }
107
108 #[cfg(feature = "response-json")]
109 pub fn json<T>(self, item: T) -> ServerResult<Response>
110 where
111 T: serde::Serialize,
112 {
113 use bytes::{BufMut, BytesMut};
114
115 let mut buf = BytesMut::with_capacity(128).writer();
116 serde_json::to_writer(&mut buf, &item)?;
117
118 let body = Body::from(buf.into_inner().freeze());
119
120 Ok(self
121 .inner
122 .header(
123 header::CONTENT_TYPE,
124 HeaderValue::from_static(mime::APPLICATION_JSON.as_ref()),
125 )
126 .body(body)?)
127 }
128
129 #[cfg(feature = "response-view")]
130 pub fn view<T>(self, template: &str, data: T) -> ServerResult<Response>
131 where
132 T: serde::Serialize,
133 {
134 let engine = ayun_core::support::app().resolve::<ayun_view::View>()?;
135 let html = engine.render(template, &tera::Context::from_serialize(data)?)?;
136
137 self.html(&html)
138 }
139
140 pub fn redirect(self, to: &str) -> ServerResult<Response> {
141 Ok(self
142 .inner
143 .status(StatusCode::SEE_OTHER)
144 .header(header::LOCATION, to)
145 .body(Body::empty())?)
146 }
147}