use std::fmt;
use url::Url;
use reqwest::{Client, StatusCode, header::CONTENT_TYPE};
use serde_urlencoded;
use crate::{
response::ApiResponse,
request::{
ApiRequest,
LangsRequest,
DetectRequest,
TranslateRequest
},
error::{
Error,
Result
},
};
const BASE_URL: &str = "https://translate.yandex.net/api/v1.5/tr.json";
pub struct ApiClient {
key: String,
client: Client,
}
impl ApiClient {
pub fn new(key: String) -> ApiClient {
let client = Client::new();
ApiClient {
key,
client,
}
}
pub fn get_langs(&self) -> LangsRequest {
LangsRequest::new(&self)
}
pub fn detect<'a>(&'a self, text: &'a str) -> DetectRequest<'a> {
DetectRequest::new(&self, text)
}
pub fn translate<'a>(
&'a self,
text: &'a str,
lang: &'a str
) -> TranslateRequest<'a> {
TranslateRequest::new(&self, text, lang)
}
pub fn execute<Req, Resp>(&self, req: Req) -> Result<Resp>
where Req: ApiRequest,
Resp: ApiResponse,
{
let url = self.make_url(req.method());
let data = serde_urlencoded::to_string(&req)
.expect("can't serialize request contents");
let resp = self.client
.post(url)
.body(data)
.header(CONTENT_TYPE, "application/x-www-form-urlencoded")
.send();
if let Ok(mut resp) = resp {
if let StatusCode::OK = resp.status() {
if let Ok(obj) = resp.json() {
Ok(obj)
} else {
Err(Error::UnexpectedResponse)
}
} else {
if let Ok(err_obj) = resp.json() {
Err(Error::ApiError(err_obj))
} else {
Err(Error::UnexpectedResponse)
}
}
} else {
Err(Error::RequestFailed)
}
}
fn make_url(&self, method: &str) -> Url {
let mut url = Url::parse(BASE_URL)
.unwrap(); url.path_segments_mut()
.unwrap() .push(method);
url.query_pairs_mut()
.append_pair("key", &self.key);
url
}
}
impl fmt::Debug for ApiClient {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("ApiClient")
.finish()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn make_url_test() {
let api = ApiClient::new("mytoken".to_string());
let url = api.make_url("method");
assert_eq!(
"https://translate.yandex.net/api/v1.5/tr.json/method?key=mytoken",
url.as_str()
);
}
}