webrune 0.1.2

A composable web server.
Documentation
use crate::Extract;
use crate::Request;
use serde::de::DeserializeOwned;
use std::fmt::{Display, Formatter};
use std::ops::Deref;

/// Extractor for query string parameters.
///
/// `Query<T>` deserializes the URL query string into a user-defined type `T`
/// using [`serde_urlencoded`].
///
/// The query string is parsed as `application/x-www-form-urlencoded` data,
/// allowing query parameters to be mapped directly onto structs.
///
/// # Example
///
/// ```ignore
/// async fn handler(request: Request, state: MyState) -> Result<Json<Payload>, MyError> {
///     let params = SearchParams::extract(&request)?;
///     ...
/// }
///
/// #[derive(Deserialize)]
/// struct SearchParams {
///     q: String,
///     page: Option<u32>,
/// }
/// ```
///
/// Given a request to:
///
/// ```text
/// /search?q=rust&page=2
/// ```
///
/// `params.q == "rust"` and `params.page == Some(2)`.
///
/// # Errors
///
/// Extraction fails if the query string cannot be deserialized into `T`.
pub struct Query<T>(pub T);

impl<T> Extract for Query<T>
where
    T: DeserializeOwned,
{
    /// Error type returned when query extraction fails.
    type Error = QueryError;

    fn extract<B>(request: &Request<B>) -> Result<Self, Self::Error> {
        let query = request.uri().query().unwrap_or_default();

        Ok(Query(
            serde_urlencoded::from_str(query).map_err(|e| QueryError(e.to_string()))?,
        ))
    }
}

impl<T> Deref for Query<T> {
    type Target = T;

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

/// Error returned when query parameter extraction fails.
pub struct QueryError(pub String);

impl Display for QueryError {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        write!(f, "{}", self.0)
    }
}