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 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160
//! spotify-rs is a Rust wrapper for the Spotify API. It has full API coverage
//! and supports all the authorisation flows (except for the implicit grant flow).
//!
//! # Getting Started
//! First, you'll need to
//! [create an app](https://developer.spotify.com/documentation/web-api/tutorials/getting-started#create-an-app)
//! on Spotify's developer [dashboard](https://developer.spotify.com/dashboard).
//!
//! You will need to set a redirect URI, which you'll need to pass to spotify-rs
//! and is recommended you use. You'll also need the client ID and possibly the
//! client secret of your app, depending on the authorisation flow you're going to use.
//!
//! To use the Spotify API, you'll need to authenticate using your client credentials,
//! and if you want to access user resources, you'll need to go through one of the authorisation flows.
//!
//! # Authorisation
//! You will need to set some scopes, redirect the user to a generated URL, which will
//! redirect them again to your app's *redirect URI*, which will contain a code that allows
//! your app to be authorised.
//!
//! spotify-rs supports 3 of the 4 OAuth2 authorisation flows the API supports:
//! the authorisation code flow, authorisation code with PKCE flow and the client credentials flow.
//!
//! The [implicit grant flow](https://developer.spotify.com/documentation/web-api/tutorials/implicit-flow)
//! is not supported for 2 reasons:
//! - it returns the access token in the URL, which is insecure and leaves your app vulnerable to all kinds of attacks;
//! - doesn't support refreshing the access token.
//!
//! The auth flow you should use depends on the use case:
//! - the authorisation code flow is recommended for long-running applications
//! where you can safely store the client secret (e.g. web and mobile apps)
//! - the authorisation code with PKCE flow is recommended for long-running applications
//! where you *can't* safely store the client secret (e.g. desktop apps and single page web apps)
//! - the client credentials flow doesn't include authorisation, thus letting you only access public information
//!
//! Below is an example for each auth flow:
//! ## Authorisation Code Flow
//! ```no_run
//! use spotify_rs::{AuthCodeClient, AuthCodeFlow, RedirectUrl};
//! # use std::error::Error;
//!
//!
//! #[tokio::main]
//! async fn main() -> Result<(), Box<dyn Error>> {
//! // This should match the redirect URI you set in your app's settings
//! let redirect_url = RedirectUrl::new("redirect_url".to_owned())?;
//! let auto_refresh = true;
//! let scopes = vec!["user-library-read", "playlist-read-private"];
//! let auth_code_flow = AuthCodeFlow::new("client_id", "client_secret", scopes);
//!
//! // Redirect the user to this URL to get the auth code and CSRF token
//! let (client, url) = AuthCodeClient::new(auth_code_flow, redirect_url, auto_refresh);
//!
//! // They will then have to be redirected to the `redirect_url` you specified,
//! // with those two parameters present in the URL
//!
//! // Finally, exchange the auth code for an access token
//! let mut spotify = client.authenticate("auth_code", "csrf_token").await?;
//!
//! // Get an album with the specified ID (requires no scopes to be set)
//! let album = spotify.album("album_id").get().await?;
//!
//! // The `album` method returns a builder with optional parameters you can set
//! // For example, this sets the market to "GB".
//! let album_gb = spotify.album("album_id").market("GB").get().await?;
//!
//! // Get 5 of the current user's playlists (requires the playlist-read-private scope)
//! let user_playlists = spotify.current_user_playlists().limit(5).get().await?;
//!
//! Ok(())
//! }
//! ```
//! The Authorisation Code Flow with PKCE is the same, except you would need to use
//! [`AuthCodePkceFlow`] and [`AuthCodeClient`].
//!
//! The list of available scopes can be found [here](https://developer.spotify.com/documentation/web-api/concepts/scopes).
//!
//! You can see all of the available optional parameters in the [`Builder`] documentation.
//! They show up after each `impl Builder<'_, F, SomeEndpoint`, where `SomeEndpoint`
//! represents the endpoint you're calling.
//!
//! The auth code and CSRF token can be obtained by parsing the URL the user was redirected
//! to from the `url` returned from `.get_authorisation`.
//!
//! That could be achieved by simply having the user copy and paste the URL into your app,
//! or, the recommended approach, by having a server listening at your `redirect_url` and
//! sending the auth code and CSRF token to the main app when the user is redirected to said URL.
//!
//! ## Client Credentials Flow
//! ```no_run
//! use spotify_rs::{ClientCredsClient, ClientCredsFlow, RedirectUrl};
//! # use std::error::Error;
//!
//! #[tokio::main]
//! async fn main() -> Result<(), Box<dyn Error>> {
//! let auth_flow = ClientCredsFlow::new("client_id", "client_secret");
//!
//! // Create an authenticate the client
//! let mut spotify = ClientCredsClient::authenticate(auth_flow).await?;
//!
//! let album = spotify.album("album_id").get().await?;
//!
//! Ok(())
//! }
//! ```
//! This flow doesn't require anything besides the client credentials,
//! but you cannot access any user information.
//!
//! You can see all of the available optional parameters in the [`Builder`] documentation.
//! They show up after each `impl Builder<'_, F, SomeEndpoint`, where `SomeEndpoint`
//! represents the endpoint you're calling.
//!
//! # Automatic Token Refreshing
//! If `auto_refresh` is set to `true` when creating the client, on every request
//! the client will check if the token is about to expire. If the token is close
//! to expiring, it will refresh the token for you.
//!
//! If you disable this feature, you'll have to refresh the token yourself using [`Client::request_refresh_token()`].
//!
//! [`AuthCodePkceFlow`]: auth::AuthCodePkceFlow
//! [`Builder`]: endpoint::Builder
//! [`Client::request_refresh_token()`]: client::Client::request_refresh_token()
pub mod auth;
pub mod client;
pub mod endpoint;
mod error;
pub mod model;
use client::Body;
use serde::{Deserialize, Deserializer};
pub(crate) fn query_list<T: AsRef<str>>(list: &[T]) -> String {
list.iter()
.map(|i| i.as_ref())
.collect::<Vec<&str>>()
.join(",")
}
pub(crate) fn body_list<T: AsRef<str>>(name: &str, list: &[T]) -> Body<serde_json::Value> {
let list: Vec<_> = list.iter().map(|i| i.as_ref()).collect();
Body::Json(serde_json::json!({ name: list }))
}
pub use auth::{AuthCodeFlow, AuthCodePkceFlow, ClientCredsFlow};
pub use client::{AuthCodeClient, AuthCodePkceClient, ClientCredsClient};
pub use error::{Error, Result as SpotifyResult};
pub use oauth2::RedirectUrl;
/// Represents an empty API response.
pub struct Nil;
impl<'de> Deserialize<'de> for Nil {
fn deserialize<D>(_: D) -> std::result::Result<Self, D::Error>
where
D: Deserializer<'de>,
{
Ok(Nil)
}
}