gloo_net/http/
response.rs1use std::{convert::From, fmt};
2
3use crate::{js_to_error, Error};
4use js_sys::{ArrayBuffer, Uint8Array};
5use wasm_bindgen::{JsCast, JsValue};
6use wasm_bindgen_futures::JsFuture;
7use web_sys::ResponseInit;
8
9use crate::http::Headers;
10#[cfg(feature = "json")]
11#[cfg_attr(docsrs, doc(cfg(feature = "json")))]
12use serde::de::DeserializeOwned;
13
14pub struct Response(web_sys::Response);
16
17impl Response {
18 pub fn builder() -> ResponseBuilder {
20 ResponseBuilder::new()
21 }
22 pub fn type_(&self) -> web_sys::ResponseType {
37 self.0.type_()
38 }
39
40 pub fn url(&self) -> String {
44 self.0.url()
45 }
46
47 pub fn redirected(&self) -> bool {
49 self.0.redirected()
50 }
51
52 pub fn status(&self) -> u16 {
55 self.0.status()
56 }
57
58 pub fn ok(&self) -> bool {
61 self.0.ok()
62 }
63
64 pub fn status_text(&self) -> String {
71 self.0.status_text()
72 }
73
74 pub fn headers(&self) -> Headers {
76 Headers::from_raw(self.0.headers())
77 }
78
79 pub fn body_used(&self) -> bool {
83 self.0.body_used()
84 }
85
86 pub fn body(&self) -> Option<web_sys::ReadableStream> {
88 self.0.body()
89 }
90
91 pub async fn form_data(&self) -> Result<web_sys::FormData, Error> {
93 let promise = self.0.form_data().map_err(js_to_error)?;
94 let val = JsFuture::from(promise).await.map_err(js_to_error)?;
95 Ok(web_sys::FormData::from(val))
96 }
97
98 #[cfg(feature = "json")]
100 #[cfg_attr(docsrs, doc(cfg(feature = "json")))]
101 pub async fn json<T: DeserializeOwned>(&self) -> Result<T, Error> {
102 serde_json::from_str::<T>(&self.text().await?).map_err(Error::from)
103 }
104
105 pub async fn text(&self) -> Result<String, Error> {
107 let promise = self.0.text().unwrap();
108 let val = JsFuture::from(promise).await.map_err(js_to_error)?;
109 let string = js_sys::JsString::from(val);
110 Ok(String::from(&string))
111 }
112
113 pub async fn binary(&self) -> Result<Vec<u8>, Error> {
118 let promise = self.0.array_buffer().map_err(js_to_error)?;
119 let array_buffer: ArrayBuffer = JsFuture::from(promise)
120 .await
121 .map_err(js_to_error)?
122 .unchecked_into();
123 let typed_buff: Uint8Array = Uint8Array::new(&array_buffer);
124 let mut body = vec![0; typed_buff.length() as usize];
125 typed_buff.copy_to(&mut body);
126 Ok(body)
127 }
128}
129
130impl From<web_sys::Response> for Response {
131 fn from(raw: web_sys::Response) -> Self {
132 Self(raw)
133 }
134}
135
136impl From<Response> for web_sys::Response {
137 fn from(res: Response) -> Self {
138 res.0
139 }
140}
141
142impl fmt::Debug for Response {
143 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
144 f.debug_struct("Response")
145 .field("url", &self.url())
146 .field("redirected", &self.redirected())
147 .field("status", &self.status())
148 .field("headers", &self.headers())
149 .field("body_used", &self.body_used())
150 .finish_non_exhaustive()
151 }
152}
153
154pub struct ResponseBuilder {
157 headers: Headers,
158 options: web_sys::ResponseInit,
159}
160
161impl ResponseBuilder {
162 pub fn new() -> Self {
165 Self::default()
166 }
167
168 pub fn headers(mut self, headers: Headers) -> Self {
170 self.headers = headers;
171 self
172 }
173
174 pub fn header(self, key: &str, value: &str) -> Self {
176 self.headers.set(key, value);
177 self
178 }
179
180 pub fn status(mut self, status: u16) -> Self {
182 self.options.status(status);
183 self
184 }
185
186 pub fn status_text(mut self, status_text: &str) -> Self {
188 self.options.status_text(status_text);
189 self
190 }
191
192 #[cfg(feature = "json")]
198 #[cfg_attr(docsrs, doc(cfg(feature = "json")))]
199 pub fn json<T: serde::Serialize + ?Sized>(self, value: &T) -> Result<Response, Error> {
200 let json = serde_json::to_string(value)?;
201 self.header("Content-Type", "application/json")
202 .body(Some(json.as_str()))
203 }
204
205 pub fn body<T>(mut self, data: T) -> Result<Response, Error>
207 where
208 T: IntoRawResponse,
209 {
210 self.options.headers(&self.headers.into_raw());
211 let init = self.options;
212
213 data.into_raw(init).map(Response).map_err(js_to_error)
214 }
215}
216
217impl IntoRawResponse for Option<&web_sys::Blob> {
218 fn into_raw(self, init: ResponseInit) -> Result<web_sys::Response, JsValue> {
219 web_sys::Response::new_with_opt_blob_and_init(self, &init)
220 }
221}
222
223impl IntoRawResponse for Option<&js_sys::Object> {
224 fn into_raw(self, init: ResponseInit) -> Result<web_sys::Response, JsValue> {
225 web_sys::Response::new_with_opt_buffer_source_and_init(self, &init)
226 }
227}
228
229impl IntoRawResponse for Option<&mut [u8]> {
230 fn into_raw(self, init: ResponseInit) -> Result<web_sys::Response, JsValue> {
231 web_sys::Response::new_with_opt_u8_array_and_init(self, &init)
232 }
233}
234
235impl IntoRawResponse for Option<&web_sys::FormData> {
236 fn into_raw(self, init: ResponseInit) -> Result<web_sys::Response, JsValue> {
237 web_sys::Response::new_with_opt_form_data_and_init(self, &init)
238 }
239}
240
241impl IntoRawResponse for Option<&web_sys::UrlSearchParams> {
242 fn into_raw(self, init: ResponseInit) -> Result<web_sys::Response, JsValue> {
243 web_sys::Response::new_with_opt_url_search_params_and_init(self, &init)
244 }
245}
246
247impl IntoRawResponse for Option<&str> {
248 fn into_raw(self, init: ResponseInit) -> Result<web_sys::Response, JsValue> {
249 web_sys::Response::new_with_opt_str_and_init(self, &init)
250 }
251}
252
253impl IntoRawResponse for Option<&web_sys::ReadableStream> {
254 fn into_raw(self, init: ResponseInit) -> Result<web_sys::Response, JsValue> {
255 web_sys::Response::new_with_opt_readable_stream_and_init(self, &init)
256 }
257}
258
259pub trait IntoRawResponse {
261 fn into_raw(self, init: ResponseInit) -> Result<web_sys::Response, JsValue>;
264}
265
266impl Default for ResponseBuilder {
267 fn default() -> Self {
268 Self {
269 headers: Headers::new(),
270 options: web_sys::ResponseInit::new(),
271 }
272 }
273}
274
275impl fmt::Debug for ResponseBuilder {
276 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
277 f.debug_struct("ResponseBuilder")
278 .field("headers", &self.headers)
279 .finish_non_exhaustive()
280 }
281}