Skip to content

Typed Extractors

FromRequest trait

FromRequest is defined in src/extract/mod.rs:

pub trait FromRequest: Sized {
fn from_request(request: &Request) -> Result<Self, Response>;
}

Call T::from_request(request) to extract a typed value from the incoming request. On failure the implementation returns a ready-to-send Response (usually 400 Bad Request) so handlers can early-return without duplicating error-building code.

Built-in extractors

Body — raw bytes

Clones the raw request body into a Vec<u8>. Never fails; an empty body produces an empty Vec.

use rust_web_server::extract::{Body, FromRequest};
fn handler(request: &Request) -> Response {
let Body(bytes) = Body::from_request(request).unwrap();
// bytes is Vec<u8>
todo!()
}

Body also exposes .into_bytes(self) -> Vec<u8> for consuming the wrapper.

BodyText — UTF-8 decoded body

Returns 400 Bad Request if the body bytes are not valid UTF-8.

use rust_web_server::extract::{BodyText, FromRequest};
use rust_web_server::error::{AppError, IntoResponse};
fn handler(request: &Request) -> Response {
let text = match BodyText::from_request(request) {
Ok(BodyText(s)) => s,
Err(err_response) => return err_response,
};
// text is String
todo!()
}

BodyText exposes .as_str(&self) -> &str for borrowing.

Query — parsed query string

Parses the query string from request.request_uri into a HashMap<String, String>. Never fails; a URI with no query string produces an empty map.

use rust_web_server::extract::{Query, FromRequest};
fn handler(request: &Request) -> Response {
let q = Query::from_request(request).unwrap();
let page = q.get("page").map(String::as_str).unwrap_or("1");
let limit = q.get("limit").map(String::as_str).unwrap_or("20");
// ...
todo!()
}

Query exposes .get(&self, key: &str) -> Option<&String>.

RequestHeaders — all request headers

Clones the entire header list. Never fails.

use rust_web_server::extract::{RequestHeaders, FromRequest};
fn handler(request: &Request) -> Response {
let headers = RequestHeaders::from_request(request).unwrap();
let auth = headers.get("Authorization"); // case-insensitive lookup
// ...
todo!()
}

RequestHeaders::get(&self, name: &str) -> Option<&str> performs a case-insensitive lookup and returns the value of the first matching header.

Combining extractors

Extractors are ordinary function calls; combine as many as you need:

use rust_web_server::extract::{BodyText, Query, RequestHeaders, FromRequest};
fn create_item(request: &Request, _params: &PathParams, _conn: &ConnectionInfo, _state: &()) -> Response {
// Early-return on bad body
let BodyText(body) = match BodyText::from_request(request) {
Ok(b) => b,
Err(r) => return r,
};
let query = Query::from_request(request).unwrap();
let headers = RequestHeaders::from_request(request).unwrap();
let dry_run = query.get("dry_run").map(|v| v == "true").unwrap_or(false);
let trace_id = headers.get("X-Trace-Id").unwrap_or("none");
// process body, dry_run, trace_id ...
todo!()
}

Writing a custom extractor

Implement FromRequest for any type that can be derived from a Request:

use rust_web_server::extract::FromRequest;
use rust_web_server::request::Request;
use rust_web_server::response::{Response, STATUS_CODE_REASON_PHRASE};
use rust_web_server::header::Header;
use rust_web_server::range::Range;
use rust_web_server::mime_type::MimeType;
/// Extracts a Bearer token from the Authorization header.
pub struct BearerToken(pub String);
impl FromRequest for BearerToken {
fn from_request(request: &Request) -> Result<Self, Response> {
let auth = request
.get_header("Authorization".to_string())
.and_then(|h| h.value.strip_prefix("Bearer ").map(str::to_string));
match auth {
Some(token) => Ok(BearerToken(token)),
None => {
let header_list = Header::get_header_list(request);
let body = Range::get_content_range(
b"Missing or invalid Authorization header".to_vec(),
MimeType::TEXT_PLAIN.to_string(),
);
Err(Response::get_response(
STATUS_CODE_REASON_PHRASE.n401_unauthorized,
Some(header_list),
Some(vec![body]),
))
}
}
}
}
// Usage:
// let BearerToken(token) = BearerToken::from_request(request)?;