Skip to content

Commit 1808e1e

Browse files
authored
Merge pull request #4 from ListenNotes/cameron-develop
Cameron develop
2 parents 1bb236d + 18e4dc9 commit 1808e1e

File tree

5 files changed

+234
-46
lines changed

5 files changed

+234
-46
lines changed

examples/sample/src/main.rs

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use podcast_api::Error;
12
use serde_json::json;
23

34
#[tokio::main]
@@ -17,17 +18,25 @@ async fn main() {
1718
.await
1819
{
1920
Ok(response) => {
20-
println!("Successfully called \"typeahead\" endpoint.");
21+
println!("Successfully called Listen Notes API.");
2122
if let Ok(body) = response.json().await {
2223
println!("Response Body:");
23-
println!("{:?}", body);
24+
println!("{}", body);
2425
} else {
2526
println!("Response body JSON data parsing error.")
2627
}
2728
}
2829
Err(err) => {
29-
println!("Error calling \"typeahead\" endpoint:");
30-
println!("{:?},", err);
30+
match err {
31+
Error::NotFoundError => { println!("Not Found: {}", err); }
32+
Error::AuthenticationError => { println!("Authentication Issue: {}", err); }
33+
Error::RateLimitError => { println!("Rate Limit: {}", err); }
34+
Error::InvalidRequestError => { println!("Invalid Request: {}", err); }
35+
Error::ListenApiError => { println!("API Error: {}", err); }
36+
Error::ApiConnectionError => { println!("Connection Issue: {}", err); }
37+
Error::Reqwest(err) => { println!("Reqwest HTTP Client Error: {}", err); }
38+
Error::Json(err) => { println!("JSON Parsing Error: {}", err); }
39+
}
3140
}
3241
};
3342
}

rustfmt.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
max_width = 120

src/client.rs

Lines changed: 57 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
use super::{Api, Result};
1+
use super::{Api, Error, Result};
2+
use http::StatusCode;
23
use reqwest::RequestBuilder;
34
use serde_json::Value;
45
use std::time::Duration;
@@ -60,11 +61,7 @@ impl Client<'_> {
6061
}
6162

