patron 0.2.1

A wrapper around the hyper.rs library to allow for targeted clients to specific remote APIs. This library should be useful on it's own or as a building block for specific remote API wrappers.
use error;
use hyper;
use hyper_rustls;
use response;
use std;
use types;
use url;


#[derive(Debug, Clone)]
pub struct Request<'a> {
  client: std::sync::Arc<hyper::Client>,
  method: types::Method,
  url: url::Url<'a>,
  headers: hyper::header::Headers,
  body: String,
}


impl<'a> Request<'a> {
  pub fn new() -> Request<'a> {
    Request {
      client: std::sync::Arc::new(hyper::Client::new()),
      method: types::Method::Get,
      url: url::Url::new(),
      headers: hyper::header::Headers::new(),
      body: String::new(),
    }
  }


  pub fn get_scheme(&self) -> types::Scheme {
    self.url.scheme.clone()
  }


  pub fn set_url(&mut self, url: url::Url<'a>) -> &mut Request<'a> {
    let client = match url.scheme {
      types::Scheme::Http => hyper::Client::new(),
      types::Scheme::Https => {
        let tls = hyper_rustls::TlsClient::new();
        let conn = hyper::net::HttpsConnector::new(tls);

        hyper::Client::with_connector(conn)
      }
    };

    self.client = std::sync::Arc::new(client);
    self.url = url;

    self
  }


  pub fn set_method(&mut self, method: types::Method) -> &mut Request<'a> {
    self.method = method;
    self
  }


  pub fn set_headers(
    &mut self,
    headers: hyper::header::Headers,
  ) -> &mut Request<'a> {
    self.headers = headers;
    self
  }


  pub fn set_body<S>(&mut self, body: S) -> &mut Request<'a>
    where S: Into<String>
  {
    self.body = body.into();
    self
  }


  pub fn add_header<H>(&mut self, header: H) -> &mut Request<'a>
    where H: hyper::header::Header + hyper::header::HeaderFormat
  {
    self.headers.set(header);
    self
  }



  pub fn add_path<S>(&mut self, path: S) -> &mut Request<'a>
    where S: Into<String>
  {
    self.url.add_path(path.into());
    self
  }


  pub fn add_query_param<K, S>(&mut self, key: K, val: S) -> &mut Request<'a>
    where K: Into<String>,
          S: Into<std::borrow::Cow<'a, str>>
  {
    self.url.add_query_param(key, val);
    self
  }


  pub fn basic_auth<U, P>(&mut self, u: U, p: Option<P>) -> &mut Request<'a>
    where U: Into<String>,
          P: Into<String>
  {
    let auth = hyper::header::Basic {
      username: u.into(),
      password: p.map(|s| s.into()),
    };
    self.add_header(hyper::header::Authorization(auth))
  }


  pub fn set_bearer_token<T>(&mut self, token: T) -> &mut Request<'a>
    where T: Into<String>
  {
    let auth = hyper::header::Bearer { token: token.into() };

    self.add_header(hyper::header::Authorization(auth))
  }


  pub fn send(&self) -> std::result::Result<response::Response, error::Error> {

    let url = try!(self.url.to_url());

    let request = match self.method {
      types::Method::Get => self.client.get(url),
      types::Method::Post => self.client.post(url),
      types::Method::Put => self.client.put(url),
    };

    request
      .headers(self.headers.clone())
      .body(&self.body)
      .send()
      .map_err(error::Error::from)
      .map(response::Response::from)
      .and_then(
        |res| match res.ok {
          true => Ok(res),
          false => Err(error::Error::from(res)),
        },
      )

  }
}