1use crate::{
4 comments::HackerNewsComment, errors::HackerNewsResult, items::HackerNewsItem,
5 stories::HackerNewsStory, users::HackerNewsUser, HackerNewsID, API_BASE_URL,
6 DEFAULT_TIMEOUT_SECONDS, ITEM_ENDPOINT, USERS_ENDPOINT,
7};
8
9#[derive(Debug, Clone, Copy)]
11pub enum ApiVersion {
12 V0,
14}
15
16#[derive(Debug)]
20pub struct HackerNewsClient {
21 http_client: reqwest::Client,
23 version: ApiVersion,
25}
26
27impl Default for HackerNewsClient {
28 fn default() -> Self {
29 Self::new()
30 }
31}
32
33impl HackerNewsClient {
34 fn new_client(timeout: u64) -> Self {
36 let client = reqwest::ClientBuilder::new()
37 .timeout(std::time::Duration::from_secs(timeout))
38 .build()
39 .unwrap();
40
41 Self {
42 http_client: client,
43 version: ApiVersion::V0,
44 }
45 }
46
47 pub fn new() -> Self {
49 Self::new_client(DEFAULT_TIMEOUT_SECONDS)
50 }
51
52 pub fn new_with_timeout(timeout: u64) -> Self {
54 Self::new_client(timeout)
55 }
56
57 fn versioned_api_base_url(&self) -> String {
59 let version = match self.version {
60 ApiVersion::V0 => "v0",
61 };
62
63 format!("{}/{}", API_BASE_URL, version)
64 }
65
66 pub async fn get_item(&self, id: HackerNewsID) -> HackerNewsResult<HackerNewsItem> {
68 let item = self
69 .http_client
70 .get(format!(
71 "{}/{}/{}.json",
72 self.versioned_api_base_url(),
73 ITEM_ENDPOINT,
74 id
75 ))
76 .send()
77 .await?
78 .json::<HackerNewsItem>()
79 .await?;
80
81 Ok(item)
82 }
83
84 pub async fn get_user(&self, username: &str) -> HackerNewsResult<HackerNewsUser> {
86 let user = self
87 .http_client
88 .get(format!(
89 "{}/{}/{}.json",
90 self.versioned_api_base_url(),
91 USERS_ENDPOINT,
92 username
93 ))
94 .send()
95 .await?
96 .json::<HackerNewsUser>()
97 .await?;
98
99 Ok(user)
100 }
101
102 pub async fn get_story(&self, id: HackerNewsID) -> HackerNewsResult<HackerNewsStory> {
104 let item = self.get_item(id).await?;
105 let story = item.try_into()?;
106 Ok(story)
107 }
108
109 pub async fn get_comment(&self, id: HackerNewsID) -> HackerNewsResult<HackerNewsComment> {
111 let item = self.get_item(id).await?;
112 let comment = item.try_into()?;
113 Ok(comment)
114 }
115}