Skip to content

Commit

Permalink
Docs improvements, add some missing API surfaces
Browse files Browse the repository at this point in the history
  • Loading branch information
sagebind committed Jul 23, 2019
1 parent 787d674 commit 85f9b09
Show file tree
Hide file tree
Showing 4 changed files with 123 additions and 37 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "chttp"
version = "0.5.0"
version = "0.5.1"
description = "The practical HTTP client that is fun to use."
authors = ["Stephen M. Coakley <[email protected]>"]
license = "MIT"
Expand Down
84 changes: 51 additions & 33 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,17 @@
//! The practical HTTP client that is fun to use.
//!
//! # Sending requests
//! Here are some of cHTTP's key features:
//!
//! - Full support for HTTP/1.1 and HTTP/2.
//! - Configurable request timeouts.
//! - Fully asynchronous core, with asynchronous and incremental reading and
//! writing of request and response bodies.
//! - Offers an ergonomic synchronous API as well as an asynchronous API with
//! support for async/await.
//! - Optional automatic redirect following.
//! - Sessions and cookie persistence.
//!
//! # Getting started
//!
//! Sending requests is as easy as calling a single function. Let's make a
//! simple GET request to an example website:
Expand Down Expand Up @@ -34,16 +45,18 @@
//! # Ok::<(), chttp::Error>(())
//! ```
//!
//! # Custom requests
//!
//! cHTTP is not limited to canned HTTP verbs; you can customize requests by
//! creating your own `Request` object and then `send`ing that.
//! If you want to customize the request by adding headers, setting timeouts,
//! etc, then you can create a [`Request`][prelude::Request] using a
//! builder-style fluent interface, then finishing it off with a
//! [`send`][RequestExt::send]:
//!
//! ```no_run
//! use chttp::prelude::*;
//! use std::time::Duration;
//!
//! let response = Request::post("https://httpbin.org/post")
//! .header("Content-Type", "application/json")
//! .timeout(Duration::from_secs(5))
//! .body(r#"{
//! "speed": "fast",
//! "cool_name": true
Expand All @@ -52,41 +65,42 @@
//! # Ok::<(), chttp::Error>(())
//! ```
//!
//! # Request configuration
//! Check out the [examples] directory in the project sources for even more
//! examples.
//!
//! There are a number of options involved in request execution that can be
//! configured for a request, such as timeouts, proxies, and other connection
//! and protocol configuration. These can be customized by using extension
//! methods provided by the [`RequestBuilderExt`](prelude::RequestBuilderExt)
//! trait:
//! # Feature tour
//!
//! ```no_run
//! use chttp::prelude::*;
//! use std::time::Duration;
//! Below is a brief overview of some notable features of cHTTP. Check out the
//! rest of the documentation for even more guides and examples.
//!
//! let response = Request::get("https://httpbin.org/get")
//! .timeout(Duration::from_secs(5))
//! .body(())?
//! .send()?;
//! # Ok::<(), chttp::Error>(())
//! ```
//! ## Easy request functions
//!
//! You can start sending requests without any configuration by using the global
//! functions in this module, including [`get`], [`post`], and [`send`]. These
//! use a shared HTTP client instance with sane defaults, so it is easy to get
//! up and running. They should work perfectly fine for many use-cases, so don't
//! about graduating to more complex APIs if you don't need them.
//!
//! ## Request and response traits
//!
//! cHTTP includes a number of traits in the [`prelude`] module that extend the
//! [`Request`] and [`Response`] types with a plethora of extra methods that
//! make common tasks convenient and allow you to make more advanced
//! configuration.
//!
//! Configuration related to sending requests is stored inside the request
//! struct using [`http::Extensions`].
//! Some key traits to read about include [`RequestExt`], [`RequestBuilderExt`],
//! and [`ResponseExt`].
//!
//! # Custom clients
//! ## Custom clients
//!
//! The free-standing functions for sending request delegate to a shared client
//! instance that is lazily instantiated with the default options. You can also
//! create custom client instances of your own, which allows you to set default
//! options for all requests and group related connections together. Each client
//! has its own connection pool and event loop, so separating certain requests
//! into separate clients can ensure that they are isolated from each other.
//! The free-standing functions for sending requests use a shared [`HttpClient`]
//! instance, but you can also create your own client instances, which allows
//! you to customize the default behavior for requests that use it.
//!
//! See the documentation for [`HttpClient`] and [`HttpClientBuilder`] for more
//! details on creating custom clients.
//! information on creating custom clients.
//!
//! # Asynchronous API and execution
//! ## Asynchronous requests
//!
//! Requests are always executed asynchronously under the hood. This allows a
//! single client to execute a large number of requests concurrently with
Expand Down Expand Up @@ -115,6 +129,7 @@
//! handy if you are debugging code and need to see the exact data being sent to
//! the server and being received.
//!
//! [examples]: https://github.com/sagebind/chttp/tree/master/examples
//! [log]: https://docs.rs/log
#![deny(unsafe_code)]
Expand Down Expand Up @@ -156,6 +171,8 @@ pub use crate::{
body::Body,
client::{HttpClient, HttpClientBuilder, ResponseFuture},
error::Error,
request::{RequestBuilderExt, RequestExt},
response::ResponseExt,
};

