use super::{FetchError, Headers, Result, Status};
#[cfg(any(feature = "serde-json", feature = "serde-wasm-bindgen"))]
use crate::browser::json;
#[cfg(any(feature = "serde-json", feature = "serde-wasm-bindgen"))]
use serde::de::DeserializeOwned;
#[cfg(any(feature = "serde-json", feature = "serde-wasm-bindgen"))]
use wasm_bindgen::JsValue;
use wasm_bindgen_futures::JsFuture;
#[derive(Debug)]
pub struct Response {
pub(crate) raw_response: web_sys::Response,
}
impl Response {
pub async fn text(&self) -> Result<String> {
Ok(self
.raw_response
.text()
.map_err(FetchError::PromiseError)
.map(JsFuture::from)?
.await
.map_err(FetchError::PromiseError)?
.as_string()
.expect("fetch: Response expected `String` after .text()"))
}
#[cfg(any(feature = "serde-json", feature = "serde-wasm-bindgen"))]
pub async fn json<T: DeserializeOwned + 'static>(&self) -> Result<T> {
let js: JsValue = self
.raw_response
.json()
.map_err(FetchError::PromiseError)
.map(JsFuture::from)?
.await
.map_err(FetchError::PromiseError)?;
Ok(json::from_js_value(&js)?)
}
pub async fn bytes(&self) -> Result<Vec<u8>> {
Ok(self
.raw_response
.array_buffer()
.map_err(FetchError::PromiseError)
.map(JsFuture::from)?
.await
.map_err(FetchError::PromiseError)
.map(|array_buffer| js_sys::Uint8Array::new(&array_buffer))?
.to_vec())
}
pub async fn blob(&self) -> Result<web_sys::Blob> {
self.raw_response
.blob()
.map_err(FetchError::PromiseError)
.map(JsFuture::from)?
.await
.map_err(FetchError::PromiseError)
.map(web_sys::Blob::from)
}
pub fn status(&self) -> Status {
Status::from(&self.raw_response)
}
pub fn check_status(self) -> Result<Self> {
let status = self.status();
if status.is_ok() {
Ok(self)
} else {
Err(FetchError::StatusError(status))
}
}
pub async fn check_detailed_status(
self,
) -> std::result::Result<Self, (FetchError, Option<String>)> {
let status = self.status();
if status.is_ok() {
Ok(self)
} else {
Err((FetchError::StatusError(status), self.text().await.ok()))
}
}
pub const fn raw_response(&self) -> &web_sys::Response {
&self.raw_response
}
pub fn headers(&self) -> Headers {
Headers::from(&self.raw_response.headers())
}
}
#[cfg(test)]
mod tests {
use wasm_bindgen_test::*;
wasm_bindgen_test_configure!(run_in_browser);
use super::*;
use serde::Deserialize;
#[derive(Deserialize)]
struct Obj {
key: String,
}
#[wasm_bindgen_test]
async fn response_json() {
let response = Response {
raw_response: web_sys::Response::new_with_opt_str(Some(r#"{ "key": "value" }"#))
.unwrap(),
};
let obj: Obj = response.json().await.unwrap();
assert_eq!(obj.key, "value");
}
#[wasm_bindgen_test]
async fn response_string() {
let response = Response {
raw_response: web_sys::Response::new_with_opt_str(Some("response")).unwrap(),
};
let string = response.text().await.unwrap();
assert_eq!(string, "response");
}
#[wasm_bindgen_test]
async fn response_bytes() {
let mut body = Vec::from(&b"response"[..]);
let response = Response {
raw_response: web_sys::Response::new_with_opt_u8_array(Some(&mut body)).unwrap(),
};
let vec = response.bytes().await.unwrap();
assert_eq!(&vec, b"response");
}
#[wasm_bindgen_test]
async fn response_blob() {
let mut body = Vec::from(&b"response"[..]);
let response = Response {
raw_response: web_sys::Response::new_with_opt_u8_array(Some(&mut body)).unwrap(),
};
let promise = response.blob().await.unwrap().text();
let text = JsFuture::from(promise).await.unwrap();
assert_eq!(&text, "response");
}
}