rust.request.rs Maven / Gradle / Ivy
use std::borrow::Cow;
use std::collections::HashMap;
use super::{configuration, Error};
use futures;
use futures::{Future, Stream};
use hyper;
use hyper::header::UserAgent;
use serde;
use serde_json;
pub(crate) struct ApiKey {
pub in_header: bool,
pub in_query: bool,
pub param_name: String,
}
impl ApiKey {
fn key(&self, prefix: &Option, key: &str) -> String {
match prefix {
None => key.to_owned(),
Some(ref prefix) => format!("{} {}", prefix, key),
}
}
}
#[allow(dead_code)]
pub(crate) enum Auth {
None,
ApiKey(ApiKey),
Basic,
Oauth,
}
pub(crate) struct Request {
auth: Auth,
method: hyper::Method,
path: String,
query_params: HashMap,
no_return_type: bool,
path_params: HashMap,
form_params: HashMap,
header_params: HashMap,
// TODO: multiple body params are possible technically, but not supported here.
serialized_body: Option,
}
impl Request {
pub fn new(method: hyper::Method, path: String) -> Self {
Request {
auth: Auth::None,
method: method,
path: path,
query_params: HashMap::new(),
path_params: HashMap::new(),
form_params: HashMap::new(),
header_params: HashMap::new(),
serialized_body: None,
no_return_type: false,
}
}
pub fn with_body_param(mut self, param: T) -> Self {
self.serialized_body = Some(serde_json::to_string(¶m).unwrap());
self
}
pub fn with_header_param(mut self, basename: String, param: String) -> Self {
self.header_params.insert(basename, param);
self
}
pub fn with_query_param(mut self, basename: String, param: String) -> Self {
self.query_params.insert(basename, param);
self
}
pub fn with_path_param(mut self, basename: String, param: String) -> Self {
self.path_params.insert(basename, param);
self
}
pub fn with_form_param(mut self, basename: String, param: String) -> Self {
self.form_params.insert(basename, param);
self
}
pub fn returns_nothing(mut self) -> Self {
self.no_return_type = true;
self
}
pub fn with_auth(mut self, auth: Auth) -> Self {
self.auth = auth;
self
}
pub fn execute<'a, C, U>(
self,
conf: &configuration::Configuration,
) -> Box> + 'a>
where
C: hyper::client::Connect,
U: Sized + 'a,
for<'de> U: serde::Deserialize<'de>,
{
let mut query_string = ::url::form_urlencoded::Serializer::new("".to_owned());
// raw_headers is for headers we don't know the proper type of (e.g. custom api key
// headers); headers is for ones we do know the type of.
let mut raw_headers = HashMap::new();
let mut headers: hyper::header::Headers = hyper::header::Headers::new();
let mut path = self.path;
for (k, v) in self.path_params {
// replace {id} with the value of the id path param
path = path.replace(&format!("{{{}}}", k), &v);
}
for (k, v) in self.header_params {
raw_headers.insert(k, v);
}
for (key, val) in self.query_params {
query_string.append_pair(&key, &val);
}
match self.auth {
Auth::ApiKey(apikey) => {
if let Some(ref key) = conf.api_key {
let val = apikey.key(&key.prefix, &key.key);
if apikey.in_query {
query_string.append_pair(&apikey.param_name, &val);
}
if apikey.in_header {
raw_headers.insert(apikey.param_name, val);
}
}
}
Auth::Basic => {
if let Some(ref auth_conf) = conf.basic_auth {
let auth = hyper::header::Authorization(hyper::header::Basic {
username: auth_conf.0.to_owned(),
password: auth_conf.1.to_owned(),
});
headers.set(auth);
}
}
Auth::Oauth => {
if let Some(ref token) = conf.oauth_access_token {
let auth = hyper::header::Authorization(hyper::header::Bearer {
token: token.to_owned(),
});
headers.set(auth);
}
}
Auth::None => {}
}
let mut uri_str = format!("{}{}", conf.base_path, path);
let query_string_str = query_string.finish();
if query_string_str != "" {
uri_str += "?";
uri_str += &query_string_str;
}
let uri: hyper::Uri = match uri_str.parse() {
Err(e) => {
return Box::new(futures::future::err(Error::UriError(e)));
}
Ok(u) => u,
};
let mut req = hyper::Request::new(self.method, uri);
{
let req_headers = req.headers_mut();
if let Some(ref user_agent) = conf.user_agent {
req_headers.set(UserAgent::new(Cow::Owned(user_agent.clone())));
}
req_headers.extend(headers.iter());
for (key, val) in raw_headers {
req_headers.set_raw(key, val);
}
}
if self.form_params.len() > 0 {
req.headers_mut().set(hyper::header::ContentType::form_url_encoded());
let mut enc = ::url::form_urlencoded::Serializer::new("".to_owned());
for (k, v) in self.form_params {
enc.append_pair(&k, &v);
}
req.set_body(enc.finish());
}
if let Some(body) = self.serialized_body {
req.headers_mut().set(hyper::header::ContentType::json());
req.headers_mut()
.set(hyper::header::ContentLength(body.len() as u64));
req.set_body(body);
}
let no_ret_type = self.no_return_type;
let res = conf.client
.request(req)
.map_err(|e| Error::from(e))
.and_then(|resp| {
let status = resp.status();
resp.body()
.concat2()
.and_then(move |body| Ok((status, body)))
.map_err(|e| Error::from(e))
})
.and_then(|(status, body)| {
if status.is_success() {
Ok(body)
} else {
Err(Error::from((status, &*body)))
}
});
Box::new(
res
.and_then(move |body| {
let parsed: Result = if no_ret_type {
// This is a hack; if there's no_ret_type, U is (), but serde_json gives an
// error when deserializing "" into (), so deserialize 'null' into it
// instead.
// An alternate option would be to require U: Default, and then return
// U::default() here instead since () implements that, but then we'd
// need to impl default for all models.
serde_json::from_str("null")
} else {
serde_json::from_slice(&body)
};
parsed.map_err(|e| Error::from(e))
})
)
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy