use crate::{
comments::HackerNewsComment, errors::HackerNewsResult, items::HackerNewsItem,
stories::HackerNewsStory, users::HackerNewsUser, HackerNewsID, API_BASE_URL,
DEFAULT_TIMEOUT_SECONDS, ITEM_ENDPOINT, USERS_ENDPOINT,
};
#[derive(Debug, Clone, Copy)]
pub enum ApiVersion {
V0,
}
#[derive(Debug)]
pub struct HackerNewsClient {
http_client: reqwest::Client,
version: ApiVersion,
}
impl Default for HackerNewsClient {
fn default() -> Self {
Self::new()
}
}
impl HackerNewsClient {
fn new_client(timeout: u64) -> Self {
let client = reqwest::ClientBuilder::new()
.timeout(std::time::Duration::from_secs(timeout))
.build()
.unwrap();
Self {
http_client: client,
version: ApiVersion::V0,
}
}
pub fn new() -> Self {
Self::new_client(DEFAULT_TIMEOUT_SECONDS)
}
pub fn new_with_timeout(timeout: u64) -> Self {
Self::new_client(timeout)
}
fn versioned_api_base_url(&self) -> String {
let version = match self.version {
ApiVersion::V0 => "v0",
};
format!("{}/{}", API_BASE_URL, version)
}
pub async fn get_item(&self, id: HackerNewsID) -> HackerNewsResult<HackerNewsItem> {
let item = self
.http_client
.get(format!(
"{}/{}/{}.json",
self.versioned_api_base_url(),
ITEM_ENDPOINT,
id
))
.send()
.await?
.json::<HackerNewsItem>()
.await?;
Ok(item)
}
pub async fn get_user(&self, username: &str) -> HackerNewsResult<HackerNewsUser> {
let user = self
.http_client
.get(format!(
"{}/{}/{}.json",
self.versioned_api_base_url(),
USERS_ENDPOINT,
username
))
.send()
.await?
.json::<HackerNewsUser>()
.await?;
Ok(user)
}
pub async fn get_story(&self, id: HackerNewsID) -> HackerNewsResult<HackerNewsStory> {
let item = self.get_item(id).await?;
let story = item.try_into()?;
Ok(story)
}
pub async fn get_comment(&self, id: HackerNewsID) -> HackerNewsResult<HackerNewsComment> {
let item = self.get_item(id).await?;
let comment = item.try_into()?;
Ok(comment)
}
}