use std::collections::HashMap;
use reqwest::{Client, Method, header::{HeaderMap, ACCEPT, CONNECTION, CONTENT_TYPE}};
use serde_json::Value;
use std::fmt;
const API_VERSION: &str = "3";
#[derive(Debug)]
pub enum APIKeyError {
MissingAPIKey,
}
impl std::error::Error for APIKeyError {}
impl fmt::Display for APIKeyError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
APIKeyError::MissingAPIKey => write!(f, "Missing API Key"),
}
}
}
pub struct TMDB {
pub base_uri: String,
pub session: Option<Client>,
pub timeout: Option<u64>,
pub headers: HeaderMap,
pub base_path: String,
pub urls: HashMap<String, String>,
}
impl TMDB {
pub fn new() -> Self {
let mut headers = HeaderMap::new();
headers.insert(CONTENT_TYPE, "application/json".parse().unwrap());
headers.insert(ACCEPT, "application/json".parse().unwrap());
headers.insert(CONNECTION, "close".parse().unwrap());
Self {
base_uri: format!("https://api.themoviedb.org/{}", API_VERSION),
session: None,
timeout: None,
headers,
base_path: "".to_string(),
urls: HashMap::new(),
}
}
pub fn _get_path(&self, key: &str) -> String {
format!("{}{}", self.base_path, self.urls.get(key).unwrap_or(&"".to_string()))
}
pub fn _get_complete_url(&self, path: &str) -> String {
format!("{}/{}", self.base_uri, path)
}
pub fn _get_params(&self, params: &mut HashMap<String, String>) -> Result<(), APIKeyError> {
let api_key = std::env::var("TMDB_API_KEY").map_err(|_| APIKeyError::MissingAPIKey)?;
params.insert("api_key".to_string(), api_key);
Ok(())
}
pub async fn _request(
&self,
method: Method,
path: &str,
params: Option<HashMap<String, String>>,
payload: Option<Value>,
) -> Result<Value, Box<dyn std::error::Error + Send + Sync + 'static>> {
let url = self._get_complete_url(path);
let mut params = params.unwrap_or_else(HashMap::new);
self._get_params(&mut params)?;
let client = self.session.as_ref().unwrap_or(&Client::new()).clone();
let mut request = client.request(method, &url).headers(self.headers.clone());
if let Some(timeout) = self.timeout {
request = request.timeout(std::time::Duration::from_secs(timeout));
}
if let Some(payload) = payload {
request = request.json(&payload);
}
let response = request.query(¶ms).send().await?;
response.error_for_status_ref()?;
let json: Value = response.json().await?;
Ok(json)
}
pub async fn _get(&self, path: &str, params: Option<HashMap<String, String>>) -> Result<Value, Box<dyn std::error::Error + Send + Sync + 'static>> {
self._request(Method::GET, path, params, None).await
}
pub async fn _post(
&self,
path: &str,
params: Option<HashMap<String, String>>,
payload: Option<Value>,
) -> Result<Value, Box<dyn std::error::Error + Send + Sync + 'static>> {
self._request(Method::POST, path, params, payload).await
}
pub async fn _delete(
&self,
path: &str,
params: Option<HashMap<String, String>>,
payload: Option<Value>,
) -> Result<Value, Box<dyn std::error::Error + Send + Sync + 'static>> {
self._request(Method::DELETE, path, params, payload).await
}
}