micro_web/extract/
extract_body.rs

1//! Body data extraction implementations
2//!
3//! This module provides implementations for extracting typed data from request bodies.
4//! It supports extracting raw bytes, strings, JSON data and form data.
5//!
6//! # Examples
7//!
8//! ```no_run
9//! # use micro_web::extract::{Json, Form};
10//! # use serde::Deserialize;
11//!
12//! #[derive(Deserialize)]
13//! struct User {
14//!     name: String,
15//!     age: u32
16//! }
17//!
18//! // Extract JSON data
19//! async fn handle_json(Json(user): Json<User>) {
20//!     println!("Got user: {}", user.name);
21//! }
22//!
23//! // Extract form data
24//! async fn handle_form(Form(user): Form<User>) {
25//!     println!("Got user: {}", user.name);
26//! }
27//! ```
28
29use crate::RequestContext;
30use crate::body::OptionReqBody;
31use crate::extract::from_request::FromRequest;
32use crate::extract::{Form, Json};
33use bytes::Bytes;
34use http_body_util::BodyExt;
35use micro_http::protocol::ParseError;
36use serde::Deserialize;
37
38/// Extracts raw bytes from request body
39impl FromRequest for Bytes {
40    type Output<'any> = Bytes;
41    type Error = ParseError;
42
43    async fn from_request(_req: &RequestContext<'_, '_>, body: OptionReqBody) -> Result<Self::Output<'static>, Self::Error> {
44        body.apply(|b| async { b.collect().await.map(|c| c.to_bytes()) }).await
45    }
46}
47
48/// Extracts UTF-8 string from request body
49impl FromRequest for String {
50    type Output<'any> = String;
51    type Error = ParseError;
52
53    async fn from_request(req: &RequestContext<'_, '_>, body: OptionReqBody) -> Result<Self::Output<'static>, Self::Error> {
54        let bytes = <Bytes as FromRequest>::from_request(req, body).await?;
55        // todo: using character to decode
56        match String::from_utf8(bytes.into()) {
57            Ok(s) => Ok(s),
58            Err(_) => Err(ParseError::invalid_body("request body is not utf8")),
59        }
60    }
61}
62
63/// Extracts form data from request body
64///
65/// This implementation expects the request body to be URL-encoded form data
66/// and deserializes it into the target type using `serde_urlencoded`.
67impl<T> FromRequest for Form<T>
68where
69    T: for<'de> Deserialize<'de> + Send,
70{
71    type Output<'r> = Form<T>;
72    type Error = ParseError;
73
74    async fn from_request<'r>(req: &'r RequestContext<'_, '_>, body: OptionReqBody) -> Result<Self::Output<'r>, Self::Error> {
75        let bytes = <Bytes as FromRequest>::from_request(req, body).await?;
76        serde_urlencoded::from_bytes::<'_, T>(&bytes).map(|t| Form(t)).map_err(|e| ParseError::invalid_body(e.to_string()))
77    }
78}
79
80/// Extracts JSON data from request body
81///
82/// This implementation expects the request body to be valid JSON
83/// and deserializes it into the target type using `serde_json`.
84impl<T> FromRequest for Json<T>
85where
86    T: for<'de> Deserialize<'de> + Send,
87{
88    type Output<'r> = Json<T>;
89    type Error = ParseError;
90
91    async fn from_request<'r>(req: &'r RequestContext<'_, '_>, body: OptionReqBody) -> Result<Self::Output<'r>, Self::Error> {
92        let bytes = <Bytes as FromRequest>::from_request(req, body).await?;
93        serde_json::from_slice::<'_, T>(&bytes).map(|t| Json(t)).map_err(|e| ParseError::invalid_body(e.to_string()))
94    }
95}