//! Types and traits for extracting data from requests. //! //! A handler function is an async function take takes any number of //! "extractors" as arguments. An extractor is a type that implements //! [`FromRequest`](crate::extract::FromRequest). //! //! For example, [`Json`] is an extractor that consumes the request body and //! deserializes it as JSON into some target type: //! //! ```rust,no_run //! use axum::prelude::*; //! use serde::Deserialize; //! //! #[derive(Deserialize)] //! struct CreateUser { //! email: String, //! password: String, //! } //! //! async fn create_user(payload: extract::Json) { //! let payload: CreateUser = payload.0; //! //! // ... //! } //! //! let app = route("/users", post(create_user)); //! # async { //! # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap(); //! # }; //! ``` //! //! # Defining custom extractors //! //! You can also define your own extractors by implementing [`FromRequest`]: //! //! ```rust,no_run //! use axum::{async_trait, extract::{FromRequest, RequestParts}, prelude::*}; //! use http::{StatusCode, header::{HeaderValue, USER_AGENT}}; //! //! struct ExtractUserAgent(HeaderValue); //! //! #[async_trait] //! impl FromRequest for ExtractUserAgent //! where //! B: Send, //! { //! type Rejection = (StatusCode, &'static str); //! //! async fn from_request(req: &mut RequestParts) -> Result { //! let user_agent = req.headers().and_then(|headers| headers.get(USER_AGENT)); //! //! if let Some(user_agent) = user_agent { //! Ok(ExtractUserAgent(user_agent.clone())) //! } else { //! Err((StatusCode::BAD_REQUEST, "`User-Agent` header is missing")) //! } //! } //! } //! //! async fn handler(user_agent: ExtractUserAgent) { //! let user_agent: HeaderValue = user_agent.0; //! //! // ... //! } //! //! let app = route("/foo", get(handler)); //! # async { //! # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap(); //! # }; //! ``` //! //! # Multiple extractors //! //! Handlers can also contain multiple extractors: //! //! ```rust,no_run //! use axum::prelude::*; //! use std::collections::HashMap; //! //! async fn handler( //! // Extract captured parameters from the URL //! params: extract::UrlParamsMap, //! // Parse query string into a `HashMap` //! query_params: extract::Query>, //! // Buffer the request body into a `Bytes` //! bytes: bytes::Bytes, //! ) { //! // ... //! } //! //! let app = route("/foo", get(handler)); //! # async { //! # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap(); //! # }; //! ``` //! //! Note that only one extractor can consume the request body. If multiple body extractors are //! applied a `500 Internal Server Error` response will be returned. //! //! # Optional extractors //! //! Wrapping extractors in `Option` will make them optional: //! //! ```rust,no_run //! use axum::{extract::Json, prelude::*}; //! use serde_json::Value; //! //! async fn create_user(payload: Option>) { //! if let Some(payload) = payload { //! // We got a valid JSON payload //! } else { //! // Payload wasn't valid JSON //! } //! } //! //! let app = route("/users", post(create_user)); //! # async { //! # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap(); //! # }; //! ``` //! //! Wrapping extractors in `Result` makes them optional and gives you the reason //! the extraction failed: //! //! ```rust,no_run //! use axum::{extract::{Json, rejection::JsonRejection}, prelude::*}; //! use serde_json::Value; //! //! async fn create_user(payload: Result, JsonRejection>) { //! match payload { //! Ok(payload) => { //! // We got a valid JSON payload //! } //! Err(JsonRejection::MissingJsonContentType(_)) => { //! // Request didn't have `Content-Type: application/json` //! // header //! } //! Err(JsonRejection::InvalidJsonBody(_)) => { //! // Couldn't deserialize the body into the target type //! } //! Err(JsonRejection::BodyAlreadyExtracted(_)) => { //! // Another extractor had already consumed the body //! } //! Err(_) => { //! // `JsonRejection` is marked `#[non_exhaustive]` so match must //! // include a catch-all case. //! } //! } //! } //! //! let app = route("/users", post(create_user)); //! # async { //! # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap(); //! # }; //! ``` //! //! # Reducing boilerplate //! //! If you're feeling adventorous you can even deconstruct the extractors //! directly on the function signature: //! //! ```rust,no_run //! use axum::{extract::Json, prelude::*}; //! use serde_json::Value; //! //! async fn create_user(Json(value): Json) { //! // `value` is of type `Value` //! } //! //! let app = route("/users", post(create_user)); //! # async { //! # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap(); //! # }; //! ``` //! //! # Request body extractors //! //! Most of the time your request body type will be [`body::Body`] (a re-export //! of [`hyper::Body`]), which is directly supported by all extractors. //! //! However if you're applying a tower middleware that changes the response you //! might have to apply a different body type to some extractors: //! //! ```rust //! use std::{ //! task::{Context, Poll}, //! pin::Pin, //! }; //! use tower_http::map_request_body::MapRequestBodyLayer; //! use axum::prelude::*; //! //! struct MyBody(B); //! //! impl http_body::Body for MyBody //! where //! B: http_body::Body + Unpin, //! { //! type Data = B::Data; //! type Error = B::Error; //! //! fn poll_data( //! mut self: Pin<&mut Self>, //! cx: &mut Context<'_>, //! ) -> Poll>> { //! Pin::new(&mut self.0).poll_data(cx) //! } //! //! fn poll_trailers( //! mut self: Pin<&mut Self>, //! cx: &mut Context<'_>, //! ) -> Poll, Self::Error>> { //! Pin::new(&mut self.0).poll_trailers(cx) //! } //! } //! //! let app = //! // `String` works directly with any body type //! route( //! "/string", //! get(|_: String| async {}) //! ) //! .route( //! "/body", //! // `extract::Body` defaults to `axum::body::Body` //! // but can be customized //! get(|_: extract::Body>| async {}) //! ) //! .route( //! "/body-stream", //! // same for `extract::BodyStream` //! get(|_: extract::BodyStream>| async {}), //! ) //! .route( //! // and `Request<_>` //! "/request", //! get(|_: Request>| async {}) //! ) //! // middleware that changes the request body type //! .layer(MapRequestBodyLayer::new(MyBody)); //! # async { //! # axum::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap(); //! # }; //! ``` //! //! [`body::Body`]: crate::body::Body use crate::response::IntoResponse; use async_trait::async_trait; use http::{header, Extensions, HeaderMap, Method, Request, Uri, Version}; use rejection::*; use std::convert::Infallible; pub mod connect_info; pub mod extractor_middleware; pub mod rejection; mod content_length_limit; mod extension; mod form; mod json; mod query; mod raw_query; mod request_parts; mod tuple; mod url_params; mod url_params_map; #[doc(inline)] pub use self::{ connect_info::ConnectInfo, content_length_limit::ContentLengthLimit, extension::Extension, extractor_middleware::extractor_middleware, form::Form, json::Json, query::Query, raw_query::RawQuery, request_parts::{Body, BodyStream}, url_params::UrlParams, url_params_map::UrlParamsMap, }; #[cfg(feature = "multipart")] #[cfg_attr(docsrs, doc(cfg(feature = "multipart")))] pub mod multipart; #[cfg(feature = "multipart")] #[cfg_attr(docsrs, doc(cfg(feature = "multipart")))] #[doc(inline)] pub use self::multipart::Multipart; #[cfg(feature = "headers")] #[cfg_attr(docsrs, doc(cfg(feature = "headers")))] mod typed_header; #[cfg(feature = "headers")] #[cfg_attr(docsrs, doc(cfg(feature = "headers")))] #[doc(inline)] pub use self::typed_header::TypedHeader; /// Types that can be created from requests. /// /// See the [module docs](crate::extract) for more details. #[async_trait] pub trait FromRequest: Sized { /// If the extractor fails it'll use this "rejection" type. A rejection is /// a kind of error that can be converted into a response. type Rejection: IntoResponse; /// Perform the extraction. async fn from_request(req: &mut RequestParts) -> Result; } /// The type used with [`FromRequest`] to extract data from requests. /// /// Has several convenience methods for getting owned parts of the request. #[derive(Debug)] pub struct RequestParts { method: Option, uri: Option, version: Option, headers: Option, extensions: Option, body: Option, } impl RequestParts { pub(crate) fn new(req: Request) -> Self { let ( http::request::Parts { method, uri, version, headers, extensions, .. }, body, ) = req.into_parts(); RequestParts { method: Some(method), uri: Some(uri), version: Some(version), headers: Some(headers), extensions: Some(extensions), body: Some(body), } } #[allow(clippy::wrong_self_convention)] pub(crate) fn into_request(&mut self) -> Request { let Self { method, uri, version, headers, extensions, body, } = self; let mut req = Request::new(body.take().expect("body already extracted")); if let Some(method) = method.take() { *req.method_mut() = method; } if let Some(uri) = uri.take() { *req.uri_mut() = uri; } if let Some(version) = version.take() { *req.version_mut() = version; } if let Some(headers) = headers.take() { *req.headers_mut() = headers; } if let Some(extensions) = extensions.take() { *req.extensions_mut() = extensions; } req } /// Gets a reference to the request method. /// /// Returns `None` if the method has been taken by another extractor. pub fn method(&self) -> Option<&Method> { self.method.as_ref() } /// Gets a mutable reference to the request method. /// /// Returns `None` if the method has been taken by another extractor. pub fn method_mut(&mut self) -> Option<&mut Method> { self.method.as_mut() } /// Takes the method out of the request, leaving a `None` in its place. pub fn take_method(&mut self) -> Option { self.method.take() } /// Gets a reference to the request URI. /// /// Returns `None` if the URI has been taken by another extractor. pub fn uri(&self) -> Option<&Uri> { self.uri.as_ref() } /// Gets a mutable reference to the request URI. /// /// Returns `None` if the URI has been taken by another extractor. pub fn uri_mut(&mut self) -> Option<&mut Uri> { self.uri.as_mut() } /// Takes the URI out of the request, leaving a `None` in its place. pub fn take_uri(&mut self) -> Option { self.uri.take() } /// Gets a reference to the request HTTP version. /// /// Returns `None` if the HTTP version has been taken by another extractor. pub fn version(&self) -> Option { self.version } /// Gets a mutable reference to the request HTTP version. /// /// Returns `None` if the HTTP version has been taken by another extractor. pub fn version_mut(&mut self) -> Option<&mut Version> { self.version.as_mut() } /// Takes the HTTP version out of the request, leaving a `None` in its place. pub fn take_version(&mut self) -> Option { self.version.take() } /// Gets a reference to the request headers. /// /// Returns `None` if the headers has been taken by another extractor. pub fn headers(&self) -> Option<&HeaderMap> { self.headers.as_ref() } /// Gets a mutable reference to the request headers. /// /// Returns `None` if the headers has been taken by another extractor. pub fn headers_mut(&mut self) -> Option<&mut HeaderMap> { self.headers.as_mut() } /// Takes the headers out of the request, leaving a `None` in its place. pub fn take_headers(&mut self) -> Option { self.headers.take() } /// Gets a reference to the request extensions. /// /// Returns `None` if the extensions has been taken by another extractor. pub fn extensions(&self) -> Option<&Extensions> { self.extensions.as_ref() } /// Gets a mutable reference to the request extensions. /// /// Returns `None` if the extensions has been taken by another extractor. pub fn extensions_mut(&mut self) -> Option<&mut Extensions> { self.extensions.as_mut() } /// Takes the extensions out of the request, leaving a `None` in its place. pub fn take_extensions(&mut self) -> Option { self.extensions.take() } /// Gets a reference to the request body. /// /// Returns `None` if the body has been taken by another extractor. pub fn body(&self) -> Option<&B> { self.body.as_ref() } /// Gets a mutable reference to the request body. /// /// Returns `None` if the body has been taken by another extractor. pub fn body_mut(&mut self) -> Option<&mut B> { self.body.as_mut() } /// Takes the body out of the request, leaving a `None` in its place. pub fn take_body(&mut self) -> Option { self.body.take() } } #[async_trait] impl FromRequest for Option where T: FromRequest, B: Send, { type Rejection = Infallible; async fn from_request(req: &mut RequestParts) -> Result, Self::Rejection> { Ok(T::from_request(req).await.ok()) } } #[async_trait] impl FromRequest for Result where T: FromRequest, B: Send, { type Rejection = Infallible; async fn from_request(req: &mut RequestParts) -> Result { Ok(T::from_request(req).await) } } fn has_content_type( req: &RequestParts, expected_content_type: &str, ) -> Result { let content_type = if let Some(content_type) = req .headers() .ok_or(HeadersAlreadyExtracted)? .get(header::CONTENT_TYPE) { content_type } else { return Ok(false); }; let content_type = if let Ok(content_type) = content_type.to_str() { content_type } else { return Ok(false); }; Ok(content_type.starts_with(expected_content_type)) } fn take_body(req: &mut RequestParts) -> Result { req.take_body().ok_or(BodyAlreadyExtracted) }