/// Re-export of the standard HTTP types.
Expand All @@ -166,8 +183,9 @@ pub mod prelude {
pub use crate::{
Body,
HttpClient,
request::{RequestBuilderExt, RequestExt},
response::ResponseExt,
RequestExt,
RequestBuilderExt,
ResponseExt,
};

pub use http::{Request, Response};
Expand Down
30 changes: 30 additions & 0 deletions src/request.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,21 @@ pub trait RequestBuilderExt {
/// being aborted.
///
/// If not set, no timeout will be enforced.
///
/// # Examples
///
/// ```no_run
/// use chttp::prelude::*;
/// use std::time::Duration;
///
/// // This page is too slow and won't respond in time.
/// let response = Request::get("https://httpbin.org/delay/10")
/// .timeout(Duration::from_secs(5))
/// .body(())?
/// .send()
/// .expect_err("page should time out");
/// # Ok::<(), chttp::Error>(())
/// ```
fn timeout(&mut self, timeout: Duration) -> &mut Self;

/// Set a timeout for the initial connection phase.
Expand Down Expand Up @@ -194,6 +209,21 @@ pub trait RequestExt<T> {
///
/// This is a convenience method that is equivalent to
/// [`send`](crate::send).
///
/// # Examples
///
/// ```no_run
/// use chttp::prelude::*;
///
/// let response = Request::post("https://httpbin.org/post")
/// .header("Content-Type", "application/json")
/// .body(r#"{
/// "speed": "fast",
/// "cool_name": true
/// }"#)?
/// .send()?;
/// # Ok::<(), chttp::Error>(())
/// ```
fn send(self) -> Result<Response<Body>, Error>
where
T: Into<Body>;
Expand Down
44 changes: 41 additions & 3 deletions src/response.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,15 @@ pub trait ResponseExt<T> {
/// # Examples
///
/// ```no_run
/// # use chttp::prelude::*;
/// use chttp::prelude::*;
///
/// chttp::get("https://httpbin.org/image/jpeg")?
/// .copy_to_file("image.jpg")?;
/// .copy_to_file("myimage.jpg")?;
/// # Ok::<(), chttp::Error>(())
/// ```
fn copy_to_file(&mut self, path: impl AsRef<Path>) -> io::Result<u64>
where
T: Read
T: Read,
{
File::create(path).and_then(|f| self.copy_to(f))
}
Expand All @@ -41,6 +42,16 @@ pub trait ResponseExt<T> {
///
/// This method consumes the entire response body stream and can only be
/// called once, unless you can rewind this response body.
///
/// # Examples
///
/// ```no_run
/// use chttp::prelude::*;
///
/// let text = chttp::get("https://example.org")?.text()?;
/// println!("{}", text);
/// # Ok::<(), chttp::Error>(())
/// ```
fn text(&mut self) -> Result<String, Error>
where
T: Read;
Expand All @@ -52,6 +63,24 @@ pub trait ResponseExt<T> {
fn text_async(&mut self) -> Text<'_, T>
where
T: AsyncRead + Unpin;

/// Deserialize the response body as JSON into a given type.
///
/// # Examples
///
/// ```no_run
/// use chttp::prelude::*;
/// use serde_json::Value;
///
/// let json: Value = chttp::get("https://httpbin.org/json")?.json()?;
/// println!("author: {}", json["slideshow"]["author"]);
/// # Ok::<(), Box<dyn std::error::Error>>(())
/// ```
#[cfg(feature = "json")]
fn json<D>(&mut self) -> Result<D, serde_json::Error>
where
D: serde::de::DeserializeOwned,
T: Read;
}

impl<T> ResponseExt<T> for Response<T> {
Expand All @@ -77,4 +106,13 @@ impl<T> ResponseExt<T> for Response<T> {
{
Text::new(self.body_mut())
}

#[cfg(feature = "json")]
fn json<D>(&mut self) -> Result<D, serde_json::Error>
where
D: serde::de::DeserializeOwned,
T: Read,
{
serde_json::from_reader(self.body_mut())
}
}

0 comments on commit 85f9b09

Please sign in to comment.