titan_core/
request.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
use crate::Respondable;
use std::convert::Infallible;
use titan_http::{Parts, Request, Response};

/// Types that can be extracted from a request.
///
/// The `FromRequest` trait is used for types that can be constructed from an HTTP request. Extractors
/// implementing this trait are responsible for parsing the incoming request body, headers, or other
/// parts of the request, and converting them into a structured type that can be used by handlers.
///
/// Since `FromRequest` extractors consume the request body, they can only be executed once for each
/// handler. If your extractor doesn't need to consume the request body (for example, when you only
/// need access to the request headers or parts of the URL), you should implement [`FromRequestParts`]
/// instead of [`FromRequest`].
///
/// # Associated Types
/// - `Error`: The type of error that can occur while extracting the request data. It must implement
///   the [`Respondable`] trait to allow the error to be returned as a valid HTTP response.
///
/// This method extracts the data from the given HTTP request and returns a result. If the extraction
/// is successful, it returns `Ok(Self)`, where `Self` is the type implementing `FromRequest`. If
/// an error occurs during extraction (e.g., due to invalid data or missing fields), it returns an
/// error of type `Self::Error`, which will be transformed into an HTTP response via the `Respondable`
/// trait.
///
/// # Example
///
/// ```
/// use titan_core::{FromRequest, Respondable};
/// use titan_http::{Request, body::Body};
///
/// // A custom extractor type that implements `FromRequest`.
/// struct MyExtractor {
///     pub field: String,
/// }
///
/// // Implement `FromRequest` for `MyExtractor`.
/// impl FromRequest for MyExtractor {
///     type Error = String; // The error type we will return if extraction fails.
///
///     fn from_request(req: Request) -> Result<Self, Self::Error> {
///         // Attempt to extract the data from the request (e.g., reading the body).
///         let field_value = req.uri().path().to_string(); // Example of extracting from the URL path.
///         Ok(MyExtractor { field: field_value })
///     }
/// }
///
/// async fn handler(data: MyExtractor) -> impl titan_core::Respondable { /* ... */}
///
/// // Now, `MyExtractor` can be used in a handler to extract data from the request.
/// ```
pub trait FromRequest: Sized {
  type Error: Respondable;
  fn from_request(req: Request) -> Result<Self, Self::Error>;
}

/// Types that can be created from request parts.
///
/// Extractors that implement `FromRequestParts` cannot consume the request body and can thus be
/// run in any order for handlers.
///
/// If your extractor needs to consume the request body then you should implement [`FromRequest`]
/// and not [`FromRequestParts`].
pub trait FromRequestParts: Sized {
  type Error: Respondable;
  fn from_request_parts(req: &mut Parts) -> Result<Self, Self::Error>;
}

impl FromRequest for String {
  type Error = ();
  fn from_request(req: Request) -> Result<Self, Self::Error> {
    let test = req.into_body();
    Ok(String::from_utf8_lossy(&test).to_string())
  }
}

impl FromRequest for Request {
  type Error = Infallible;
  fn from_request(req: Request) -> Result<Self, Self::Error> {
    Ok(req)
  }
}

impl FromRequest for () {
  type Error = Infallible;
  fn from_request(req: Request) -> Result<Self, Self::Error> {
    let _ = req;
    Ok(())
  }
}

macro_rules! impl_from_request {
    (
        [$($ty:ident),*], $last:ident
    ) => {
        #[allow(non_snake_case, unused_mut, unused_variables)]
        impl<$($ty,)* $last> FromRequestParts for ($($ty,)* $last,)
        where
            $( $ty: FromRequestParts + Send, )*
            $last: FromRequestParts + Send,
        {
            type Error = Response;

            fn from_request_parts(parts: &mut Parts) -> Result<Self, Self::Error> {
                $(
                    let $ty = $ty::from_request_parts(parts)
                        .map_err(|err| err.respond())?;
                )*
                let $last = $last::from_request_parts(parts)
                    .map_err(|err| err.respond())?;

                Ok(($($ty,)* $last,))
            }
        }

        // This impl must not be generic over M, otherwise it would conflict with the blanket
        // implementation of `FromRequest<S, Mut>` for `T: FromRequestParts<S>`.
        #[allow(non_snake_case, unused_mut, unused_variables)]
        impl<$($ty,)* $last> FromRequest for ($($ty,)* $last,)
        where
            $( $ty: FromRequestParts + Send, )*
            $last: FromRequest + Send,
        {
            type Error = Response;

            fn from_request(req: Request) -> Result<Self, Self::Error> {
                let (mut parts, body) = req.into_parts();

                $(
                    let $ty = $ty::from_request_parts(&mut parts).map_err(|err| err.respond())?;
                )*

                let req = Request::from_parts(parts, body);
                let $last = $last::from_request(req).map_err(|err| err.respond())?;

                Ok(($($ty,)* $last,))
            }
        }
    };
}

all_the_tuples!(impl_from_request);

#[cfg(feature = "deploy-lambda")]
impl FromRequest for lambda_http::http::Request<lambda_http::Body> {
  type Error = ();
  fn from_request(req: Request) -> Result<Self, Self::Error> {
    let (parts, body) = req.into_parts();

    Ok(lambda_http::http::Request::from_parts(
      parts,
      lambda_http::Body::Binary(body.to_vec()),
    ))
  }
}