Skip to main content

Request

Struct Request 

Source
pub struct Request { /* private fields */ }
Expand description

HTTP request.

Implementations§

Source§

impl Request

Source

pub fn new(method: Method, path: impl Into<String>) -> Request

Create a new request.

Source

pub fn with_version( method: Method, path: impl Into<String>, version: HttpVersion, ) -> Request

Create a new request with an explicit HTTP version.

Source

pub fn method(&self) -> Method

Get the HTTP method.

Source

pub fn version(&self) -> HttpVersion

Get the HTTP version.

Source

pub fn set_version(&mut self, version: HttpVersion)

Set the HTTP version.

Source

pub fn path(&self) -> &str

Get the request path.

Examples found in repository?
examples/crud_api.rs (line 116)
115fn extract_user_id(req: &Request) -> Result<u64, Response> {
116    let path = req.path();
117    let segments: Vec<&str> = path.split('/').filter(|s| !s.is_empty()).collect();
118    segments
119        .get(1)
120        .and_then(|s| s.parse::<u64>().ok())
121        .ok_or_else(|| json_error(StatusCode::BAD_REQUEST, "Invalid user ID"))
122}
Source

pub fn query(&self) -> Option<&str>

Get the query string.

Source

pub fn headers(&self) -> &Headers

Get the headers.

Examples found in repository?
examples/crud_api.rs (line 97)
95fn parse_json_body<T: serde::de::DeserializeOwned>(req: &mut Request) -> Result<T, Response> {
96    let is_json = req
97        .headers()
98        .get("content-type")
99        .is_some_and(|ct| ct.starts_with(b"application/json"));
100
101    if !is_json {
102        return Err(json_error(
103            StatusCode::UNSUPPORTED_MEDIA_TYPE,
104            "Content-Type must be application/json",
105        ));
106    }
107
108    let Body::Bytes(body) = req.take_body() else {
109        return Err(json_error(StatusCode::BAD_REQUEST, "Missing request body"));
110    };
111    serde_json::from_slice(&body)
112        .map_err(|e| json_error(StatusCode::BAD_REQUEST, &format!("Invalid JSON: {e}")))
113}
More examples
Hide additional examples
examples/auth_example.rs (line 112)
106fn login_handler(_ctx: &RequestContext, req: &mut Request) -> std::future::Ready<Response> {
107    // For this demo, we only check Content-Type and return a fixed token.
108    // Real applications should parse the body and validate credentials.
109
110    // Check Content-Type
111    let is_json = req
112        .headers()
113        .get("content-type")
114        .is_some_and(|ct| ct.starts_with(b"application/json"));
115
116    if !is_json {
117        let error = serde_json::json!({
118            "detail": "Content-Type must be application/json"
119        });
120        return std::future::ready(
121            Response::with_status(StatusCode::UNSUPPORTED_MEDIA_TYPE)
122                .header("content-type", b"application/json".to_vec())
123                .body(ResponseBody::Bytes(error.to_string().into_bytes())),
124        );
125    }
126
127    // For demo purposes, we don't validate credentials - just return the token
128    // In production:
129    // 1. Parse the request body as LoginRequest
130    // 2. Verify username/password against your database
131    // 3. Generate a unique, cryptographically secure token
132    // 4. Store token -> user_id mapping (with expiration)
133
134    let response = LoginResponse {
135        access_token: DEMO_BEARER_VALUE.to_string(),
136        token_type: "bearer",
137    };
138
139    std::future::ready(
140        Response::ok()
141            .header("content-type", b"application/json".to_vec())
142            .body(ResponseBody::Bytes(json_bytes(&response))),
143    )
144}
145
146/// Handler for protected endpoint - requires valid bearer token.
147///
148/// This handler manually extracts and validates the bearer token:
149/// 1. Gets the Authorization header
150/// 2. Verifies it uses the Bearer scheme
151/// 3. Validates the token against our secret using constant-time comparison
152///
153/// Returns appropriate error responses for each failure mode.
154fn protected_handler(_ctx: &RequestContext, req: &mut Request) -> std::future::Ready<Response> {
155    // Step 1: Get the Authorization header
156    let Some(auth_header) = req.headers().get("authorization") else {
157        // Missing header -> 401 Unauthorized
158        let body = serde_json::json!({
159            "detail": "Not authenticated"
160        });
161        return std::future::ready(
162            Response::with_status(StatusCode::UNAUTHORIZED)
163                .header("www-authenticate", b"Bearer".to_vec())
164                .header("content-type", b"application/json".to_vec())
165                .body(ResponseBody::Bytes(body.to_string().into_bytes())),
166        );
167    };
168
169    // Step 2: Parse the Authorization header
170    let Ok(auth_str) = std::str::from_utf8(auth_header) else {
171        // Invalid UTF-8 -> 401 Unauthorized
172        let body = serde_json::json!({
173            "detail": "Invalid authentication credentials"
174        });
175        return std::future::ready(
176            Response::with_status(StatusCode::UNAUTHORIZED)
177                .header("www-authenticate", b"Bearer".to_vec())
178                .header("content-type", b"application/json".to_vec())
179                .body(ResponseBody::Bytes(body.to_string().into_bytes())),
180        );
181    };
182
183    // Step 3: Check for "Bearer " prefix (case-insensitive for the scheme)
184    let Some(bearer_value) = auth_str
185        .strip_prefix("Bearer ")
186        .or_else(|| auth_str.strip_prefix("bearer "))
187    else {
188        // Wrong scheme -> 401 Unauthorized
189        let body = serde_json::json!({
190            "detail": "Invalid authentication credentials"
191        });
192        return std::future::ready(
193            Response::with_status(StatusCode::UNAUTHORIZED)
194                .header("www-authenticate", b"Bearer".to_vec())
195                .header("content-type", b"application/json".to_vec())
196                .body(ResponseBody::Bytes(body.to_string().into_bytes())),
197        );
198    };
199
200    let bearer_value = bearer_value.trim();
201    if bearer_value.is_empty() {
202        // Empty token -> 401 Unauthorized
203        let body = serde_json::json!({
204            "detail": "Invalid authentication credentials"
205        });
206        return std::future::ready(
207            Response::with_status(StatusCode::UNAUTHORIZED)
208                .header("www-authenticate", b"Bearer".to_vec())
209                .header("content-type", b"application/json".to_vec())
210                .body(ResponseBody::Bytes(body.to_string().into_bytes())),
211        );
212    }
213
214    // Step 4: Validate the bearer value using constant-time comparison
215    if !bearer_value.secure_eq(DEMO_BEARER_VALUE) {
216        // Invalid token -> 403 Forbidden
217        let body = serde_json::json!({
218            "detail": "Invalid token"
219        });
220        return std::future::ready(
221            Response::with_status(StatusCode::FORBIDDEN)
222                .header("content-type", b"application/json".to_vec())
223                .body(ResponseBody::Bytes(body.to_string().into_bytes())),
224        );
225    }
226
227    // Token is valid - return protected data
228    let user_info = UserInfo {
229        username: "demo_user".to_string(),
230        message: "You have accessed a protected resource!".to_string(),
231    };
232
233    std::future::ready(
234        Response::ok()
235            .header("content-type", b"application/json".to_vec())
236            .body(ResponseBody::Bytes(json_bytes(&user_info))),
237    )
238}
Source

