#![deny(warnings)]
#![deny(missing_docs)]
#[macro_use]
extern crate quick_error;
extern crate bytes;
extern crate elastic_requests;
extern crate elastic_responses;
extern crate futures;
extern crate reqwest;
extern crate serde;
#[cfg_attr(test, macro_use)]
extern crate serde_json;
extern crate tokio_core;
extern crate url;
mod private {
pub trait Sealed {}
}
pub mod sync;
pub mod async;
pub use self::sync::{SyncBody, SyncElasticClient, SyncFromResponse};
pub use self::async::{AsyncBody, AsyncElasticClient, AsyncFromResponse};
pub mod req {
pub use elastic_requests::*;
}
pub mod res {
pub use elastic_responses::*;
}
pub use self::res::parse;
use std::sync::Arc;
use std::collections::BTreeMap;
use std::str;
use reqwest::Error as ReqwestError;
use reqwest::header::{ContentType, Header, Headers};
use url::form_urlencoded::Serializer;
use self::res::error::ResponseError;
use self::req::HttpMethod;
quick_error! {
#[derive(Debug)]
pub enum Error {
Http(err: ReqwestError) {
from()
description("http error")
display("http error: {}", err)
cause(err)
}
Response(err: ResponseError) {
from()
description("response error")
display("response error: {}", err)
cause(err)
}
#[doc(hidden)]
__NonExhaustive
}
}
#[derive(Clone)]
pub struct RequestParams {
base_url: String,
url_params: BTreeMap<&'static str, String>,
headers_factory: Option<Arc<Fn(&mut Headers) + Send + Sync + 'static>>,
}
impl RequestParams {
pub fn new<T: Into<String>>(base: T) -> Self {
RequestParams {
base_url: base.into(),
headers_factory: None,
url_params: BTreeMap::new(),
}
}
pub fn base_url<T: Into<String>>(mut self, base: T) -> Self {
self.base_url = base.into();
self
}
pub fn url_param<T: ToString>(mut self, key: &'static str, value: T) -> Self {
self.url_params.insert(key, value.to_string());
self
}
pub fn header<H>(self, header: H) -> Self
where
H: Header + Clone,
{
self.headers(move |h| h.set(header.clone()))
}
fn headers<F>(mut self, headers_factory: F) -> Self
where
F: Fn(&mut Headers) + Send + Sync + 'static,
{
if let Some(old_headers_factory) = self.headers_factory {
let headers_factory = move |mut headers: &mut Headers| {
old_headers_factory(&mut headers);
headers_factory(&mut headers);
};
self.headers_factory = Some(Arc::new(headers_factory));
} else {
self.headers_factory = Some(Arc::new(headers_factory));
}
self
}
pub fn get_base_url(&self) -> &str {
&self.base_url
}
pub fn get_headers(&self) -> Headers {
let mut headers = Headers::new();
headers.set(ContentType::json());
if let Some(ref headers_factory) = self.headers_factory {
headers_factory(&mut headers);
}
headers
}
pub fn get_url_qry(&self) -> (usize, Option<String>) {
if self.url_params.len() > 0 {
let qry: String = Serializer::for_suffix(String::from("?"), 1)
.extend_pairs(self.url_params.iter())
.finish();
(qry.len(), Some(qry))
} else {
(0, None)
}
}
}
impl Default for RequestParams {
fn default() -> Self {
RequestParams::new("http://localhost:9200")
}
}
fn build_url<'a>(req_url: &str, params: &RequestParams) -> String {
let (qry_len, qry) = params.get_url_qry();
let mut url = String::with_capacity(params.base_url.len() + req_url.len() + qry_len);
url.push_str(¶ms.base_url);
url.push_str(&req_url);
if let Some(qry) = qry {
url.push_str(&qry);
}
url
}
fn build_method(method: HttpMethod) -> reqwest::Method {
match method {
HttpMethod::Get => reqwest::Method::Get,
HttpMethod::Post => reqwest::Method::Post,
HttpMethod::Head => reqwest::Method::Head,
HttpMethod::Delete => reqwest::Method::Delete,
HttpMethod::Put => reqwest::Method::Put,
HttpMethod::Patch => reqwest::Method::Patch,
}
}
#[cfg(test)]
fn assert_send<T: Send>() {}
#[cfg(test)]
fn assert_sync<T: Sync>() {}
#[cfg(test)]
mod tests {
use reqwest::header::{Authorization, ContentType, Referer};
use super::*;
#[test]
fn assert_send_sync() {
assert_send::<RequestParams>();
assert_sync::<RequestParams>();
}
#[test]
fn request_params_has_default_content_type() {
let req = RequestParams::default();
let headers = req.get_headers();
assert_eq!(Some(&ContentType::json()), headers.get::<ContentType>());
}
#[test]
fn set_multiple_headers() {
let req = RequestParams::default()
.headers(|h| h.set(Referer::new("/not-the-value")))
.headers(|h| h.set(Referer::new("/People.html#tim")))
.headers(|h| h.set(Authorization("let me in".to_owned())));
let headers = req.get_headers();
assert_eq!(Some(&ContentType::json()), headers.get::<ContentType>());
assert_eq!(
Some(&Referer::new("/People.html#tim")),
headers.get::<Referer>()
);
assert_eq!(
Some(&Authorization("let me in".to_owned())),
headers.get::<Authorization<String>>()
);
}
#[test]
fn request_params_has_default_base_url() {
let req = RequestParams::default();
assert_eq!("http://localhost:9200", req.base_url);
}
#[test]
fn request_params_can_set_base_url() {
let req = RequestParams::default().base_url("http://eshost:9200");
assert_eq!("http://eshost:9200", req.base_url);
}
#[test]
fn request_params_can_set_url_query() {
let req = RequestParams::default()
.url_param("pretty", false)
.url_param("pretty", true)
.url_param("q", "*");
assert_eq!(
(16, Some(String::from("?pretty=true&q=*"))),
req.get_url_qry()
);
}
#[test]
fn empty_request_params_returns_empty_string() {
let req = RequestParams::default();
assert_eq!((0, None), req.get_url_qry());
}
}