use super::error;
use isahc::{http::StatusCode, prelude::*, Body, Response};
use secrecy::{ExposeSecret, SecretString};
use serde::de::DeserializeOwned;
use std::collections::HashMap;
use url::Url;
pub enum HttpMethod {
Get,
}
pub type Headers<'a> = HashMap<String, &'a SecretString>;
pub trait ApiEndpoint<Value>
where
Value: DeserializeOwned,
{
fn method(&self) -> HttpMethod {
return HttpMethod::Get;
}
fn headers(&self) -> Headers {
return HashMap::new();
}
fn url(&self) -> Url;
}
pub fn call<V>(endpoint: &dyn ApiEndpoint<V>) -> Result<V, error::Error>
where
V: DeserializeOwned,
{
let mut response = match endpoint.method() {
HttpMethod::Get => get(&endpoint.url(), &endpoint.headers())?,
};
let status = response.status();
if status == StatusCode::FORBIDDEN || status == StatusCode::UNAUTHORIZED {
return Err(error::Error::Unauthorized);
}
if status == StatusCode::NOT_FOUND {
return Err(error::Error::ResourceNotFound);
}
return match response.json() {
Ok(obj) => Ok(obj),
Err(err) => {
let data = response
.text()
.map_err(|_| error::Error::UnexpectedResponse)?;
println!("Failed to parse value due to error: {err}: {data}");
return Err(error::Error::UnexpectedResponse);
}
};
}
fn get(url: &Url, headers: &Headers) -> Result<Response<Body>, error::Error> {
let mut req = isahc::Request::get(url.as_str());
for (key, value) in headers.iter() {
req = req.header(key, value.expose_secret().clone());
}
if headers.len() > 0 {
println!("GET {url} (headers)");
} else {
println!("GET {url}");
}
match isahc::send(req.body(()).unwrap()) {
Err(err) => {
println!("Request failed due to error: {err}");
return Err(error::Error::NetworkFailure);
}
Ok(response) => return Ok(response),
};
}