newswrap/client.rs
1//! Hacker News API client bindings and various methods for interacting. The client is an async-first HTTP client and
2//! application authors should expect to bring an async runtime of their choosing. There are currently no plans to provide
3//! a blocking API, though this may change in future releases.
4
5use std::time::Duration;
6
7use crate::{
8 http::InternalHttpClient, items::client::HackerNewsItemClient,
9 realtime::client::HackerNewsRealtimeClient, users::client::HackerNewsUserClient,
10};
11
12/// Version information for the Hacker News API containing the base URLs.
13#[derive(Debug, Clone, Copy)]
14pub enum ApiVersion {
15 /// Represents version 0 of the Hacker News API.
16 V0,
17}
18
19/// All outgoing requests will have a user-agent associated to newswrap for request visibility.
20const USER_AGENT: &str = concat!(env!("CARGO_PKG_NAME"), "/", env!("CARGO_PKG_VERSION"),);
21
22/// Current URL of the API.
23const API_BASE_URL: &str = "https://hacker-news.firebaseio.com/v0";
24
25/// Default timeout for requests the API.
26const DEFAULT_TIMEOUT_SECONDS: u64 = 10;
27
28/// A wrapping HTTP client for Hacker News Firebase API and real-time data.
29/// A client instance should only be instantiated once in an application's
30/// lifecycle, seeking to reuse it where possible. Clients can be configured
31/// with requests timeouts in seconds, defaulting to 10 seconds.
32///
33/// ```
34/// use newswrap::client::HackerNewsClient;
35///
36/// // Default client with 10 second timeout
37/// let default_timeout_client = HackerNewsClient::new();
38///
39/// // Or, with an optional timeout
40/// let custom_client = HackerNewsClient::new_with_timeout_secs(10);
41/// let custom_client_with_duration = HackerNewsClient::new_with_timeout_duration(std::time::Duration::from_millis(400));
42/// ```
43#[derive(Debug)]
44pub struct HackerNewsClient {
45 /// An internal item client for interacting with items.
46 pub items: HackerNewsItemClient,
47 /// An internal user client for interacting with users.
48 pub users: HackerNewsUserClient,
49 /// An internal realtime client for interacting with live data.
50 pub realtime: HackerNewsRealtimeClient,
51 /// The internal version of the Hacker News API your client will target.
52 pub version: ApiVersion,
53}
54
55impl Default for HackerNewsClient {
56 fn default() -> Self {
57 Self::new()
58 }
59}
60
61impl HackerNewsClient {
62 /// Internally constructs the client allowing for flexibility in configuring the timeout.
63 fn new_client(timeout: std::time::Duration) -> Self {
64 let client = reqwest::ClientBuilder::new()
65 .timeout(timeout)
66 .user_agent(USER_AGENT)
67 .build()
68 // TODO: probably move this to a builder of sorts, if this panics we have much bigger problems
69 .unwrap();
70
71 let internal_client = InternalHttpClient::new(client, API_BASE_URL);
72 let item_client = HackerNewsItemClient::new(internal_client.clone());
73 let user_client: HackerNewsUserClient = HackerNewsUserClient::new(internal_client.clone());
74 let realtime_client = HackerNewsRealtimeClient::new(internal_client);
75
76 Self {
77 items: item_client,
78 users: user_client,
79 realtime: realtime_client,
80 version: ApiVersion::V0,
81 }
82 }
83
84 /// Constructs a new client pointing to the latest Hacker News API version.
85 pub fn new() -> Self {
86 let duration = std::time::Duration::from_secs(DEFAULT_TIMEOUT_SECONDS);
87 Self::new_client(duration)
88 }
89
90 /// Constructs a new client pointing to the latest Hacker News API version with the configured request timeout in seconds.
91 pub fn new_with_timeout_secs(timeout: u64) -> Self {
92 let duration = std::time::Duration::from_secs(timeout);
93 Self::new_client(duration)
94 }
95
96 /// Constructs a new client pointing to the latest Hacker News API version with the configured request timeout duration.
97 pub fn new_with_timeout_duration(duration: Duration) -> Self {
98 Self::new_client(duration)
99 }
100}