1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
use crate::spotify::{Spotify, SpotifyError};
use json::{self, JsonValue, Null};
use reqwest;
use serde_json::Value;
use std::collections::HashMap;
/// Enum to store types of requests relevant to Spotify API
pub enum RequestMethod {
Get,
Post(HashMap<String, Value>),
Put(HashMap<String, Value>),
Delete(HashMap<String, Value>),
}
impl Spotify {
/// General request to the spotify API. Returns JSON response
///
/// # Arguments
/// * `url_extension` - part of url past: `https://api.spotify.com/v1/`. Specific to each type of request
/// * `request_method` - type of request (GET, POST, PUT, DELETE)
///
/// # Panics
/// On various parsing errors. Shouldn't happen? Probably.
///
pub fn spotify_request(
&self,
url_extension: &str,
request_method: RequestMethod,
) -> Result<JsonValue, SpotifyError> {
let access_token = self.access_token()?; // get access token
let client = reqwest::blocking::Client::new(); // create client
let mut headers = reqwest::header::HeaderMap::new(); // create header map
headers.insert(
"Authorization",
format!("Bearer {}", access_token).parse().unwrap(),
); // insert authorization header
let request_url = format!("https://api.spotify.com/v1/{}", url_extension); // create request url
// Send appropriate request for request method
let response = match request_method {
RequestMethod::Get => match client.get(&request_url).headers(headers).send() {
Ok(response) => response,
Err(e) => return Err(SpotifyError::RequestError(e.to_string())),
},
RequestMethod::Post(body) => {
match client
.post(&request_url)
.headers(headers)
.header("Content-Type", "application/json")
.json(&body)
.send()
{
Ok(response) => response,
Err(e) => return Err(SpotifyError::RequestError(e.to_string())),
}
}
RequestMethod::Put(body) => {
match client
.put(&request_url)
.headers(headers)
.header("Content-Type", "application/json")
.json(&body)
.send()
{
Ok(response) => response,
Err(e) => return Err(SpotifyError::RequestError(e.to_string())),
}
}
RequestMethod::Delete(body) => {
match client
.delete(&request_url)
.headers(headers)
.header("Content-Type", "application/json")
.json(&body)
.send()
{
Ok(response) => response,
Err(e) => return Err(SpotifyError::RequestError(e.to_string())),
}
}
};
let response_body = json::parse(&response.text().unwrap()); // parse response body
match response_body {
// check for errors
Ok(response_body) => {
if response_body["error"].is_null() {
// if no error field then assume no error
Ok(response_body)
} else {
match response_body["error"]["status"].as_i32() {
// match various known errors
Some(401) => Err(SpotifyError::BadOrExpiredToken(
response_body["error"]["message"].to_string(),
)),
Some(403) => Err(SpotifyError::BadRequest(
response_body["error"]["message"].to_string(),
)),
Some(429) => Err(SpotifyError::RateLimitExceeded(
response_body["error"]["message"].to_string(),
)),
_ => Err(SpotifyError::RequestError(format!(
"Error code: {}, message: {}",
response_body["error"]["status"], response_body["error"]["message"]
))), // unknown error/general error
}
}
}
Err(_) => Ok(Null), // on json parsing error just return nothing (temp fix for a potential non-problem)
}
}
}