1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111
//! Fetch API. //! //! Seed Fetch API is very similar to the browser [native one][fetch-mdn]. //! //! There is one entry point: [`fetch`][fetch] function. //! It can accept both string urls as well as [`Request`][request]. //! //! To get a [`Response`][response] you need to `.await` fetch: //! ```rust //! let response = fetch("/foo").await?; //! ``` //! //! Then you can check [`Status`][status] and extract body in various formats: //! ```rust //! let response = fetch("/foo").await?.check_status()?; //! let body: FooStruct = response.json().await?; //! ``` //! //! Use [`Request`][request] methods to set init options: //! ```rust //! fetch(Request::new(url).method(Method::Post)).await //! ``` //! //! //! [fetch]: ./fn.fetch.html //! [request]: ./struct.Request.html //! [response]: ./struct.Response.html //! [status]: ./struct.Status.html //! [fetch-mdn]: https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API use crate::util::window; use std::convert::TryInto; use wasm_bindgen_futures::JsFuture; pub mod header; mod method; mod request; mod response; mod status; pub use header::{Header, Headers}; pub use method::*; pub use request::*; pub use response::*; pub use status::*; /// Convenient type alias. pub type Result<T> = std::result::Result<T, FetchError>; /// The main Fetch API function. /// It fires a HTTP request. /// /// ## Examples /// /// Simple `GET` request: /// ```rust /// let response = fetch("https://seed-rs.org").await?; /// let body = response.text().await?; /// ``` /// /// `POST` request with `JSON` body: /// ```rust /// let form = Form{email: "foo@example.com"}; /// let response = fetch(Request::new("/api").method(Method::Post).json(form)).await?; /// let data: SubmitResponse = response.json().await?; /// ``` /// /// ## Errors /// /// `fetch` will return `Err` only on network errors. This means that /// even if you get `Ok` from this function, you still need to check /// `Response` status for HTTP errors. pub async fn fetch<'a>(request: impl Into<Request<'a>>) -> Result<Response> { let request = request.into(); let promise = window().fetch_with_request(&request.try_into()?); let raw_response = JsFuture::from(promise) .await .map(Into::into) .map_err(FetchError::NetworkError)?; Ok(Response { raw_response }) } #[allow(clippy::module_name_repetitions)] #[derive(Debug)] pub enum FetchError { SerdeError(serde_json::Error), DomException(web_sys::DomException), PromiseError(wasm_bindgen::JsValue), NetworkError(wasm_bindgen::JsValue), /// Request construction failed. RequestError(wasm_bindgen::JsValue), StatusError(Status), } #[cfg(test)] mod tests { use wasm_bindgen_test::*; wasm_bindgen_test_configure!(run_in_browser); use super::*; use crate::browser::Url; #[wasm_bindgen_test] fn test_fetch_args() { let _ = fetch("https://seed-rs.org"); let _ = fetch(String::from("https://seed-rs.org")); let _ = fetch(Url::new().set_path(&["/", "foo"])); let _ = fetch(Request::new("https://seed-rs.org")); } }