Skip to content

Commit bb3fa8e

Browse files
committed
update documentation
1 parent af6b6b2 commit bb3fa8e

File tree

4 files changed

+225
-42
lines changed

4 files changed

+225
-42
lines changed

README.md

Lines changed: 218 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ repositories {
1414
jcenter()
1515
}
1616
17-
compile group: 'com.adamratzman', name: 'spotify-api-kotlin-core', version: '3.2.08'
17+
compile group: 'com.adamratzman', name: 'spotify-api-kotlin-core', version: '3.2.10'
1818
```
1919

2020
### Android
@@ -54,20 +54,25 @@ If you have a question, you can:
5454
3. Contact me using **Adam#9261** on [Discord](https://discordapp.com)
5555

5656
## Creating a new api instance
57-
To decide which api you need (SpotifyAppApi, SpotifyClientApi, SpotifyImplicitGrantApi), please refer to
58-
https://developer.spotify.com/documentation/general/guides/authorization-guide/. In general:
57+
To decide which api you need (SpotifyAppApi, SpotifyClientApi, SpotifyImplicitGrantApi), you can refer
58+
to the sections below or the [Spotify authorization guide](https://developer.spotify.com/documentation/general/guides/authorization-guide/). In general:
5959
- If you don't need client resources, use SpotifyAppApi
6060
- If you're using the api in a backend application, use SpotifyClientApi (with or without PKCE)
6161
- If you're using the api in Kotlin/JS browser, use SpotifyImplicitGrantApi
62-
- If you need access to client resources in an Android or other application, use SpotifyClientApi with PKCe
62+
- If you need access to client resources in an Android or other application, use SpotifyClientApi with PKCE
6363

6464

6565
### SpotifyAppApi
66-
This provides access only to public Spotify endpoints. By default, the SpotifyApi `Token` automatically regenerates when needed. This can be changed
67-
through the `automaticRefresh` parameter in all builders.
66+
This provides access only to public Spotify endpoints.
67+
Use this when you have a server-side application. Note that implicit grant authorization
68+
provides a higher api ratelimit, so consider using implicit grant if your application has
69+
significant usage.
70+
71+
By default, the SpotifyApi `Token` automatically regenerates when needed.
72+
This can be changed by overriding the `automaticRefresh` builder setting.
6873

6974
There are four exposed builders, depending on the level of control you need over api creation.
70-
Please see the [spotifyAppApi builder docs](https://adamint.github.io/spotify-web-api-kotlin/docs/spotify-web-api-kotlin/com.adamratzman.spotify/spotify-app-api.html) for a full list of available builders.
75+
Please see the [spotifyAppApi builder docs](https://adamint.github.io/spotify-web-api-kotlin/com.adamratzman.spotify-web-api-kotlin/com.adamratzman.spotify/spotify-app-api.html) for a full list of available builders.
7176

7277
You will need:
7378
- Spotify application client id
@@ -80,24 +85,189 @@ val api = spotifyAppApi("clientId", "clientSecret").build() // create and build
8085
println(api.browse.getNewReleases().complete()) // use it
8186
```
8287

83-
Example creation, using an existing Token
84-
88+
Example creation, using an existing Token and setting automatic token refresh to false
89+
```kotlin
90+
val token = spotifyAppApi(spotifyClientId, spotifyClientSecret).build().token
91+
val api = spotifyAppApi(
92+
"clientId",
93+
"clientSecret",
94+
token,
95+
SpotifyApiOptionsBuilder(
96+
automaticRefresh = false
97+
)
98+
)
99+
println(api.browse.getNewReleases().complete()) // use it
100+
```
85101

86102
### SpotifyClientApi
87-
The `SpotifyClientApi` is a superset of `SpotifyApi`; thus, you have access to all `SpotifyApi` methods in `SpotifyClientApi`.
88-
This library does not provide a method to retrieve the code from your callback url; you must implement that with a web server.
103+
The `SpotifyClientApi` is a superset of `SpotifyApi`; thus, nothing changes if you want to
104+
access public data.
105+
This library does not provide a method to retrieve the code from your callback url; instead,
106+
you must implement that with a web server.
107+
Automatic refresh is available *only* when building with an authorization code or a
108+
`Token` object. Otherwise, it will expire `Token.expiresIn` seconds after creation.
89109

