mirror of
https://github.com/tokio-rs/axum.git
synced 2026-08-20 00:00:11 +02:00
Break up extract.rs (#103)
This breaks up `extract.rs` into several smaller submodules. The public API remains the same. This is done in prep for adding more tests to extractors which would get messy if they were all in the same file.
This commit is contained in:
@@ -0,0 +1,67 @@
|
||||
use super::{rejection::*, FromRequest, RequestParts};
|
||||
use async_trait::async_trait;
|
||||
use serde::de::DeserializeOwned;
|
||||
use std::ops::Deref;
|
||||
|
||||
/// Extractor that deserializes query strings into some type.
|
||||
///
|
||||
/// `T` is expected to implement [`serde::Deserialize`].
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust,no_run
|
||||
/// use axum::prelude::*;
|
||||
/// use serde::Deserialize;
|
||||
///
|
||||
/// #[derive(Deserialize)]
|
||||
/// struct Pagination {
|
||||
/// page: usize,
|
||||
/// per_page: usize,
|
||||
/// }
|
||||
///
|
||||
/// // This will parse query strings like `?page=2&per_page=30` into `Pagination`
|
||||
/// // structs.
|
||||
/// async fn list_things(pagination: extract::Query<Pagination>) {
|
||||
/// let pagination: Pagination = pagination.0;
|
||||
///
|
||||
/// // ...
|
||||
/// }
|
||||
///
|
||||
/// let app = route("/list_things", get(list_things));
|
||||
/// # async {
|
||||
/// # hyper::Server::bind(&"".parse().unwrap()).serve(app.into_make_service()).await.unwrap();
|
||||
/// # };
|
||||
/// ```
|
||||
///
|
||||
/// If the query string cannot be parsed it will reject the request with a `400
|
||||
/// Bad Request` response.
|
||||
#[derive(Debug, Clone, Copy, Default)]
|
||||
pub struct Query<T>(pub T);
|
||||
|
||||
#[async_trait]
|
||||
impl<T, B> FromRequest<B> for Query<T>
|
||||
where
|
||||
T: DeserializeOwned,
|
||||
B: Send,
|
||||
{
|
||||
type Rejection = QueryRejection;
|
||||
|
||||
async fn from_request(req: &mut RequestParts<B>) -> Result<Self, Self::Rejection> {
|
||||
let query = req
|
||||
.uri()
|
||||
.ok_or(UriAlreadyExtracted)?
|
||||
.query()
|
||||
.ok_or(QueryStringMissing)?;
|
||||
let value = serde_urlencoded::from_str(query)
|
||||
.map_err(FailedToDeserializeQueryString::new::<T, _>)?;
|
||||
Ok(Query(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Deref for Query<T> {
|
||||
type Target = T;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user