1use crate::error::{Error, Result};
2use crate::types::OxiditeRequest;
3use serde::de::DeserializeOwned;
4
5pub struct Path<T>(pub T);
20
21pub struct Query<T>(pub T);
37
38pub struct Json<T>(pub T);
54
55pub trait FromRequest: Sized {
57 fn from_request(req: &mut OxiditeRequest) -> impl std::future::Future<Output = Result<Self>> + Send;
58}
59
60impl<T: DeserializeOwned + Send> FromRequest for Path<T> {
61 async fn from_request(req: &mut OxiditeRequest) -> Result<Self> {
62 req.extensions()
64 .get::<PathParams>()
65 .ok_or_else(|| Error::BadRequest("No path parameters found".to_string()))
66 .and_then(|params| {
67 serde_json::from_value(params.0.clone())
68 .map(Path)
69 .map_err(|e| Error::BadRequest(format!("Invalid path parameters: {}", e)))
70 })
71 }
72}
73
74impl<T: DeserializeOwned + Send> FromRequest for Query<T> {
75 async fn from_request(req: &mut OxiditeRequest) -> Result<Self> {
76 let query = req.uri().query().unwrap_or("");
77 serde_urlencoded::from_str(query)
78 .map(Query)
79 .map_err(|e| Error::BadRequest(format!("Invalid query parameters: {}", e)))
80 }
81}
82
83impl<T: DeserializeOwned + Send> FromRequest for Json<T> {
84 async fn from_request(req: &mut OxiditeRequest) -> Result<Self> {
85 use http_body_util::BodyExt;
86 use bytes::Buf;
87
88 let body = req.body_mut();
89 let bytes = body.collect().await
90 .map_err(|e| Error::InternalServerError(format!("Failed to read body: {}", e)))?
91 .aggregate();
92
93 serde_json::from_reader(bytes.reader())
94 .map(Json)
95 .map_err(|e| Error::BadRequest(format!("Invalid JSON: {}", e)))
96 }
97}
98
99#[derive(Clone)]
101pub struct PathParams(pub serde_json::Value);
102
103impl<T: serde::Serialize> Json<T> {
105 pub fn into_response(self) -> Result<http_body_util::Full<bytes::Bytes>> {
106 let body = serde_json::to_vec(&self.0)
107 .map_err(|e| Error::InternalServerError(format!("Failed to serialize JSON: {}", e)))?;
108 Ok(http_body_util::Full::new(bytes::Bytes::from(body)))
109 }
110}
111
112pub struct State<T>(pub T);
121
122impl<T: Clone + Send + Sync + 'static> FromRequest for State<T> {
123 async fn from_request(req: &mut OxiditeRequest) -> Result<Self> {
124 req.extensions()
125 .get::<T>()
126 .cloned()
127 .map(State)
128 .ok_or_else(|| Error::InternalServerError("Application state not found in request extensions".to_string()))
129 }
130}
131
132pub struct Form<T>(pub T);
147
148impl<T: DeserializeOwned + Send> FromRequest for Form<T> {
149 async fn from_request(req: &mut OxiditeRequest) -> Result<Self> {
150 use http_body_util::BodyExt;
151 use bytes::Buf;
152
153 let content_type = req.headers()
155 .get("content-type")
156 .and_then(|ct| ct.to_str().ok())
157 .unwrap_or("");
158
159 if !content_type.starts_with("application/x-www-form-urlencoded") {
160 return Err(Error::BadRequest(
161 "Expected application/x-www-form-urlencoded content type".to_string()
162 ));
163 }
164
165 let body = req.body_mut();
166 let bytes = body.collect().await
167 .map_err(|e| Error::InternalServerError(format!("Failed to read body: {}", e)))?
168 .aggregate();
169
170 let body_str = std::str::from_utf8(bytes.chunk())
171 .map_err(|e| Error::BadRequest(format!("Invalid UTF-8 in form data: {}", e)))?;
172
173 serde_urlencoded::from_str(body_str)
174 .map(Form)
175 .map_err(|e| Error::BadRequest(format!("Invalid form data: {}", e)))
176 }
177}
178
179pub struct Cookies {
191 cookies: std::collections::HashMap<String, String>,
192}
193
194impl Cookies {
195 pub fn get(&self, name: &str) -> Option<&String> {
196 self.cookies.get(name)
197 }
198
199 pub fn contains_key(&self, name: &str) -> bool {
200 self.cookies.contains_key(name)
201 }
202
203 pub fn iter(&self) -> impl Iterator<Item = (&String, &String)> {
204 self.cookies.iter()
205 }
206}
207
208impl FromRequest for Cookies {
209 async fn from_request(req: &mut OxiditeRequest) -> Result<Self> {
210 let mut cookies_map = std::collections::HashMap::new();
211
212 if let Some(cookie_header) = req.headers().get(http::header::COOKIE) {
213 if let Ok(cookie_str) = cookie_header.to_str() {
214 for cookie_pair in cookie_str.split(';') {
215 let trimmed = cookie_pair.trim();
216 if let Some((name, value)) = trimmed.split_once('=') {
217 cookies_map.insert(name.trim().to_string(), value.trim().to_string());
218 }
219 }
220 }
221 }
222
223 Ok(Cookies { cookies: cookies_map })
224 }
225}
226
227pub struct Body<T>(pub T);
237
238impl FromRequest for Body<String> {
239 async fn from_request(req: &mut OxiditeRequest) -> Result<Self> {
240 use http_body_util::BodyExt;
241 use bytes::Buf;
242
243 let body = req.body_mut();
244 let bytes = body.collect().await
245 .map_err(|e| Error::InternalServerError(format!("Failed to read body: {}", e)))?
246 .aggregate();
247
248 let body_str = std::str::from_utf8(bytes.chunk())
249 .map_err(|e| Error::InternalServerError(format!("Invalid UTF-8 in body: {}", e)))?
250 .to_string();
251
252 Ok(Body(body_str))
253 }
254}
255
256impl FromRequest for Body<Vec<u8>> {
257 async fn from_request(req: &mut OxiditeRequest) -> Result<Self> {
258 use http_body_util::BodyExt;
259
260 let body = req.body_mut();
261 let bytes = body.collect().await
262 .map_err(|e| Error::InternalServerError(format!("Failed to read body: {}", e)))?
263 .to_bytes();
264
265 Ok(Body(bytes.to_vec()))
266 }
267}