Update documentation. (#73)
* Update documentation. Synchronize goals section between README and rustdoc, and add two goals (blocking API; no unsafe) that were mentioned elsewhere in the README. Add error handling to examples for the module and for the Response object. And a section on synthetic errors to the top-level module documentation. * Add back missing close brace. * Add main function that returns Result. * Add links to send_bytes and send_form. * Document chunked encoding for send. * Use a larger vec of bytes for send.
This commit is contained in:
committed by
GitHub
parent
7adbd57308
commit
fdc1f37662
35
README.md
35
README.md
@@ -13,20 +13,21 @@
|
|||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate ureq;
|
extern crate ureq;
|
||||||
|
|
||||||
fn main() {
|
// sync post request of some json.
|
||||||
|
let resp = ureq::post("https://myapi.example.com/ingest")
|
||||||
|
.set("X-My-Header", "Secret")
|
||||||
|
.send_json(json!({
|
||||||
|
"name": "martin",
|
||||||
|
"rust": true
|
||||||
|
}));
|
||||||
|
|
||||||
// sync post request of some json.
|
// .ok() tells if response is 200-299.
|
||||||
let resp = ureq::post("https://myapi.acme.com/ingest")
|
if resp.ok() {
|
||||||
.set("X-My-Header", "Secret")
|
println!("success: {}", resp.into_string()?);
|
||||||
.send_json(json!({
|
} else {
|
||||||
"name": "martin",
|
// This can include errors like failure to parse URL or connect timeout.
|
||||||
"rust": true
|
// They are treated as synthetic HTTP-level error statuses.
|
||||||
}));
|
println!("error {}: {}", resp.status(), resp.into_string()?);
|
||||||
|
|
||||||
// .ok() tells if response is 200-299.
|
|
||||||
if resp.ok() {
|
|
||||||
// ...
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -77,7 +78,9 @@ You can control them when including `ureq` as a dependency.
|
|||||||
|
|
||||||
* Minimal dependency tree
|
* Minimal dependency tree
|
||||||
* Obvious API
|
* Obvious API
|
||||||
* Convencience over correctness
|
* Blocking API
|
||||||
|
* Convenience over correctness
|
||||||
|
* No use of unsafe
|
||||||
|
|
||||||
This library tries to provide a convenient request library with a minimal dependency
|
This library tries to provide a convenient request library with a minimal dependency
|
||||||
tree and an obvious API. It is inspired by libraries like
|
tree and an obvious API. It is inspired by libraries like
|
||||||
@@ -104,8 +107,8 @@ for convenience over correctness, so the decision is left to the user.
|
|||||||
This library uses blocking socket reads and writes. When it was
|
This library uses blocking socket reads and writes. When it was
|
||||||
created, there wasn't any async/await support in rust, and for my own
|
created, there wasn't any async/await support in rust, and for my own
|
||||||
purposes, blocking IO was fine. At this point, one good reason to keep
|
purposes, blocking IO was fine. At this point, one good reason to keep
|
||||||
this library going is that it is blocking (the other is that it relies
|
this library going is that it is blocking (the other is that it does not
|
||||||
on very little use of unsafe).
|
use unsafe).
|
||||||
|
|
||||||
## TODO
|
## TODO
|
||||||
|
|
||||||
|
|||||||
48
src/lib.rs
48
src/lib.rs
@@ -6,23 +6,33 @@
|
|||||||
//!
|
//!
|
||||||
//! * Minimal dependency tree
|
//! * Minimal dependency tree
|
||||||
//! * Obvious API
|
//! * Obvious API
|
||||||
|
//! * Blocking API
|
||||||
|
//! * Convenience over correctness
|
||||||
|
//! * No use of unsafe
|
||||||
//!
|
//!
|
||||||
//! ```
|
//! ```
|
||||||
//! // requires feature: `ureq = { version = "*", features = ["json"] }`
|
//! // requires feature: `ureq = { version = "*", features = ["json"] }`
|
||||||
//! # #[cfg(feature = "json")] {
|
//! # #[cfg(feature = "json")] {
|
||||||
//! use ureq::json;
|
//! use ureq::json;
|
||||||
//!
|
//!
|
||||||
//! // sync post request of some json.
|
//! fn main() -> std::io::Result<()> {
|
||||||
//! let resp = ureq::post("https://myapi.acme.com/ingest")
|
//! // sync post request of some json.
|
||||||
//! .set("X-My-Header", "Secret")
|
//! let resp = ureq::post("https://myapi.example.com/ingest")
|
||||||
//! .send_json(json!({
|
//! .set("X-My-Header", "Secret")
|
||||||
//! "name": "martin",
|
//! .send_json(json!({
|
||||||
//! "rust": true
|
//! "name": "martin",
|
||||||
//! }));
|
//! "rust": true
|
||||||
|
//! }));
|
||||||
//!
|
//!
|
||||||
//! // .ok() tells if response is 200-299.
|
//! // .ok() tells if response is 200-299.
|
||||||
//! if resp.ok() {
|
//! if resp.ok() {
|
||||||
//! // ....
|
//! println!("success: {}", resp.into_string()?);
|
||||||
|
//! } else {
|
||||||
|
//! // This can include errors like failure to parse URL or connect timeout.
|
||||||
|
//! // They are treated as synthetic HTTP-level error statuses.
|
||||||
|
//! println!("error {}: {}", resp.status(), resp.into_string()?);
|
||||||
|
//! }
|
||||||
|
//! Ok(())
|
||||||
//! }
|
//! }
|
||||||
//! # }
|
//! # }
|
||||||
//! ```
|
//! ```
|
||||||
@@ -37,8 +47,10 @@
|
|||||||
//! which follows a build pattern. The builders are finished using:
|
//! which follows a build pattern. The builders are finished using:
|
||||||
//!
|
//!
|
||||||
//! * [`.call()`](struct.Request.html#method.call) without a request body.
|
//! * [`.call()`](struct.Request.html#method.call) without a request body.
|
||||||
//! * [`.send()`](struct.Request.html#method.send) with a request body as `Read`.
|
//! * [`.send()`](struct.Request.html#method.send) with a request body as `Read` (chunked encoding).
|
||||||
//! * [`.send_string()`](struct.Request.html#method.send_string) body as string.
|
//! * [`.send_string()`](struct.Request.html#method.send_string) body as string.
|
||||||
|
//! * [`.send_bytes()`](struct.Request.html#method.send_bytes) body as bytes.
|
||||||
|
//! * [`.send_form()`](struct.Request.html#method.send_form) key-value pairs as application/x-www-form-urlencoded.
|
||||||
//!
|
//!
|
||||||
//! # JSON
|
//! # JSON
|
||||||
//!
|
//!
|
||||||
@@ -91,6 +103,20 @@
|
|||||||
//! we first check if the user has set a `; charset=<whatwg charset>` and attempt
|
//! we first check if the user has set a `; charset=<whatwg charset>` and attempt
|
||||||
//! to encode the request body using that.
|
//! to encode the request body using that.
|
||||||
//!
|
//!
|
||||||
|
//! # Synthetic errors
|
||||||
|
//!
|
||||||
|
//! Rather than exposing a custom error type through results, this library has opted for
|
||||||
|
//! representing potential connection/TLS/etc errors as HTTP response codes. These invented codes
|
||||||
|
//! are called "[synthetic](struct.Response.html#method.synthetic)."
|
||||||
|
//!
|
||||||
|
//! The idea is that from a library user's point of view the distinction of whether a failure
|
||||||
|
//! originated in the remote server (500, 502) etc, or some transient network failure, the code
|
||||||
|
//! path of handling that would most often be the same.
|
||||||
|
//!
|
||||||
|
//! As a result, reading from a Response may yield an error message generated by the ureq library.
|
||||||
|
//! To handle these errors, use the
|
||||||
|
//! [`response.synthetic_error()`](struct.Response.html#method.synthetic_error) method.
|
||||||
|
//!
|
||||||
|
|
||||||
mod agent;
|
mod agent;
|
||||||
mod body;
|
mod body;
|
||||||
|
|||||||
@@ -214,16 +214,19 @@ impl Request {
|
|||||||
|
|
||||||
/// Send data from a reader.
|
/// Send data from a reader.
|
||||||
///
|
///
|
||||||
/// The `Content-Length` header is not set because we can't know the length of the reader.
|
/// This uses [chunked transfer encoding](https://tools.ietf.org/html/rfc7230#section-4.1).
|
||||||
|
/// The caller is responsible for setting the Transfer-Encoding: chunked header.
|
||||||
|
///
|
||||||
|
/// The input from the reader is buffered into chunks of size 16,384, the max size of a TLS fragment.
|
||||||
///
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// use std::io::Cursor;
|
/// use std::io::Cursor;
|
||||||
///
|
///
|
||||||
/// let text = "Hello there!\n";
|
/// let read = Cursor::new(vec![0x20; 100_000]);
|
||||||
/// let read = Cursor::new(text.to_string().into_bytes());
|
|
||||||
///
|
///
|
||||||
/// let resp = ureq::post("/somewhere")
|
/// let resp = ureq::post("http://localhost/example-upload")
|
||||||
/// .set("Content-Type", "text/plain")
|
/// .set("Content-Type", "text/plain")
|
||||||
|
/// .set("Transfer-Encoding", "chunked")
|
||||||
/// .send(read);
|
/// .send(read);
|
||||||
/// ```
|
/// ```
|
||||||
pub fn send(&mut self, reader: impl Read + 'static) -> Response {
|
pub fn send(&mut self, reader: impl Read + 'static) -> Response {
|
||||||
|
|||||||
@@ -29,8 +29,16 @@ pub const DEFAULT_CHARACTER_SET: &str = "utf-8";
|
|||||||
/// [`into_json_deserialize()`](#method.into_json_deserialize) or
|
/// [`into_json_deserialize()`](#method.into_json_deserialize) or
|
||||||
/// [`into_string()`](#method.into_string) consumes the response.
|
/// [`into_string()`](#method.into_string) consumes the response.
|
||||||
///
|
///
|
||||||
|
/// All error handling, including URL parse errors and connection errors, is done by mapping onto
|
||||||
|
/// [synthetic errors](#method.synthetic). Callers must check response.synthetic_error(),
|
||||||
|
/// response.is_ok(), or response.error() before relying on the contents of the reader.
|
||||||
|
///
|
||||||
/// ```
|
/// ```
|
||||||
/// let response = ureq::get("https://www.google.com").call();
|
/// let response = ureq::get("https://www.google.com").call();
|
||||||
|
/// if let Some(error) = response.synthetic_error() {
|
||||||
|
/// eprintln!("{}", error);
|
||||||
|
/// return;
|
||||||
|
/// }
|
||||||
///
|
///
|
||||||
/// // socket is still open and the response body has not been read.
|
/// // socket is still open and the response body has not been read.
|
||||||
///
|
///
|
||||||
|
|||||||
Reference in New Issue
Block a user