rama_http_types/
body_ext.rs

1use crate::dep::http_body_util::BodyExt;
2use rama_error::{BoxError, ErrorContext, OpaqueError};
3
4/// An extension trait for [`Body`] that provides methods to extract data from it.
5///
6/// [`Body`]: crate::Body
7pub trait BodyExtractExt: private::Sealed {
8    /// Try to deserialize the (contained) body as a JSON object.
9    fn try_into_json<T: serde::de::DeserializeOwned + Send + 'static>(
10        self,
11    ) -> impl Future<Output = Result<T, OpaqueError>> + Send;
12
13    /// Try to turn the (contained) body in an utf-8 string.
14    fn try_into_string(self) -> impl Future<Output = Result<String, OpaqueError>> + Send;
15}
16
17impl<Body> BodyExtractExt for crate::Response<Body>
18where
19    Body: crate::dep::http_body::Body<Data: Send + 'static, Error: Into<BoxError>> + Send + 'static,
20{
21    async fn try_into_json<T: serde::de::DeserializeOwned + Send + 'static>(
22        self,
23    ) -> Result<T, OpaqueError> {
24        let body = self
25            .into_body()
26            .collect()
27            .await
28            .map_err(|err| OpaqueError::from_boxed(err.into()))?;
29        serde_json::from_slice(body.to_bytes().as_ref())
30            .context("deserialize response body as JSON")
31    }
32
33    async fn try_into_string(self) -> Result<String, OpaqueError> {
34        let body = self
35            .into_body()
36            .collect()
37            .await
38            .map_err(|err| OpaqueError::from_boxed(err.into()))?;
39        let bytes = body.to_bytes();
40        String::from_utf8(bytes.to_vec()).context("parse body as utf-8 string")
41    }
42}
43
44impl<Body> BodyExtractExt for crate::Request<Body>
45where
46    Body: crate::dep::http_body::Body<Data: Send + 'static, Error: Into<BoxError>> + Send + 'static,
47{
48    async fn try_into_json<T: serde::de::DeserializeOwned + Send + 'static>(
49        self,
50    ) -> Result<T, OpaqueError> {
51        let body = self
52            .into_body()
53            .collect()
54            .await
55            .map_err(|err| OpaqueError::from_boxed(err.into()))?;
56        serde_json::from_slice(body.to_bytes().as_ref()).context("deserialize request body as JSON")
57    }
58
59    async fn try_into_string(self) -> Result<String, OpaqueError> {
60        let body = self
61            .into_body()
62            .collect()
63            .await
64            .map_err(|err| OpaqueError::from_boxed(err.into()))?;
65        let bytes = body.to_bytes();
66        String::from_utf8(bytes.to_vec()).context("parse request body as utf-8 string")
67    }
68}
69
70impl<B: Into<crate::Body> + Send + 'static> BodyExtractExt for B {
71    async fn try_into_json<T: serde::de::DeserializeOwned + Send + 'static>(
72        self,
73    ) -> Result<T, OpaqueError> {
74        let body = self.into().collect().await.context("collect body")?;
75        serde_json::from_slice(body.to_bytes().as_ref()).context("deserialize body as JSON")
76    }
77
78    async fn try_into_string(self) -> Result<String, OpaqueError> {
79        let body = self.into().collect().await.context("collect body")?;
80        let bytes = body.to_bytes();
81        String::from_utf8(bytes.to_vec()).context("parse body as utf-8 string")
82    }
83}
84
85mod private {
86    pub trait Sealed {}
87
88    impl<Body> Sealed for crate::Response<Body> {}
89    impl<Body> Sealed for crate::Request<Body> {}
90    impl<B: Into<crate::Body> + Send + 'static> Sealed for B {}
91}