use crate::changelog::GetChangelogRequest;
use crate::coins::{
GetCoinEventsRequest, GetCoinExchangesRequest, GetCoinMarketsRequest,
GetCoinOHLCHistoricalRequest, GetCoinOHLCLastFullDayRequest, GetCoinOHLCTodayRequest,
GetCoinRequest, GetCoinsRequest, GetTwitterRequest,
};
use crate::contracts::{GetContractPlatformsRequest, GetContractsRequest};
use crate::error::Error;
use crate::exchanges::{GetExchangeMarketsRequest, GetExchangeRequest, GetExchangesRequest};
use crate::global::GetGlobalRequest;
use crate::key::GetKeyInfoRequest;
use crate::people::GetPersonRequest;
use crate::tags::{GetTagRequest, GetTagsRequest};
use crate::tickers::{GetHistoricalTicksRequest, GetTickerRequest, GetTickersRequest};
use crate::tools::{GetPriceConversionRequest, GetSearchRequest};
use reqwest::StatusCode;
use reqwest_middleware::{
ClientBuilder, ClientWithMiddleware, Error as ReqwestMiddlewareError, RequestBuilder,
};
use reqwest_retry::{policies::ExponentialBackoff, RetryTransientMiddleware};
static DEFAULT_USER_AGENT: &str = "coinpaprika-api-rust-client";
static API_URL: &str = "https://api.coinpaprika.com/v1/";
static API_URL_PRO: &str = "https://api-pro.coinpaprika.com/v1/";
#[derive(Debug)]
pub struct Response {
pub response: reqwest::Response,
pub request: reqwest::Request,
}
pub struct Client {
pub client: ClientWithMiddleware,
pub api_url: &'static str,
api_key: Option<String>,
user_agent: &'static str,
}
impl Client {
pub fn new() -> Self {
Client {
client: ClientBuilder::new(reqwest::Client::new())
.with(RetryTransientMiddleware::new_with_policy(
ExponentialBackoff::builder().build_with_max_retries(3),
))
.build(),
api_url: API_URL,
api_key: None,
user_agent: DEFAULT_USER_AGENT,
}
}
pub fn with_key(key: &str) -> Self {
Client {
client: ClientBuilder::new(reqwest::Client::new())
.with(RetryTransientMiddleware::new_with_policy(
ExponentialBackoff::builder().build_with_max_retries(3),
))
.build(),
api_url: API_URL_PRO,
api_key: Some(String::from(key)),
user_agent: DEFAULT_USER_AGENT,
}
}
pub async fn request(&self, request: RequestBuilder) -> Result<Response, Error> {
let mut request = request.header("User-Agent", self.user_agent);
if let Some(api_key) = &self.api_key {
request = request.header("Authorization", api_key);
}
let request = request.build()?;
let response = self
.client
.execute(request.try_clone().expect(
"Error can remain unhandled because we're not using streams, which are the try_clone fail condition",
))
.await;
match &response {
Ok(response) => match response.status() {
StatusCode::BAD_REQUEST => return Err(Error::InvalidRequestError),
StatusCode::PAYMENT_REQUIRED => return Err(Error::InsufficientPlan),
StatusCode::FORBIDDEN => return Err(Error::InvalidApiKey),
StatusCode::NOT_FOUND => return Err(Error::InvalidParameter),
StatusCode::TOO_MANY_REQUESTS => return Err(Error::RateLimitError),
StatusCode::INTERNAL_SERVER_ERROR => return Err(Error::InternalServerError),
_ => {}
},
Err(err) => match err {
ReqwestMiddlewareError::Middleware(_err) => {
return Err(Error::ApiConnectionError);
}
ReqwestMiddlewareError::Reqwest(err) => {
if err.is_connect() || err.is_timeout() {
return Err(Error::ApiConnectionError);
}
}
},
};
Ok(Response {
response: response?,
request,
})
}
pub fn key_info(&self) -> GetKeyInfoRequest {
GetKeyInfoRequest::new(self)
}
pub fn global(&self) -> GetGlobalRequest {
GetGlobalRequest::new(self)
}
pub fn coins(&self) -> GetCoinsRequest {
GetCoinsRequest::new(self)
}
pub fn coin(&self, coin_id: &str) -> GetCoinRequest {
GetCoinRequest::new(self, coin_id)
}
pub fn twitter(&self, coin_id: &str) -> GetTwitterRequest {
GetTwitterRequest::new(self, coin_id)
}
pub fn coin_events(&self, coin_id: &str) -> GetCoinEventsRequest {
GetCoinEventsRequest::new(self, coin_id)
}
pub fn coin_exchanges(&self, coin_id: &str) -> GetCoinExchangesRequest {
GetCoinExchangesRequest::new(self, coin_id)
}
pub fn coin_markets(&self, coin_id: &str) -> GetCoinMarketsRequest {
GetCoinMarketsRequest::new(self, coin_id)
}
pub fn coin_ohlc_last_full_day(&self, coin_id: &str) -> GetCoinOHLCLastFullDayRequest {
GetCoinOHLCLastFullDayRequest::new(self, coin_id)
}
pub fn coin_ohlc_historical(&self, coin_id: &str) -> GetCoinOHLCHistoricalRequest {
GetCoinOHLCHistoricalRequest::new(self, coin_id)
}
pub fn coin_ohlc_today(&self, coin_id: &str) -> GetCoinOHLCTodayRequest {
GetCoinOHLCTodayRequest::new(self, coin_id)
}
pub fn person(&self, person_id: &str) -> GetPersonRequest {
GetPersonRequest::new(self, person_id)
}
pub fn tags(&self) -> GetTagsRequest {
GetTagsRequest::new(self)
}
pub fn tag(&self, tag_id: &str) -> GetTagRequest {
GetTagRequest::new(self, tag_id)
}
pub fn tickers(&self) -> GetTickersRequest {
GetTickersRequest::new(self)
}
pub fn ticker(&self, coin_id: &str) -> GetTickerRequest {
GetTickerRequest::new(self, coin_id)
}
pub fn historical_ticks(&self, coin_id: &str) -> GetHistoricalTicksRequest {
GetHistoricalTicksRequest::new(self, coin_id)
}
pub fn exchanges(&self) -> GetExchangesRequest {
GetExchangesRequest::new(self)
}
pub fn exchange(&self, exchange_id: &str) -> GetExchangeRequest {
GetExchangeRequest::new(self, exchange_id)
}
pub fn exchange_markets(&self, exchange_id: &str) -> GetExchangeMarketsRequest {
GetExchangeMarketsRequest::new(self, exchange_id)
}
pub fn search(&self, q: &str) -> GetSearchRequest {
GetSearchRequest::new(self, q)
}
pub fn price_convert(
&self,
base_currency_id: &str,
quote_currency_id: &str,
) -> GetPriceConversionRequest {
GetPriceConversionRequest::new(self, base_currency_id, quote_currency_id)
}
pub fn contract_platforms(&self) -> GetContractPlatformsRequest {
GetContractPlatformsRequest::new(self)
}
pub fn contracts(&self, platform_id: &str) -> GetContractsRequest {
GetContractsRequest::new(self, platform_id)
}
pub fn changelog(&self, page: i32) -> GetChangelogRequest {
GetChangelogRequest::new(self, page)
}
}
impl Default for Client {
fn default() -> Self {
Self::new()
}
}