Skip to content

Commit a261fd1

Browse files
committed
Initial crate commit, partially done
1 parent e0a1ecb commit a261fd1

File tree

9 files changed

+189
-0
lines changed

9 files changed

+189
-0
lines changed

Cargo.toml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
[package]
2+
name = "listennotes"
3+
version = "0.1.0"
4+
authors = ["Cameron Fyfe <cameron.j.fyfe@gmail.com>"]
5+
edition = "2018"
6+
7+
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
8+
9+
[dependencies]
10+
serde = { version = "1", features = ["derive"] }
11+
serde_json = "1"
12+
tokio = { version = "1", features = ["full"] }
13+
reqwest = { version = "0.11", features = ["json"] }

examples/sample/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
target/

examples/sample/Cargo.toml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
[package]
2+
name = "sample"
3+
version = "0.1.0"
4+
authors = ["Cameron Fyfe <cameron.j.fyfe@gmail.com>"]
5+
edition = "2018"
6+
7+
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
8+
9+
[dependencies]
10+
listennotes = { version = "^0", path = "../../" }
11+
reqwest = { version = "0.11", features = ["json"] }
12+
serde = { version = "1", features = ["derive"] }
13+
serde_json = "1"
14+
tokio = { version = "1", features = ["full"] }

examples/sample/src/main.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
use listennotes::podcast_api;
2+
use serde_json::json;
3+
4+
#[tokio::main]
5+
async fn main() {
6+
// Api Key (None => Test API, Some(key) => Productino API)
7+
let api_key = None;
8+
9+
// Create client
10+
let client = podcast_api::Client::new(reqwest::Client::new(), api_key);
11+
12+
// Call API
13+
match client
14+
.typeahead(&json!({
15+
"q": "startup",
16+
"show_podcasts": 1
17+
}))
18+
.await
19+
{
20+
Ok(response) => {
21+
println!("Successfully called \"typeahead\" endpoint.");
22+
println!("Response Body:");
23+
println!("{:?}", response);
24+
}
25+
Err(err) => {
26+
println!("Error calling \"typeahead\" endpoint:");
27+
println!("{:?},", err);
28+
}
29+
};
30+
}

src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
pub mod podcast_api;

src/podcast_api/api.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
pub enum Api {
2+
Production(String),
3+
Mock,
4+
}
5+
6+
impl Api {
7+
pub fn url(&self) -> &str {
8+
match &self {
9+
Api::Production(_) => "https://listen-api.listennotes.com/api/v2",
10+
Api::Mock => "https://listen-api-test.listennotes.com/api/v2",
11+
}
12+
}
13+
}

src/podcast_api/client.rs

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
use super::{Api, Result};
2+
use serde_json::{json, Value};
3+
4+
pub struct Client {
5+
client: reqwest::Client,
6+
api: Api,
7+
}
8+
9+
impl Client {
10+
pub fn new(client: reqwest::Client, id: Option<String>) -> Client {
11+
Client {
12+
client,
13+
api: if let Some(id) = id {
14+
Api::Production(id)
15+
} else {
16+
Api::Mock
17+
},
18+
}
19+
}
20+
21+
pub async fn search(&self, parameters: &Value) -> Result<Value> {
22+
self.get("search", parameters).await
23+
}
24+
25+
pub async fn typeahead(&self, parameters: &Value) -> Result<Value> {
26+
self.get("typeahead", parameters).await
27+
}
28+
29+
pub async fn episode_by_id(&self, id: &str, parameters: &Value) -> Result<Value> {
30+
self.get(&format!("episodes/{}", id), parameters).await
31+
}
32+
33+
pub async fn episodes(&self, ids: &[&str], parameters: &Value) -> Result<Value> {
34+
self.post("episodes", &parameters.with("ids", &ids.join(",").as_str()))
35+
.await
36+
}
37+
38+
pub async fn genres(&self, parameters: &Value) -> Result<Value> {
39+
self.get("genres", parameters).await
40+
}
41+
42+
async fn get(&self, endpoint: &str, parameters: &Value) -> Result<Value> {
43+
Ok(self
44+
.client
45+
.get(format!("{}/{}", self.api.url(), endpoint))
46+
.query(parameters)
47+
.send()
48+
.await?
49+
.json()
50+
.await?)
51+
}
52+
53+
async fn post(&self, endpoint: &str, parameters: &Value) -> Result<Value> {
54+
Ok(self
55+
.client
56+
.post(format!("{}/{}", self.api.url(), endpoint))
57+
.header("Content-Type", "application/x-www-form-urlencoded")
58+
.body(serde_json::to_string(&parameters)?) // TODO: switch to URL encoding
59+
.send()
60+
.await?
61+
.json()
62+
.await?)
63+
}
64+
}
65+
66+
trait AddField {
67+
fn with(&self, key: &str, value: &str) -> Self;
68+
}
69+
70+
impl AddField for Value {
71+
fn with(&self, key: &str, value: &str) -> Self {
72+
let mut p = self.clone();
73+
p[key] = json!(value);
74+
p
75+
}
76+
}

src/podcast_api/error.rs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
#[derive(Debug)]
2+
pub enum Error {
3+
Reqwest(reqwest::Error),
4+
Json(serde_json::Error),
5+
}
6+
7+
impl From<reqwest::Error> for Error {
8+
fn from(e: reqwest::Error) -> Error {
9+
Error::Reqwest(e)
10+
}
11+
}
12+
13+
impl From<serde_json::Error> for Error {
14+
fn from(e: serde_json::Error) -> Error {
15+
Error::Json(e)
16+
}
17+
}
18+
19+
impl std::error::Error for Error {
20+
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
21+
match *self {
22+
Error::Reqwest(ref e) => Some(e),
23+
Error::Json(ref e) => Some(e),
24+
}
25+
}
26+
}
27+
28+
impl std::fmt::Display for Error {
29+
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
30+
write!(f, "{}", *self)
31+
}
32+
}

src/podcast_api/mod.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
mod api;
2+
mod client;
3+
mod error;
4+
5+
use api::Api;
6+
7+
pub use client::Client;
8+
pub use error::Error;
9+
pub type Result<T> = std::result::Result<T, error::Error>;

0 commit comments

Comments
 (0)