/* This Source Code Form is subject to the terms of the Mozilla Public *License,v.2.0.IfacopyoftheMPLwasnotdistributedwiththis
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#[must_use = "`Request`'s \"builder\" functions take by move, not by `&mut self`"] #[derive(Clone, Debug)] pubstruct Request { pub method: Method, pub url: Url, pub headers: Headers, pub body: Option<Vec<u8>>,
}
impl Request { /// Construct a new request to the given `url` using the given `method`. /// Note that the request is not made until `send()` is called. pubfn new(method: Method, url: Url) -> Self { Self {
method,
url,
headers: Headers::new(),
body: None,
}
}
/// Alias for `Request::new(Method::Get, url)`, for convenience. pubfn get(url: Url) -> Self { Self::new(Method::Get, url)
}
/// Alias for `Request::new(Method::Patch, url)`, for convenience. pubfn patch(url: Url) -> Self { Self::new(Method::Patch, url)
}
/// Alias for `Request::new(Method::Post, url)`, for convenience. pubfn post(url: Url) -> Self { Self::new(Method::Post, url)
}
/// Alias for `Request::new(Method::Put, url)`, for convenience. pubfn put(url: Url) -> Self { Self::new(Method::Put, url)
}
/// Alias for `Request::new(Method::Delete, url)`, for convenience. pubfn delete(url: Url) -> Self { Self::new(Method::Delete, url)
}
/// Append the provided query parameters to the URL /// /// ## Example /// ``` /// # use viaduct::{Request, header_names}; /// # use url::Url; /// let some_url = url::Url::parse("https://www.example.com/xyz").unwrap(); /// /// let req = Request::post(some_url).query(&[("a", "1234"), ("b", "qwerty")]); /// assert_eq!(req.url.as_str(), "https://www.example.com/xyz?a=1234&b=qwerty"); /// /// // This appends to the query query instead of replacing `a`. /// let req = req.query(&[("a", "5678")]); /// assert_eq!(req.url.as_str(), "https://www.example.com/xyz?a=1234&b=qwerty&a=5678"); /// ``` pubfn query(mutself, pairs: &[(&str, &str)]) -> Self { letmut append_to = self.url.query_pairs_mut(); for (k, v) in pairs {
append_to.append_pair(k, v);
}
drop(append_to); self
}
/// Set the query string of the URL. Note that `req.set_query(None)` will /// clear the query. /// /// See also `Request::query` which appends a slice of query pairs, which is /// typically more ergonomic when usable. /// /// ## Example /// ``` /// # use viaduct::{Request, header_names}; /// # use url::Url; /// let some_url = url::Url::parse("https://www.example.com/xyz").unwrap(); /// /// let req = Request::post(some_url).set_query("a=b&c=d"); /// assert_eq!(req.url.as_str(), "https://www.example.com/xyz?a=b&c=d"); /// /// let req = req.set_query(None); /// assert_eq!(req.url.as_str(), "https://www.example.com/xyz"); /// ``` pubfn set_query<'a, Q: Into<Option<&'a str>>>(mutself, query: Q) -> Self { self.url.set_query(query.into()); self
}
/// Add all the provided headers to the list of headers to send with this /// request. pubfn headers<I>(mutself, to_add: I) -> Self where
I: IntoIterator<Item = Header>,
{ self.headers.extend(to_add); self
}
/// Add the provided header to the list of headers to send with this request. /// /// This returns `Err` if `val` contains characters that may not appear in /// the body of a header. /// /// ## Example /// ``` /// # use viaduct::{Request, header_names}; /// # use url::Url; /// # fn main() -> Result<(), viaduct::Error> { /// # let some_url = url::Url::parse("https://www.example.com").unwrap(); /// Request::post(some_url) /// .header(header_names::CONTENT_TYPE, "application/json")? /// .header("My-Header", "Some special value")?; /// // ... /// # Ok(()) /// # } /// ``` pubfn header<Name, Val>(mutself, name: Name, val: Val) -> Result<Self, crate::Error> where
Name: Into<HeaderName> + PartialEq<HeaderName>,
Val: Into<String> + AsRef<str>,
{ self.headers.insert(name, val)?;
Ok(self)
}
/// Set this request's body. pubfn body(mutself, body: impl Into<Vec<u8>>) -> Self { self.body = Some(body.into()); self
}
/// Set body to the result of serializing `val`, and, unless it has already /// been set, set the Content-Type header to "application/json". /// /// Note: This panics if serde_json::to_vec fails. This can only happen /// in a couple cases: /// /// 1. Trying to serialize a map with non-string keys. /// 2. We wrote a custom serializer that fails. /// /// Neither of these are things we do. If they happen, it seems better for /// this to fail hard with an easy to track down panic, than for e.g. `sync` /// to fail with a JSON parse error (which we'd probably attribute to /// corrupt data on the server, or something). pubfn json<T: ?Sized + serde::Serialize>(mutself, val: &T) -> Self { self.body =
Some(serde_json::to_vec(val).expect("Rust component bug: serde_json::to_vec failure")); self.headers
.insert_if_missing(header_names::CONTENT_TYPE, "application/json")
.unwrap(); // We know this has to be valid. self
}
}
/// A response from the server. #[derive(Clone, Debug)] pubstruct Response { /// The method used to request this response. pub request_method: Method, /// The URL of this response. pub url: Url, /// The HTTP Status code of this response. pub status: u16, /// The headers returned with this response. pub headers: Headers, /// The body of the response. pub body: Vec<u8>,
}
impl Response { /// Parse the body as JSON. pubfn json<'a, T>(&'a self) -> Result<T, serde_json::Error> where
T: serde::Deserialize<'a>,
{
serde_json::from_slice(&self.body)
}
/// Get the body as a string. Assumes UTF-8 encoding. Any non-utf8 bytes /// are replaced with the replacement character. pubfn text(&self) -> std::borrow::Cow<'_, str> {
String::from_utf8_lossy(&self.body)
}
/// Returns true if the status code is in the interval `[200, 300)`. #[inline] pubfn is_success(&self) -> bool {
status_codes::is_success_code(self.status)
}
/// Returns true if the status code is in the interval `[500, 600)`. #[inline] pubfn is_server_error(&self) -> bool {
status_codes::is_server_error_code(self.status)
}
/// Returns true if the status code is in the interval `[400, 500)`. #[inline] pubfn is_client_error(&self) -> bool {
status_codes::is_client_error_code(self.status)
}
/// Returns an [`UnexpectedStatus`] error if `self.is_success()` is false, /// otherwise returns `Ok(self)`. #[inline] pubfn require_success(self) -> Result<Self, UnexpectedStatus> { ifself.is_success() {
Ok(self)
} else {
Err(UnexpectedStatus {
method: self.request_method, // XXX We probably should try and sanitize this. Replace the user id // if it's a sync token server URL, for example.
url: self.url,
status: self.status,
})
}
}
}
/// A module containing constants for all HTTP status codes. pubmod status_codes {
/// Is it a 2xx status? #[inline] pubfn is_success_code(c: u16) -> bool {
(200..300).contains(&c)
}
/// Is it a 4xx error? #[inline] pubfn is_client_error_code(c: u16) -> bool {
(400..500).contains(&c)
}
/// Is it a 5xx error? #[inline] pubfn is_server_error_code(c: u16) -> bool {
(500..600).contains(&c)
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.