diff --git a/README.md b/README.md index 4797f06..ce15e9f 100644 --- a/README.md +++ b/README.md @@ -72,6 +72,12 @@ Ureq supports sending and receiving json, if you enable the "json" feature: .into_string()?; ``` +### Error handling + +ureq returns errors via `Result`. That includes I/O errors, +protocol errors, and status code errors (when the server responded 4xx or +5xx). More details on the [Error] type. + ### Features To enable a minimal dependency tree, some features are off by default. @@ -192,6 +198,7 @@ If ureq is not what you're looking for, check out these other Rust HTTP clients: [post()]: https://docs.rs/ureq/latest/ureq/fn.post.html [put()]: https://docs.rs/ureq/latest/ureq/fn.put.html [Request]: https://docs.rs/ureq/latest/ureq/struct.Request.html +[Error]: https://docs.rs/ureq/latest/ureq/enum.Error.html [Request::call()]: https://docs.rs/ureq/latest/ureq/struct.Request.html#method.call [Request::send()]: https://docs.rs/ureq/latest/ureq/struct.Request.html#method.send [Request::send_bytes()]: https://docs.rs/ureq/latest/ureq/struct.Request.html#method.send_bytes diff --git a/README.tpl b/README.tpl index 92a944d..a5da6df 100644 --- a/README.tpl +++ b/README.tpl @@ -12,6 +12,7 @@ [post()]: https://docs.rs/ureq/latest/ureq/fn.post.html [put()]: https://docs.rs/ureq/latest/ureq/fn.put.html [Request]: https://docs.rs/ureq/latest/ureq/struct.Request.html +[Error]: https://docs.rs/ureq/latest/ureq/enum.Error.html [Request::call()]: https://docs.rs/ureq/latest/ureq/struct.Request.html#method.call [Request::send()]: https://docs.rs/ureq/latest/ureq/struct.Request.html#method.send [Request::send_bytes()]: https://docs.rs/ureq/latest/ureq/struct.Request.html#method.send_bytes diff --git a/src/agent.rs b/src/agent.rs index 60f6a13..5c018cc 100644 --- a/src/agent.rs +++ b/src/agent.rs @@ -417,13 +417,13 @@ impl AgentBuilder { /// let result = ureq::builder() /// .redirects(1) /// .build() + /// # ; + /// # let result = ureq::agent() /// .get("http://httpbin.org/status/301") - /// .error_on_non_2xx(false) /// .call()?; /// assert_ne!(result.status(), 301); /// /// let result = ureq::post("http://httpbin.org/status/307") - /// .error_on_non_2xx(false) /// .send_bytes(b"some data")?; /// assert_eq!(result.status(), 307); /// # Ok(()) diff --git a/src/error.rs b/src/error.rs index 272c2c4..e912d8a 100644 --- a/src/error.rs +++ b/src/error.rs @@ -42,6 +42,23 @@ use crate::Response; /// ureq::get(url).call() /// } /// ``` +/// +/// If you'd like to treat all status code errors as normal, successful responses, +/// you can use [Result::or_else](std::result::Result::or_else) like this: +/// +/// ``` +/// use ureq::Error::Status; +/// # fn main() -> std::result::Result<(), ureq::Error> { +/// # ureq::is_test(true); +/// let resp = ureq::get("http://example.com/") +/// .call() +/// .or_else(|e| match e { +/// Status(_, r) => Ok(r), // turn status errors into Ok Responses. +/// _ => Err(e), +/// })?; +/// # Ok(()) +/// # } +/// ``` #[derive(Debug)] pub enum Error { /// A response was successfully received but had status code >= 400. diff --git a/src/lib.rs b/src/lib.rs index 26bf627..4ba9b6a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -82,6 +82,12 @@ //! # fn main() {} //! ``` //! +//! ## Error handling +//! +//! ureq returns errors via `Result`. That includes I/O errors, +//! protocol errors, and status code errors (when the server responded 4xx or +//! 5xx). More details on the [Error] type. +//! //! ## Features //! //! To enable a minimal dependency tree, some features are off by default. diff --git a/src/request.rs b/src/request.rs index 5622ca1..8bf0991 100644 --- a/src/request.rs +++ b/src/request.rs @@ -120,7 +120,7 @@ impl Request { let unit = Unit::new(&self.agent, &self.method, &url, &self.headers, &reader); let response = unit::connect(unit, true, reader, None).map_err(|e| e.url(url.clone()))?; - if self.error_on_non_2xx && response.status() >= 400 { + if response.status() >= 400 { Err(Error::Status(response.status(), response)) } else { Ok(response) @@ -336,26 +336,6 @@ impl Request { .push((param.to_string(), value.to_string())); self } - - /// By default, if a response's status is anything but a 2xx or 3xx, - /// call()/send() and related methods will return an Error. If you want - /// to handle such responses as non-errors, set this to `false`. - /// - /// Example: - /// ``` - /// # fn main() -> Result<(), ureq::Error> { - /// # ureq::is_test(true); - /// let response = ureq::get("http://httpbin.org/status/500") - /// .error_on_non_2xx(false) - /// .call()?; - /// assert_eq!(response.status(), 500); - /// # Ok(()) - /// # } - /// ``` - pub fn error_on_non_2xx(mut self, value: bool) -> Self { - self.error_on_non_2xx = value; - self - } } #[test] diff --git a/src/testserver.rs b/src/testserver.rs index 8d7ea63..3cdef51 100644 --- a/src/testserver.rs +++ b/src/testserver.rs @@ -17,6 +17,8 @@ pub(crate) fn test_agent() -> Agent { let headers = read_request(&stream); if headers.0.is_empty() { // no headers probably means it's the initial request to check test server is up. + } else if headers.path() == "/status/200" { + stream.write_all(b"HTTP/1.1 200 OK\r\n\r\n")?; } else if headers.path() == "/status/500" { stream.write_all(b"HTTP/1.1 500 Server Internal Error\r\n\r\n")?; } else if headers.path() == "/bytes/100" { @@ -30,11 +32,11 @@ pub(crate) fn test_agent() -> Agent { stream.write_all(br#"{"hello": "world"}"#)?; } else if headers.path() == "/status/301" { stream.write_all(b"HTTP/1.1 301 Found\r\n")?; - stream.write_all(b"Location: /redirect/3\r\n")?; + stream.write_all(b"Location: /status/200\r\n")?; stream.write_all(b"\r\n")?; } else if headers.path() == "/status/307" { stream.write_all(b"HTTP/1.1 307 Found\r\n")?; - stream.write_all(b"Location: /redirect/3\r\n")?; + stream.write_all(b"Location: /status/200\r\n")?; stream.write_all(b"\r\n")?; } else { stream.write_all(b"HTTP/1.1 200 OK\r\n")?;