6263
/// Creates new Listen API Client with user provided HTTP Client.
63-
pub fn new_custom<'a>(
64-
client: reqwest::Client,
65-
id: Option<&'a str>,
66-
user_agent: Option<&'a str>,
67-
) -> Client<'a> {
64+
pub fn new_custom<'a>(client: reqwest::Client, id: Option<&'a str>, user_agent: Option<&'a str>) -> Client<'a> {
6865
Client {
6966
client,
7067
api: if let Some(id) = id {
@@ -115,6 +112,36 @@ impl Client<'_> {
115112
self.post("episodes", parameters).await
116113
}
117114

115+
/// Calls [`GET /curated_podcasts/{id}`](https://www.listennotes.com/api/docs/#post-api-v2-curated_podcasts-id) with supplied parameters.
116+
pub async fn fetch_curated_podcasts_list_by_id(&self, id: &str, parameters: &Value) -> Result<Response> {
117+
self.get(&format!("curated_podcasts/{}", id), parameters).await
118+
}
119+
120+
/// Calls [`GET /curated_podcasts`](https://www.listennotes.com/api/docs/#post-api-v2-curated_podcasts) with supplied parameters.
121+
pub async fn fetch_curated_podcasts_lists(&self, parameters: &Value) -> Result<Response> {
122+
self.get("curated_podcasts", parameters).await
123+
}
124+
125+
/// Calls [`GET /genres`](https://www.listennotes.com/api/docs/#post-api-v2-genres) with supplied parameters.
126+
pub async fn fetch_podcast_genres(&self, parameters: &Value) -> Result<Response> {
127+
self.get("genres", parameters).await
128+
}
129+
130+
/// Calls [`GET /regions`](https://www.listennotes.com/api/docs/#post-api-v2-regions) with supplied parameters.
131+
pub async fn fetch_podcast_regions(&self, parameters: &Value) -> Result<Response> {
132+
self.get("regions", parameters).await
133+
}
134+
135+
/// Calls [`GET /languages`](https://www.listennotes.com/api/docs/#post-api-v2-languages) with supplied parameters.
136+
pub async fn fetch_podcast_languages(&self, parameters: &Value) -> Result<Response> {
137+
self.get("languages", parameters).await
138+
}
139+
140+
/// Calls [`GET /just_listen`](https://www.listennotes.com/api/docs/#post-api-v2-just_listen) with supplied parameters.
141+
pub async fn just_listen(&self, parameters: &Value) -> Result<Response> {
142+
self.get("just_listen", parameters).await
143+
}
144+
118145
async fn get(&self, endpoint: &str, parameters: &Value) -> Result<Response> {
119146
let request = self
120147
.client
@@ -143,8 +170,31 @@ impl Client<'_> {
143170
.header("User-Agent", self.user_agent)
144171
.build()?;
145172

173+
let response = self
174+
.client
175+
.execute(request.try_clone().expect(
176+
"Error can remain unhandled because we're not using streams, which are the try_clone fail condition",
177+
))
178+
.await;
179+
180+
match &response {
181+
Ok(response) => match response.status() {
182+
StatusCode::NOT_FOUND => return Err(Error::NotFoundError),
183+
StatusCode::UNAUTHORIZED => return Err(Error::AuthenticationError),
184+
StatusCode::TOO_MANY_REQUESTS => return Err(Error::RateLimitError),
185+
StatusCode::BAD_REQUEST => return Err(Error::InvalidRequestError),
186+
StatusCode::INTERNAL_SERVER_ERROR => return Err(Error::ListenApiError),
187+
_ => {}
188+
},
189+
Err(err) => {
190+
if err.is_connect() || err.is_timeout() {
191+
return Err(Error::ApiConnectionError);
192+
}
193+
}
194+
};
195+
146196
Ok(Response {
147-
response: self.client.execute(request.try_clone().expect("Error can remain unhandled because we're not using streams, which are the try_clone fail condition")).await?,
197+
response: response?,
148198
request,
149199
})
150200
}

src/error.rs

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,18 @@
11
/// Error for API calls from [`Client`](super::Client).
22
#[derive(Debug)]
33
pub enum Error {
4+
/// Wrong api key or your account is suspended.
5+
AuthenticationError,
6+
/// Fail to connect to API servers.
7+
ApiConnectionError,
8+
/// Something wrong on your end (client side errors), e.g., missing required parameters.
9+
InvalidRequestError,
10+
/// You are using FREE plan and you exceed the quota limit.
11+
RateLimitError,
12+
/// Endpoint not exist, or podcast / episode not exist.
13+
NotFoundError,
14+
/// Something wrong on our end (unexpected server errors).
15+
ListenApiError,
416
/// Error from http client.
517
Reqwest(reqwest::Error),
618
/// Error from JSON creation/processing.
@@ -24,12 +36,38 @@ impl std::error::Error for Error {
2436
match *self {
2537
Error::Reqwest(ref e) => Some(e),
2638
Error::Json(ref e) => Some(e),
39+
_ => None,
2740
}
2841
}
2942
}
3043

3144
impl std::fmt::Display for Error {
3245
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
33-
write!(f, "{}", *self)
46+
match self {
47+
Error::AuthenticationError => {
48+
write!(f, "Wrong api key or your account is suspended.")
49+
}
50+
Error::ApiConnectionError => {
51+
write!(f, "Fail to connect to API servers.")
52+
}
53+
Error::InvalidRequestError => {
54+
write!(
55+
f,
56+
"Something wrong on your end (client side errors), e.g., missing required parameters."
57+
)
58+
}
59+
Error::RateLimitError => {
60+
write!(f, "You are using FREE plan and you exceed the quota limit.")
61+
}
62+
Error::NotFoundError => {
63+
write!(f, "Endpoint not exist, or podcast / episode not exist.")
64+
}
65+
Error::ListenApiError => {
66+
write!(f, "Something wrong on our end (unexpected server errors).")
67+
}
68+
Error::Reqwest(_) | Error::Json(_) => {
69+
write!(f, "{}", self)
70+
}
71+
}
3472
}
3573
}

0 commit comments

Comments
 (0)