//! 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 for Builder { fn empty(self) -> http::Result> { 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(self) -> Result; /// 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(self) -> Result; } #[async_trait] impl SputnikBody for hyper::Body { async fn into_form(self) -> Result { let full_body = hyper::body::to_bytes(self).await.map_err(BodyError)?; Ok(serde_urlencoded::from_bytes::(&full_body)?) } #[cfg(feature = "hyper_body_json")] #[cfg_attr(docsrs, doc(cfg(feature = "hyper_body_json")))] async fn into_json(self) -> Result { let full_body = hyper::body::to_bytes(self).await.map_err(BodyError)?; Ok(serde_json::from_slice::(&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), }