pub fn headers_mut(&mut self) -> &mut Headers

Get mutable headers.

Source

pub fn body(&self) -> &Body

Get the body.

Source

pub fn take_body(&mut self) -> Body

Take the body, replacing with Empty.

Examples found in repository?
examples/crud_api.rs (line 108)
95fn parse_json_body<T: serde::de::DeserializeOwned>(req: &mut Request) -> Result<T, Response> {
96    let is_json = req
97        .headers()
98        .get("content-type")
99        .is_some_and(|ct| ct.starts_with(b"application/json"));
100
101    if !is_json {
102        return Err(json_error(
103            StatusCode::UNSUPPORTED_MEDIA_TYPE,
104            "Content-Type must be application/json",
105        ));
106    }
107
108    let Body::Bytes(body) = req.take_body() else {
109        return Err(json_error(StatusCode::BAD_REQUEST, "Missing request body"));
110    };
111    serde_json::from_slice(&body)
112        .map_err(|e| json_error(StatusCode::BAD_REQUEST, &format!("Invalid JSON: {e}")))
113}
Source

pub fn set_body(&mut self, body: Body)

Set the body.

Source

pub fn set_query(&mut self, query: Option<String>)

Set the query string.

Source

pub fn insert_extension<T>(&mut self, value: T)
where T: Any + Send + Sync,

Insert a typed extension value.

Source

pub fn get_extension<T>(&self) -> Option<&T>
where T: Any + Send + Sync,

Get a typed extension value.

Source

pub fn get_extension_mut<T>(&mut self) -> Option<&mut T>
where T: Any + Send + Sync,

Get a mutable typed extension value.

Source

pub fn take_extension<T>(&mut self) -> Option<T>
where T: Any + Send + Sync,

Remove and return a typed extension value.

Source

pub fn background_tasks(&mut self) -> &BackgroundTasks

Access (and lazily create) the request-scoped background tasks container.

Trait Implementations§

Source§

impl Debug for Request

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error>

Formats the value using the given formatter. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, _span: NoopSpan) -> Self

Instruments this future with a span (no-op when disabled).
Source§

fn in_current_span(self) -> Self

Instruments this future with the current span (no-op when disabled).
Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

impl<T> ResponseProduces<T> for T