webrune 0.1.2

A composable web server.
Documentation
use std::ops::{Deref, DerefMut};

use hyper::body::Incoming;
use serde::de::DeserializeOwned;

use crate::{
    Extract,
    extract::{Path, PathError, Query, QueryError},
};

/// A wrapper around [`http::Request`] with extraction helpers.
///
/// `Request` provides ergonomic access to the underlying HTTP request
/// while adding convenience methods for extracting structured data.
///
/// It dereferences to `http::Request`, so it can be used anywhere an
/// HTTP request is expected.
///
/// # Extraction
///
/// `Request` supports both synchronous and asynchronous extraction:
///
/// - Synchronous extraction via [`Extract`] (e.g. path or query parameters)
/// - Asynchronous extraction via [`FromRequest`] (e.g. request bodies)
///
/// Note: [`FromRequest`] takes ownership of the request.
///
/// # Example
///
/// ```ignore
/// async fn handler(request: Request, _: ()) {
///     let path: UserPath = request.path()?;
///     let query: SearchQuery = request.query()?;
///     let body: CreateUser = request.body().await?;
/// }
/// ```
pub struct Request<B = Incoming>(http::Request<B>);

impl<B> Request<B> {
    /// Extracts a value from the request using the [`Extract`] trait.
    ///
    /// This is the most general synchronous extraction API.
    pub fn extract<E>(&self) -> Result<E, E::Error>
    where
        E: Extract,
    {
        E::extract(self)
    }

    /// Extracts and deserializes path parameters into `T`.
    ///
    /// This is a convenience wrapper around [`Path`].
    pub fn path<T>(&self) -> Result<T, PathError>
    where
        T: DeserializeOwned,
    {
        let Path(path) = Path::extract(self)?;
        Ok(path)
    }

    /// Extracts and deserializes query parameters into `T`.
    ///
    /// This is a convenience wrapper around [`Query`].
    pub fn query<T>(&self) -> Result<T, QueryError>
    where
        T: DeserializeOwned,
    {
        let Query(query) = Query::extract(self)?;
        Ok(query)
    }

    /// Consumes the request and asynchronously extracts a value from it.
    ///
    /// This is typically used for body extraction, where the request body
    /// must be read and decoded.
    pub async fn body<T>(self) -> Result<T::Output, T::Error>
    where
        T: FromRequest<B>,
    {
        T::from_request(self).await
    }

    /// Returns the inner [`http::Request`].
    pub fn into_inner(self) -> http::Request<B> {
        self.0
    }
}

impl<B> From<http::Request<B>> for Request<B> {
    fn from(value: http::Request<B>) -> Self {
        Request(value)
    }
}

impl<B> Deref for Request<B> {
    type Target = http::Request<B>;

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

impl<B> DerefMut for Request<B> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.0
    }
}

/// Trait for asynchronous request extraction.
///
/// `FromRequest` is used for extractors that need to consume the request
/// body or perform asynchronous work.
///
/// Typical use cases include:
/// - parsing request bodies (e.g. JSON, form data),
/// - streaming payloads,
/// - ownership-sensitive transformations.
///
/// # Note
///
/// Because the request body can only be consumed once, extractors
/// implementing `FromRequest` take ownership of the [`Request`].
pub trait FromRequest<B = Incoming>: Sized {
    /// Error returned when extraction fails.
    type Error;

    /// Output returned when extraction succeeds.
    type Output;

    /// Asynchronously extracts `Self` from the request.
    async fn from_request(request: Request<B>) -> Result<Self::Output, Self::Error>;
}

/// Identity implementation of [`FromRequest`] for [`Request`].
///
/// This allows handlers to receive the full request by value.
impl<B> FromRequest<B> for Request<B> {
    type Error = ();
    type Output = Self;

    async fn from_request(request: Request<B>) -> Result<Self, Self::Error> {
        Ok(request)
    }
}