rustolio_utils/http/request/
mod.rs1mod builder;
12
13#[cfg(not(target_arch = "wasm32"))]
14use bytes::Bytes;
15#[cfg(target_arch = "wasm32")]
16use js_sys::JsString;
17#[cfg(target_arch = "wasm32")]
18use wasm_bindgen::JsCast as _;
19#[cfg(target_arch = "wasm32")]
20use wasm_bindgen::JsValue;
21#[cfg(target_arch = "wasm32")]
22use web_sys::RequestInit;
23
24use crate::bytes::IntoUtf8Bytes;
25#[cfg(not(target_arch = "wasm32"))]
26use crate::threadsafe;
27
28use super::{
29 Error, HeaderName, HeaderValue, Incoming, Method, Outgoing, Response, Result, Uri, Version,
30};
31
32pub use builder::Builder;
33
34pub struct Request<B>(
36 #[cfg(not(target_arch = "wasm32"))] http::Request<B>,
37 #[cfg(target_arch = "wasm32")] std::marker::PhantomData<B>,
38);
39
40impl Request<()> {
41 #[inline]
43 pub fn get(uri: impl IntoUtf8Bytes) -> Builder<Outgoing> {
44 Builder::<Outgoing>::new(Method::GET, uri.into_utf8_bytes())
45 }
46
47 #[inline]
49 pub fn post(uri: impl IntoUtf8Bytes) -> Builder<()> {
50 Builder::<()>::new(Method::POST, uri.into_utf8_bytes())
51 }
52
53 #[inline]
55 pub fn patch(uri: impl IntoUtf8Bytes) -> Builder<()> {
56 Builder::<()>::new(Method::PATCH, uri.into_utf8_bytes())
57 }
58
59 #[inline]
61 pub fn put(uri: impl IntoUtf8Bytes) -> Builder<()> {
62 Builder::<()>::new(Method::PUT, uri.into_utf8_bytes())
63 }
64
65 #[inline]
67 pub fn delete(uri: impl IntoUtf8Bytes) -> Builder<()> {
68 Builder::<()>::new(Method::DELETE, uri.into_utf8_bytes())
69 }
70}
71
72impl<B> Request<B> {
73 #[cfg(not(target_arch = "wasm32"))]
74 pub fn method(&self) -> &Method {
75 self.0.method()
76 }
77
78 #[cfg(not(target_arch = "wasm32"))]
79 pub fn header(&self, key: impl IntoUtf8Bytes) -> Option<&HeaderValue> {
80 let key = key.into();
81 let key: http::HeaderName = key.to_vec().try_into().ok()?;
82 self.0.headers().get(&key)
83 }
84
85 #[cfg(not(target_arch = "wasm32"))]
86 pub fn uri(&self) -> &Uri {
87 self.0.uri()
88 }
89
90 #[cfg(not(target_arch = "wasm32"))]
91 pub fn body(&self) -> &B {
92 self.0.body()
93 }
94
95 #[cfg(not(target_arch = "wasm32"))]
96 pub fn into_body(self) -> B {
97 self.0.into_body()
98 }
99}
100
101impl Request<Incoming> {
102 #[cfg(not(target_arch = "wasm32"))]
103 pub fn from_inner(req: http::Request<Incoming>) -> Self {
104 Self(req)
105 }
106}
107
108#[cfg(not(target_arch = "wasm32"))]
109impl<B> Request<B>
110where
111 B: hyper::body::Body<Error: threadsafe::Error>,
112{
113 pub async fn text(self) -> Result<Request<String>> {
114 use http_body_util::BodyExt;
115
116 let (parts, body) = self.0.into_parts();
117
118 let body = body.collect().await.map_err(Error::body)?;
119 let Ok(text) = String::from_utf8(body.to_bytes().to_vec()) else {
120 return Err(Error::InvalidType);
121 };
122
123 Ok(Request(http::Request::from_parts(parts, text)))
124 }
125
126 pub async fn json<T: serde::de::DeserializeOwned>(self) -> Result<Request<T>> {
127 use http_body_util::BodyExt;
128
129 let Some(ty) = self.header(HeaderName::CONTENT_TYPE) else {
130 return Err(Error::InvalidType);
131 };
132 if !ty
133 .to_str()
134 .map_err(|_| Error::InvalidType)?
135 .starts_with("application/json")
136 {
137 return Err(Error::InvalidType);
138 }
139
140 let (parts, body) = self.0.into_parts();
141
142 let body = body.collect().await.map_err(Error::body)?;
143 let Ok(json) = serde_json::from_slice(&body.to_bytes()) else {
144 return Err(Error::InvalidType);
145 };
146
147 Ok(Request(http::Request::from_parts(parts, json)))
148 }
149
150 pub async fn encoded<T: crate::prelude::Decode>(self) -> Result<Request<T>> {
152 self.bytes().await.and_then(|b| {
153 let (parts, body) = b.0.into_parts();
154
155 let decoded: T =
156 crate::bytes::encoding::decode_from_bytes(body).map_err(Error::body)?;
157
158 Ok(Request(http::Request::from_parts(parts, decoded)))
159 })
160 }
161
162 pub async fn bytes(self) -> Result<Request<Bytes>> {
163 use http_body_util::BodyExt;
164
165 let (parts, body) = self.0.into_parts();
166
167 let body = body.collect().await.map_err(Error::body)?;
168 let bytes = body.to_bytes();
169
170 Ok(Request(http::Request::from_parts(parts, bytes)))
171 }
172}