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 async fn from_request(req: &mut OxiditeRequest) -> Result<Self>;
58}
59
60impl<T: DeserializeOwned> 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> 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> 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 fn from_request(req: &mut OxiditeRequest) -> impl std::future::Future<Output = Result<Self>> {
124 async {
125 req.extensions()
126 .get::<T>()
127 .cloned()
128 .map(State)
129 .ok_or_else(|| Error::InternalServerError("Application state not found in request extensions".to_string()))
130 }
131 }
132}
133
134pub struct Form<T>(pub T);
149
150impl<T: DeserializeOwned> FromRequest for Form<T> {
151 async fn from_request(req: &mut OxiditeRequest) -> Result<Self> {
152 use http_body_util::BodyExt;
153 use bytes::Buf;
154
155 let content_type = req.headers()
157 .get("content-type")
158 .and_then(|ct| ct.to_str().ok())
159 .unwrap_or("");
160
161 if !content_type.starts_with("application/x-www-form-urlencoded") {
162 return Err(Error::BadRequest(
163 "Expected application/x-www-form-urlencoded content type".to_string()
164 ));
165 }
166
167 let body = req.body_mut();
168 let bytes = body.collect().await
169 .map_err(|e| Error::InternalServerError(format!("Failed to read body: {}", e)))?
170 .aggregate();
171
172 let body_str = std::str::from_utf8(bytes.chunk())
173 .map_err(|e| Error::BadRequest(format!("Invalid UTF-8 in form data: {}", e)))?;
174
175 serde_urlencoded::from_str(body_str)
176 .map(Form)
177 .map_err(|e| Error::BadRequest(format!("Invalid form data: {}", e)))
178 }
179}
180
181pub struct Cookies {
193 cookies: std::collections::HashMap<String, String>,
194}
195
196impl Cookies {
197 pub fn get(&self, name: &str) -> Option<&String> {
198 self.cookies.get(name)
199 }
200
201 pub fn contains_key(&self, name: &str) -> bool {
202 self.cookies.contains_key(name)
203 }
204
205 pub fn iter(&self) -> impl Iterator<Item = (&String, &String)> {
206 self.cookies.iter()
207 }
208}
209
210impl FromRequest for Cookies {
211 async fn from_request(req: &mut OxiditeRequest) -> Result<Self> {
212 let mut cookies_map = std::collections::HashMap::new();
213
214 if let Some(cookie_header) = req.headers().get(http::header::COOKIE) {
215 if let Ok(cookie_str) = cookie_header.to_str() {
216 for cookie_pair in cookie_str.split(';') {
217 let trimmed = cookie_pair.trim();
218 if let Some((name, value)) = trimmed.split_once('=') {
219 cookies_map.insert(name.trim().to_string(), value.trim().to_string());
220 }
221 }
222 }
223 }
224
225 Ok(Cookies { cookies: cookies_map })
226 }
227}
228
229pub struct Body<T>(pub T);
239
240impl FromRequest for Body<String> {
241 async fn from_request(req: &mut OxiditeRequest) -> Result<Self> {
242 use http_body_util::BodyExt;
243 use bytes::Buf;
244
245 let body = req.body_mut();
246 let bytes = body.collect().await
247 .map_err(|e| Error::InternalServerError(format!("Failed to read body: {}", e)))?
248 .aggregate();
249
250 let body_str = std::str::from_utf8(bytes.chunk())
251 .map_err(|e| Error::InternalServerError(format!("Invalid UTF-8 in body: {}", e)))?
252 .to_string();
253
254 Ok(Body(body_str))
255 }
256}
257
258impl FromRequest for Body<Vec<u8>> {
259 async fn from_request(req: &mut OxiditeRequest) -> Result<Self> {
260 use http_body_util::BodyExt;
261
262 let body = req.body_mut();
263 let bytes = body.collect().await
264 .map_err(|e| Error::InternalServerError(format!("Failed to read body: {}", e)))?
265 .to_bytes();
266
267 Ok(Body(bytes.to_vec()))
268 }
269}