use std::io::Read;
use reqwest::{Client as ReqwestClient, RequestBuilder, StatusCode, Url};
use serde::de::DeserializeOwned;
use serde_json;
use ::builder::Search;
use ::{API_URL, Error, Result};
use ::model::{Anime, Character, Manga, Producer, Response, User};
pub trait KitsuRequester {
fn get_anime(&self, id: u64) -> Result<Response<Anime>>;
fn get_character(&self, id: u64) -> Result<Response<Character>>;
fn get_manga(&self, id: u64) -> Result<Response<Manga>>;
fn get_producer(&self, id: u64) -> Result<Response<Producer>>;
fn get_user(&self, id: u64) -> Result<Response<User>>;
fn search_anime<F: FnOnce(Search) -> Search>(&self, f: F) ->
Result<Response<Vec<Anime>>>;
fn search_characters<F: FnOnce(Search) -> Search>(&self, f: F)
-> Result<Response<Vec<Character>>>;
fn search_manga<F: FnOnce(Search) -> Search>(&self, f: F) ->
Result<Response<Vec<Manga>>>;
fn search_users<F: FnOnce(Search) -> Search>(&self, f: F) ->
Result<Response<Vec<User>>>;
}
impl KitsuRequester for ReqwestClient {
fn get_anime(&self, id: u64) -> Result<Response<Anime>> {
let uri = Url::parse(&format!("{}/anime/{}", API_URL, id.to_string()))?;
handle_request::<Response<Anime>>(&mut self.get(uri))
}
fn get_character(&self, id: u64) -> Result<Response<Character>> {
let uri = Url::parse(&format!("{}/characters/{}", API_URL, id.to_string()))?;
handle_request::<Response<Character>>(&mut self.get(uri))
}
fn get_manga(&self, id: u64) -> Result<Response<Manga>> {
let uri = Url::parse(&format!("{}/manga/{}", API_URL, id.to_string()))?;
handle_request::<Response<Manga>>(&mut self.get(uri))
}
fn get_user(&self, id: u64) -> Result<Response<User>> {
let uri = Url::parse(&format!("{}/users/{}", API_URL, id.to_string()))?;
handle_request::<Response<User>>(&mut self.get(uri))
}
fn get_producer(&self, id: u64) -> Result<Response<Producer>> {
let uri = Url::parse(&format!("{}/producers/{}", API_URL, id.to_string()))?;
handle_request::<Response<Producer>>(&mut self.get(uri))
}
fn search_anime<F: FnOnce(Search) -> Search>(&self, f: F) ->
Result<Response<Vec<Anime>>> {
let params = f(Search::default()).0;
let uri = Url::parse(&format!("{}/anime?{}", API_URL, params))?;
handle_request::<Response<Vec<Anime>>>(&mut self.get(uri))
}
fn search_characters<F: FnOnce(Search) -> Search>(&self, f: F) ->
Result<Response<Vec<Character>>> {
let params = f(Search::default()).0;
let uri = Url::parse(&format!("{}/characters?{}", API_URL, params))?;
handle_request::<Response<Vec<Character>>>(&mut self.get(uri))
}
fn search_manga<F: FnOnce(Search) -> Search>(&self, f: F) ->
Result<Response<Vec<Manga>>> {
let params = f(Search::default()).0;
let uri = Url::parse(&format!("{}/manga?{}", API_URL, params))?;
handle_request::<Response<Vec<Manga>>>(&mut self.get(uri))
}
fn search_users<F: FnOnce(Search) -> Search>(&self, f: F) ->
Result<Response<Vec<User>>> {
let params = f(Search::default()).0;
let uri = Url::parse(&format!("{}/users?{}", API_URL, params))?;
handle_request::<Response<Vec<User>>>(&mut self.get(uri))
}
}
fn handle_request<T: DeserializeOwned>(request: &mut RequestBuilder) -> Result<T> {
let response = request.send()?;
match response.status() {
StatusCode::Ok => {},
StatusCode::BadRequest => {
return Err(Error::ReqwestBad(Box::new(response)));
},
StatusCode::Unauthorized => {
return Err(Error::ReqwestUnauthorized(Box::new(response)));
},
_ => return Err(Error::ReqwestInvalid(Box::new(response))),
}
from_reader(response)
}
#[inline]
fn from_reader<T: DeserializeOwned, U: Read>(reader: U) -> Result<T> {
serde_json::from_reader(reader).map_err(From::from)
}