90110
Make sure your application has requested the proper [Scopes](https://developer.spotify.com/web-api/using-spotifyScopes/) in order to
91-
ensure proper function of this library.
111+
ensure proper function of this library. The api option `requiredScopes` allows you to verify
112+
that a client has actually authorized with the scopes you are expecting.
92113

93-
Its automatic refresh ability is available *only* when building with
94-
an authorization code or a `Token` object. Otherwise, it will expire `Token.expiresIn` seconds after creation.
114+
You will need:
115+
- Spotify application client id
116+
- Spotify application client secret (if not using PKCE)
117+
- Spotify application redirect uri
118+
- To choose which client authorization method (PKCE or non-PKCE) to use
119+
120+
#### PKCE
121+
Use the PKCE builders and helper methods if you are using the Spotify client authorization PKCE flow.
122+
Building via PKCE returns a `SpotifyClientApi` which has modified refresh logic.
123+
124+
Use cases:
125+
1. You are using this library in an application (likely Android), or do not want to expose the client secret.
126+
127+
To learn more about the PKCE flow, please read the [Spotify authorization guide](https://developer.spotify.com/documentation/general/guides/authorization-guide/#implicit-grant-flow).
128+
Some highlights about the flow are:
129+
- It is refreshable, but each refresh token can only be used once. This library handles token refresh automatically by default
130+
- It does not require a client secret; instead, a set redirect uri and a random code verifier
131+
are used to verify the authenticity of the authorization.
132+
- A code verifier is required. The code verifier is "*a cryptographically random string between 43 and 128 characters in length.
133+
It can contain letters, digits, underscores, periods, hyphens, or tildes.*"
134+
- A code challenge is required. "*In order to generate the code challenge, your app should
135+
hash the code verifier using the SHA256 algorithm. Then, base64url encode the hash that you generated.*"
136+
- When creating a pkce api instance, the code verifier is passed in by you and compared to
137+
the code challenge used to authorize the user.
138+
139+
This library contains helpful methods that can be used to simplify the PKCE authorization process.
140+
This includes `getSpotifyPkceCodeChallenge` (not available in the Kotlin/JS target), which SHA256 hashes and base64url encodes the code
141+
challenge, and `getPkceAuthorizationUrl`, which allows you to generate an easy authorization url for PKCE flow.
142+
143+
Please see the [spotifyClientPkceApi builder docs](https://adamint.github.io/spotify-web-api-kotlin/com.adamratzman.spotify-web-api-kotlin/com.adamratzman.spotify/spotify-client-pkce-api.html) for a full list of available builders.
144+
145+
**Takeaway**: Use PKCE authorization flow in applications where you cannot secure the client secret.
146+
147+
To get a PKCE authorization url, to which you can redirect a user, you can use the `getPkceAuthorizationUrl`
148+
top-level method. An example is shown below, requesting 4 different scopes.
149+
```kotlin
150+
val codeVerifier = "thisisaveryrandomalphanumericcodeverifierandisgreaterthan43characters"
151+
val codeChallenge = getSpotifyPkceCodeChallenge(codeVerifier) // helper method
152+
val url: String = getPkceAuthorizationUrl(
153+
SpotifyScope.PLAYLIST_READ_PRIVATE,
154+
SpotifyScope.PLAYLIST_MODIFY_PRIVATE,
155+
SpotifyScope.USER_FOLLOW_READ,
156+
SpotifyScope.USER_LIBRARY_MODIFY,
157+
clientId = "clientId",
158+
redirectUri = "your-redirect-uri",
159+
codeChallenge = codeChallenge
160+
)
161+
```
162+
163+
There is also an optional parameter `state`, which helps you verify the authorization.
164+
165+
**Note**: If you want automatic token refresh, you need to pass in your application client id and redirect uri
166+
when using the `spotifyClientPkceApi`.
167+
168+
##### Example: A user has authorized your application. You now have the authorization code obtained after the user was redirected back to your application. You want to create a new `SpotifyClientApi`.
169+
```kotlin
170+
val codeVerifier = "thisisaveryrandomalphanumericcodeverifierandisgreaterthan43characters"
171+
val code: String = ...
172+
val api = spotifyClientPkceApi(
173+
"clientId", // optional. include for token refresh
174+
"your-redirect-uri", // optional. include for token refresh
175+
code,
176+
codeVerifier, // the same code verifier you used to generate the code challenge
177+
SpotifyApiOptionsBuilder(
178+
retryWhenRateLimited = false
179+
)
180+
).build()
181+
println(api.library.getSavedTracks().complete().take(10).filterNotNull().map { it.track.name })
182+
```
183+
184+
#### Non-PKCE (backend applications, requires client secret)
185+
To get a non-PKCE authorization url, to which you can redirect a user, you can use the `getSpotifyAuthorizationUrl`
186+
top-level method. An example is shown below, requesting 4 different scopes.
187+
```kotlin
188+
val url: String = getSpotifyAuthorizationUrl(
189+
SpotifyScope.PLAYLIST_READ_PRIVATE,
190+
SpotifyScope.PLAYLIST_MODIFY_PRIVATE,
191+
SpotifyScope.USER_FOLLOW_READ,
192+
SpotifyScope.USER_LIBRARY_MODIFY,
193+
clientId = "clientId",
194+
redirectUri = "your-redirect-uri",
195+
state = "your-special-state" // optional
196+
)
197+
```
198+
There are also several optional parameters, allowing you to set whether the authorization url is meant
199+
for implicit grant flow, the state, and whether a re-authorization dialog should be shown to users.
200+
201+
There are several exposed builders, depending on the level of control you need over api creation.
202+
Please see the [spotifyClientApi builder docs](https://adamint.github.io/spotify-web-api-kotlin/com.adamratzman.spotify-web-api-kotlin/com.adamratzman.spotify/spotify-client-api.html) for a full list of available builders.
203+
204+
##### Example: You've redirected the user back to your web server and have an authorization code (code).
205+
In this example, automatic token refresh is turned on by default.
206+
```kotlin
207+
val authCode = ""
208+
val api = spotifyClientApi(
209+
"clientId",
210+
"clientSecret",
211+
"your-redirect-uri",
212+
authCode
213+
).build() // create and build api
214+
println(api.personalization.getTopTracks(limit = 5).complete().items.map { it.name }) // print user top tracks
215+
```
216+
217+
##### Example: You've saved a user's token from previous authorization and need to create an api instance.
218+
In this case, if you provide a client id to the builder, automatic token refresh will also be turned on.
219+
```kotlin
220+
val token: Token = ... // your existing token
221+
val api = spotifyClientApi(
222+
"clientId",
223+
"clientSecret",
224+
"your-redirect-uri",
225+
token,
226+
SpotifyApiOptionsBuilder(
227+
onTokenRefresh = {
228+
println("Token refreshed at ${System.currentTimeMillis()}")
229+
}
230+
)
231+
).build()
232+
println(api.personalization.getTopTracks(limit = 5).complete().items.map { it.name })
233+
```
95234

96-
Please see the [spotifyClientApi builder docs](https://adamint.github.io/spotify-web-api-kotlin/docs/spotify-web-api-kotlin/com.adamratzman.spotify/spotify-client-api.html) for a full list of available builders, or the client [samples](https://github.com/adamint/spotify-web-api-kotlin/tree/master/samples/jvm/src/main/kotlin/clientApi).
97235

98236
### SpotifyImplicitGrantApi
99-
Instantiate this api only if you are using the Spotify implicit grant flow. It is a superset of `SpotifyClientApi`.
100-
Please see the [spotifyImplicitGrantApi builder docs](https://adamint.github.io/spotify-web-api-kotlin/docs/spotify-web-api-kotlin/com.adamratzman.spotify/spotify-implicit-grant-api.html) for a full list of available builders, or the implicit grant [samples (tbd)]().
237+
Use the `SpotifyImplicitGrantApi` if you are using the Spotify implicit grant flow.
238+
`SpotifyImplicitGrantApi` is a superset of `SpotifyClientApi`.
239+
Unlike the other builders, the `spotifyImplicitGrantApi` builder method directly returns
240+
a `SpotifyImplicitGrantApi` instead of an api builder.
241+
242+
Use cases:
243+
1. You are using the **Kotlin/JS** target for this library.
244+
2. Your frontend Javascript passes the token received through the implicit grant flow to your
245+
backend, where it is then used to create an api instance.
246+
247+
To learn more about the implicit grant flow, please read the [Spotify authorization guide](https://developer.spotify.com/documentation/general/guides/authorization-guide/#implicit-grant-flow).
248+
Some highlights about the flow are:
249+
- It is non-refreshable
250+
- It is client-side
251+
- It does not require a client secret
252+
253+
Please see the [spotifyImplicitGrantApi builder docs](https://adamint.github.io/spotify-web-api-kotlin/com.adamratzman.spotify-web-api-kotlin/com.adamratzman.spotify/spotify-implicit-grant-api.html) for a full list of available builders.
254+
255+
The Kotlin/JS target contains the `parseSpotifyCallbackHashToToken` method, which will parse the hash
256+
for the current url into a Token object, with which you can then instantiate the api.
257+
258+
**Takeaway**: There are two ways to use implicit grant flow, browser-side only and browser and
259+
server. This library provides easy access for both.
260+
261+
##### Example
262+
```kotlin
263+
val token: Token = ...
264+
val api = spotifyImplicitGrantApi(
265+
null,
266+
null,
267+
token
268+
) // create api. there is no need to build it
269+
println(api.personalization.getTopArtists(limit = 1).complete()[0].name) // use it
270+
```
101271

102272
### SpotifyApiBuilder Block & setting API options
103273
There are three pluggable blocks in each api's corresponding builder
@@ -123,6 +293,9 @@ most of the default values either allow for significant performance or feature e
123293
- `allowBulkRequests`: Allow splitting too-large requests into smaller, allowable api requests. Default: true
124294
- `requestTimeoutMillis`: The maximum time, in milliseconds, before terminating an http request. Default: 100000ms
125295
- `refreshTokenProducer`: Provide if you want to use your own logic when refreshing a Spotify token.
296+
- `requiredScopes`: Scopes that your application requires to function (only applicable to `SpotifyClientApi` and `SpotifyImplicitGrantApi`).
297+
This verifies that the token your user authorized with actually contains the scopes your
298+
application needs to function.
126299

127300
Notes:
128301
- Unless you have a good reason otherwise, `useCache` should be true
@@ -131,10 +304,29 @@ Notes:
131304
- `allowBulkRequests` for example, lets you query 80 artists in one wrapper call by splitting it into 50 artists + 30 artists
132305
- `refreshTokenProducer` is useful when you want to re-authorize with the Spotify Auth SDK or elsewhere
133306

134-
### Tips
135-
-
136-
137-
307+
### Using the API
308+
APIs available in all `SpotifyApi` instances, including `SpotifyClientApi` and `SpotifyImplicitGrantApi`:
309+
- `SearchApi` (searching items)
310+
- `AlbumApi` (get information about albums)
311+
- `BrowseApi` (browse new releases, featured playlists, categories, and recommendations)
312+
- `ArtistApi` (get information about artists)
313+
- `PlaylistApi` (get information about playlists)
314+
- `UserApi` (get public information about users on Spotify)
315+
- `TrackApi` (get information about tracks)
316+
- `FollowingApi` (check whether users follow playlists)
317+
318+
APIs available only in `SpotifyClientApi` and `SpotifyImplicitGrantApi` instances:
319+
- `ClientSearchApi` (all the methods in `SearchApi`, and searching shows and episodes)
320+
- `EpisodeApi` (get information about episodes)
321+
- `ShowApi` (get information about shows)
322+
- `ClientPlaylistApi` (all the methods in `PlaylistApi`, and get and manage user playlists)
323+
- `ClientProfileApi` (all the methods in `UserApi`, and get the user profile, depending on scopes)
324+
- `ClientFollowingApi` (all the methods in `FollowingApi`, and get and manage following of playlists, artists, and users)
325+
- `ClientPersonalizationApi` (get user top tracks and artists)
326+
- `ClientLibraryApi` (get and manage saved tracks and albums)
327+
- `ClientPlayerApi` (view and control Spotify playback)
328+
329+
## Tips
138330

139331
### Building the API
140332
The easiest way to build the API is synchronously using .build() after a builder
@@ -143,7 +335,7 @@ The easiest way to build the API is synchronously using .build() after a builder
143335
spotifyAppApi(clientId, clientSecret).build()
144336
```
145337

146-
You can also build the API asynchronously using kotlin coroutines!
338+
You can also build the API asynchronously using Kotlin coroutines.
147339
```kotlin
148340
runBlocking {
149341
spotifyAppApi(clientId, clientSecret).buildAsyncAt(this) { api ->
@@ -152,7 +344,7 @@ runBlocking {
152344
}
153345
```
154346

155-
## What is the SpotifyRestAction class?
347+
### What is the SpotifyRestAction class?
156348
Abstracting requests into a `SpotifyRestAction` class allows for a lot of flexibility in sending and receiving requests.
157349
This class includes options for asynchronous and blocking execution in all endpoints. However,
158350
due to this, you **must** call one of the provided methods in order for the call
@@ -171,13 +363,12 @@ time, this will likely be accurate within a few milliseconds.
171363
- `asFuture()` transforms the supplier into a `CompletableFuture` (only JVM)
172364

173365
### SpotifyRestPagingAction
174-
Separate from, but a superset of SpotifyRestAction, this specialized implementation of RestActions is
175-
just for [AbstractPagingObject] (`PagingObject` and `CursorBasedPagingObject`). This class gives you the same functionality as SpotifyRestAction,
366+
Separate from, but a superset of SpotifyRestAction, this specialized implementation of RestActions includes extensions
367+
for `AbstractPagingObject` (`PagingObject` and `CursorBasedPagingObject`). This class gives you the same functionality as SpotifyRestAction,
176368
but you also have the ability to retrieve *all* of its items or linked PagingObjects, or a *subset* of its items or linked PagingObjects with one call, with
177369
a single method call to `getAllItems()` or `getAllPagingObjects()`, or `getWithNext(total: Int, context: CoroutineContext = Dispatchers.Default)` or `getWithNextItems(total: Int, context: CoroutineContext = Dispatchers.Default)` respectively
178370

179-
180-
## Using the Library
371+
## Design Notes
181372
### The benefits of LinkedResults, PagingObjects, and Cursor-based Paging Objects
182373
Spotify provides these three object models in order to simplify our lives as developers. So let's see what we
183374
can do with them!

build.gradle.kts

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,7 @@ buildscript {
3131
}
3232

3333
group = "com.adamratzman"
34-
version = "3.2.08"
35-
36-
/*java {
37-
withSourcesJar()
38-
withJavadocJar()
39-
}
40-
*/
34+
version = "3.2.10"
4135

4236
tasks.withType<Test> {
4337
this.testLogging {
@@ -52,7 +46,6 @@ android {
5246
targetCompatibility = JavaVersion.VERSION_1_8
5347
}
5448
packagingOptions {
55-
// exclude("META-INF/*.kotlin_module")
5649
exclude("META-INF/*.md")
5750
}
5851
defaultConfig {
@@ -324,12 +317,6 @@ tasks {
324317
}
325318
}
326319

327-
/* val javadocJar by getting(Jar::class) {
328-
dependsOn.add(javadoc)
329-
archiveClassifier.set("javadoc")
330-
from(javadoc)
331-
}*/
332-
333320
spotless {
334321
kotlin {
335322
target("**/*.kt")

src/commonMain/kotlin/com.adamratzman.spotify/endpoints/client/ClientLibraryApi.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ import kotlinx.serialization.builtins.serializer
2424
typealias ClientLibraryAPI = ClientLibraryApi
2525

2626
/**
27-
* Endpoints for retrieving information about, and managing, tracks that the current user has saved in their “Your Music” library.
27+
* Endpoints for retrieving information about, and managing, tracks and albums that the current user has saved in their “Your Music” library.
2828
*
2929
* **[Api Reference](https://developer.spotify.com/documentation/web-api/reference/library/)**
3030
*/

src/commonMain/kotlin/com.adamratzman.spotify/endpoints/public/EpisodeApi.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,11 @@ import com.adamratzman.spotify.models.serialization.toObject
1515
import com.adamratzman.spotify.utils.Market
1616
import com.adamratzman.spotify.utils.catch
1717

18+
/**
19+
* Endpoints for retrieving information about one or more episodes from the Spotify catalog.
20+
*
21+
* **[Api Reference](https://developer.spotify.com/documentation/web-api/reference/episodes/)**
22+
*/
1823
class EpisodeApi(api: GenericSpotifyApi) : SpotifyEndpoint(api) {
1924
/**
2025
* Get Spotify catalog information for a single episode identified by its unique Spotify ID.

0 commit comments

Comments
 (0)