//! Extends `hyper::Body` with [`SputnikBody`]. use hyper::http::{self, response::Builder}; use async_trait::async_trait; use serde::de::DeserializeOwned; use crate::response::EmptyBuilder; impl EmptyBuilder<hyper::Body> for Builder { fn empty(self) -> http::Result<http::response::Response<hyper::Body>> { self.body(hyper::Body::empty()) } } /// Adds deserialization methods to [`hyper::Body`]. #[async_trait] pub trait SputnikBody { /// Parses a `application/x-www-form-urlencoded` request body into a given struct. async fn into_form<T: DeserializeOwned>(self) -> Result<T, FormError>; /// Attempts to deserialize the request body as JSON. #[cfg(feature = "hyper_body_json")] #[cfg_attr(docsrs, doc(cfg(feature = "hyper_body_json")))] async fn into_json<T: DeserializeOwned>(self) -> Result<T, JsonError>; } #[async_trait] impl SputnikBody for hyper::Body { async fn into_form<T: DeserializeOwned>(self) -> Result<T, FormError> { let full_body = hyper::body::to_bytes(self).await.map_err(BodyError)?; Ok(serde_urlencoded::from_bytes::<T>(&full_body)?) } #[cfg(feature = "hyper_body_json")] #[cfg_attr(docsrs, doc(cfg(feature = "hyper_body_json")))] async fn into_json<T: DeserializeOwned>(self) -> Result<T, JsonError> { let full_body = hyper::body::to_bytes(self).await.map_err(BodyError)?; Ok(serde_json::from_slice::<T>(&full_body)?) } } #[derive(thiserror::Error, Debug)] #[error("failed to read body")] pub struct BodyError(pub hyper::Error); #[derive(thiserror::Error, Debug)] pub enum FormError { #[error("{0}")] Body(#[from] BodyError), #[error("form deserialize error: {0}")] Deserialize(#[from] serde_urlencoded::de::Error), } #[cfg(feature = "hyper_body_json")] #[cfg_attr(docsrs, doc(cfg(feature = "hyper_body_json")))] #[derive(thiserror::Error, Debug)] pub enum JsonError { #[error("{0}")] Body(#[from] BodyError), #[error("json deserialize error: {0}")] Deserialize(#[from] serde_json::Error), }