about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--src/lib.rs82
1 files changed, 63 insertions, 19 deletions
diff --git a/src/lib.rs b/src/lib.rs
index 82e7322f38c8..080e7d9c6670 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -2,14 +2,41 @@
 //!
 //! This library provides a simplified API over the [cURL Rust
 //! bindings][] that resemble that of higher-level libraries such as
-//! [reqwest][].
+//! [reqwest][]. All calls are synchronous.
 //!
 //! `crimp` is intended to be used in situations where HTTP client
 //! functionality is desired without adding a significant number of
 //! dependencies or sacrificing too much usability.
 //!
+//! Using `crimp` to make HTTP requests is done using a simple
+//! builder-pattern style API:
+//!
+//! ```rust
+//! use crimp::{Method, Request};
+//!
+//! let response = Request::new(Method::Get, "http://httpbin.org/get").unwrap()
+//!     .user_agent("crimp test suite").unwrap()
+//!     .send().unwrap();
+//!
+//! assert_eq!(response.status, 200);
+//! ```
+//!
+//! The `json` feature (enabled by default) adds support for
+//! automatically serialising and deserialising request/response
+//! bodies using `serde_json`.
+//!
+//! If a feature from the underlying cURL library is missing, the
+//! `Request::raw` method can be used as an escape hatch to deal with
+//! the handle directly. Should you find yourself doing this, please
+//! [file an issue][].
+//!
+//! `crimp` does not currently expose functionality for re-using a
+//! cURL Easy handle, meaning that keep-alive of HTTP connections and
+//! the like is not supported.
+//!
 //! [cURL Rust bindings]: https://docs.rs/curl
 //! [reqwest]: https://docs.rs/reqwest
+//! [file an issue]: https://github.com/tazjin/crimp/issues
 
 extern crate curl;
 
@@ -17,22 +44,26 @@ extern crate curl;
 #[cfg(feature = "json")] extern crate serde_json;
 
 use curl::easy::{Easy, List, ReadError};
-#[cfg(feature = "json")] use serde::Serialize;
-#[cfg(feature = "json")] use serde::de::DeserializeOwned;
 use std::collections::HashMap;
 use std::io::Write;
 use std::string::{FromUtf8Error, ToString};
 
+#[cfg(feature = "json")] use serde::Serialize;
+#[cfg(feature = "json")] use serde::de::DeserializeOwned;
+
 #[cfg(test)]
 mod tests;
 
-type CurlResult<T> = Result<T, curl::Error>;
-
 /// HTTP method to use for the request.
 pub enum Method {
     Get, Post, Put, Patch, Delete
 }
 
+/// Builder structure for an HTTP request.
+///
+/// This is the primary API-type in `crimp`. After creating a new
+/// request its parameters are modified using the various builder
+/// methods until it is consumed by `send()`.
 pub struct Request<'a> {
     handle: Easy,
     headers: List,
@@ -49,16 +80,28 @@ enum Body<'a> {
     }
 }
 
+/// HTTP responses structure containing response data and headers.
+///
+/// By default the `send()` function of the `Request` structure will
+/// return a `Response<Vec<u8>>`. Convenience helpers exist for
+/// decoding a string via `Response::as_string` or to a
+/// `serde`-compatible type with `Response::as_json` (if the
+/// `json`-feature is enabled).
 #[derive(Debug)]
-pub struct CurlResponse<T> {
+pub struct Response<T> {
+    /// HTTP status code of the response.
     pub status: u32,
+
+    /// HTTP headers returned from the remote.
     pub headers: HashMap<String, String>,
+
+    /// Body data from the HTTP response.
     pub body: T,
 }
 
 impl <'a> Request<'a> {
     /// Initiate an HTTP request with the given method and URL.
-    pub fn new(method: Method, url: &str) -> CurlResult<Self> {
+    pub fn new(method: Method, url: &str) -> Result<Self, curl::Error> {
         let mut handle = Easy::new();
         handle.url(url)?;
 
@@ -77,20 +120,21 @@ impl <'a> Request<'a> {
         })
     }
 
-    /// Add a header to a request.
-    pub fn header(mut self, k: &str, v: &str) -> CurlResult<Self> {
+    /// Add an HTTP header to a request.
+    pub fn header(mut self, k: &str, v: &str) -> Result<Self, curl::Error> {
         self.headers.append(&format!("{}: {}", k, v))?;
         Ok(self)
     }
 
-    /// Set the User-Agent for this request.
-    pub fn user_agent<'b: 'a>(mut self, agent: &str) -> CurlResult<Self> {
+    /// Set the `User-Agent` for this request. By default this will be
+    /// set to cURL's standard user agent.
+    pub fn user_agent<'b: 'a>(mut self, agent: &str) -> Result<Self, curl::Error> {
         self.handle.useragent(agent)?;
         Ok(self)
     }
 
     /// Add a byte-array body to a request using the specified
-    /// Content-Type.
+    /// `Content-Type`.
     pub fn body(mut self, content_type: &'a str, data: &'a [u8]) -> Self {
         self.body = Body::Bytes { data, content_type };
         self
@@ -106,7 +150,7 @@ impl <'a> Request<'a> {
 
     /// Send the HTTP request and return a response structure
     /// containing the raw body.
-    pub fn send(mut self) -> CurlResult<CurlResponse<Vec<u8>>> {
+    pub fn send(mut self) -> Result<Response<Vec<u8>>, curl::Error> {
         // Create structures in which to store the response data:
         let mut headers = HashMap::new();
         let mut body = vec![];
@@ -191,7 +235,7 @@ impl <'a> Request<'a> {
             transfer.perform()?;
         }
 
-        Ok(CurlResponse {
+        Ok(Response {
             status: self.handle.response_code()?,
             headers,
             body
@@ -199,13 +243,13 @@ impl <'a> Request<'a> {
     }
 }
 
-impl CurlResponse<Vec<u8>> {
+impl Response<Vec<u8>> {
     /// Attempt to parse the HTTP response body as a UTF-8 encoded
     /// string.
-    pub fn as_string(self) -> Result<CurlResponse<String>, FromUtf8Error> {
+    pub fn as_string(self) -> Result<Response<String>, FromUtf8Error> {
         let body = String::from_utf8(self.body)?;
 
-        Ok(CurlResponse {
+        Ok(Response {
             body,
             status: self.status,
             headers: self.headers,
@@ -214,10 +258,10 @@ impl CurlResponse<Vec<u8>> {
 
     /// Attempt to deserialize the HTTP response body from JSON.
     #[cfg(feature = "json")]
-    pub fn as_json<T: DeserializeOwned>(self) -> Result<CurlResponse<T>, serde_json::Error> {
+    pub fn as_json<T: DeserializeOwned>(self) -> Result<Response<T>, serde_json::Error> {
         let deserialized = serde_json::from_slice(&self.body)?;
 
-        Ok(CurlResponse {
+        Ok(Response {
             body: deserialized,
             status: self.status,
             headers: self.headers,