Skip to content

Commit 1eeb32a

Browse files
committed
update builders, put utilities inside their own utility block
1 parent 478b2d5 commit 1eeb32a

File tree

2 files changed

+212
-95
lines changed

2 files changed

+212
-95
lines changed

src/main/kotlin/com/adamratzman/spotify/Builder.kt

Lines changed: 157 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -16,54 +16,40 @@ fun spotifyApi(block: SpotifyApiBuilderDsl.() -> Unit) = SpotifyApiBuilderDsl().
1616
* Spotify traditional Java style API builder
1717
*/
1818
class SpotifyApiBuilder(
19-
val clientId: String,
20-
val clientSecret: String,
21-
var redirectUri: String? = null,
22-
var authorizationCode: String? = null,
23-
var tokenString: String? = null,
24-
var token: Token? = null,
25-
var useCache: Boolean = true,
26-
var cacheLimit: Int? = 200,
27-
var automaticRefresh: Boolean = true,
28-
var retryWhenRateLimited: Boolean = false,
29-
var enableLogger: Boolean = false
19+
private var clientId: String,
20+
private var clientSecret: String
3021
) {
31-
/**
32-
* Instantiate the builder with the application [clientId] and [clientSecret]
33-
*/
34-
constructor(clientId: String, clientSecret: String) : this(clientId, clientSecret, null)
35-
36-
/**
37-
* Instantiate the builder with the application [clientId], [clientSecret], and whether to use a cache
38-
*/
39-
constructor(clientId: String, clientSecret: String, useCache: Boolean) : this(clientId, clientSecret, null, useCache = useCache)
22+
private var redirectUri: String? = null
23+
private var authorizationCode: String? = null
24+
private var tokenString: String? = null
25+
private var token: Token? = null
26+
private var useCache: Boolean = true
27+
private var cacheLimit: Int? = 200
28+
private var automaticRefresh: Boolean = true
29+
private var retryWhenRateLimited: Boolean = false
30+
private var enableLogger: Boolean = false
31+
private var testTokenValidity: Boolean = false
32+
private var enableAllUtilities: Boolean = false
4033

4134
/**
42-
* Instantiate the builder with the application [clientId], [clientSecret], and application
43-
* [redirectUri]
35+
* Set whether to enable all utilities ([automaticRefresh], [retryWhenRateLimited], [useCache], [enableLogger], [testTokenValidity])
4436
*/
45-
constructor(clientId: String, clientSecret: String, redirectUri: String) : this(clientId, clientSecret, redirectUri, null)
37+
fun enableAllUtilities(enableAllUtilities: Boolean) = apply { this.enableAllUtilities = enableAllUtilities }
4638

4739
/**
48-
* Instantiate the builder with the application [clientId], [clientSecret], application
49-
* [redirectUri], and an [authorizationCode]
40+
* After API creation, set whether to test whether the token is valid by performing a lightweight request
5041
*/
51-
constructor(clientId: String, clientSecret: String, redirectUri: String?, authorizationCode: String, useCache: Boolean) :
52-
this(clientId, clientSecret, redirectUri, authorizationCode, null, useCache = useCache)
42+
fun testTokenValidity(testTokenValidity: Boolean) = apply { this.testTokenValidity = testTokenValidity }
5343

5444
/**
55-
* Instantiate the builder with the application [clientId], [clientSecret], application
56-
* [redirectUri], and an access token string ([tokenString])
45+
* Set the application client id
5746
*/
58-
constructor(clientId: String, clientSecret: String, redirectUri: String?, tokenString: String) :
59-
this(clientId, clientSecret, redirectUri, null, tokenString)
47+
fun clientId(clientId: String) = apply { this.clientId = clientId }
6048

6149
/**
62-
* Instantiate the builder with the application [clientId], [clientSecret], application
63-
* [redirectUri], and a [token]
50+
* Set the application client secret
6451
*/
65-
constructor(clientId: String, clientSecret: String, redirectUri: String?, token: Token, useCache: Boolean) :
66-
this(clientId, clientSecret, redirectUri, null, null, token, useCache)
52+
fun clientSecret(clientSecret: String) = apply { this.clientSecret = clientSecret }
6753

6854
/**
6955
* Set whether to cache requests. Default: true
@@ -136,10 +122,15 @@ class SpotifyApiBuilder(
136122
token = this@SpotifyApiBuilder.token
137123
tokenString = this@SpotifyApiBuilder.tokenString
138124
}
139-
140-
automaticRefresh = this@SpotifyApiBuilder.automaticRefresh
141-
retryWhenRateLimited = this@SpotifyApiBuilder.retryWhenRateLimited
142-
enableLogger = this@SpotifyApiBuilder.enableLogger
125+
utilities {
126+
useCache = this@SpotifyApiBuilder.useCache
127+
cacheLimit = this@SpotifyApiBuilder.cacheLimit
128+
automaticRefresh = this@SpotifyApiBuilder.automaticRefresh
129+
retryWhenRateLimited = this@SpotifyApiBuilder.retryWhenRateLimited
130+
enableLogger = this@SpotifyApiBuilder.enableLogger
131+
testTokenValidity = this@SpotifyApiBuilder.testTokenValidity
132+
enableAllUtilities = this@SpotifyApiBuilder.enableAllUtilities
133+
}
143134
}.buildCredentialed()
144135

145136
/**
@@ -157,10 +148,15 @@ class SpotifyApiBuilder(
157148
tokenString = this@SpotifyApiBuilder.tokenString
158149
token = this@SpotifyApiBuilder.token
159150
}
160-
161-
automaticRefresh = this@SpotifyApiBuilder.automaticRefresh
162-
retryWhenRateLimited = this@SpotifyApiBuilder.retryWhenRateLimited
163-
enableLogger = this@SpotifyApiBuilder.enableLogger
151+
utilities {
152+
useCache = this@SpotifyApiBuilder.useCache
153+
cacheLimit = this@SpotifyApiBuilder.cacheLimit
154+
automaticRefresh = this@SpotifyApiBuilder.automaticRefresh
155+
retryWhenRateLimited = this@SpotifyApiBuilder.retryWhenRateLimited
156+
enableLogger = this@SpotifyApiBuilder.enableLogger
157+
testTokenValidity = this@SpotifyApiBuilder.testTokenValidity
158+
enableAllUtilities = this@SpotifyApiBuilder.enableAllUtilities
159+
}
164160
}.buildClient()
165161
}
166162

@@ -184,7 +180,7 @@ class SpotifyCredentialsBuilder {
184180
data class SpotifyCredentials(val clientId: String?, val clientSecret: String?, val redirectUri: String?)
185181

186182
/**
187-
* Authentication methods.
183+
* Authentication methods
188184
*
189185
* @property authorizationCode Only available when building [SpotifyClientAPI]. Spotify auth code
190186
* @property token Build the API using an existing token. If you're building [SpotifyClientAPI], this
@@ -197,28 +193,78 @@ class SpotifyUserAuthorizationBuilder(
197193
var authorizationCode: String? = null,
198194
var tokenString: String? = null,
199195
var token: Token? = null
196+
) {
197+
fun build() = if (authorizationCode == null && tokenString == null && token == null) throw IllegalArgumentException("An authorization method must be supplied")
198+
else SpotifyUserAuthorization(authorizationCode, tokenString, token)
199+
}
200+
201+
data class SpotifyUserAuthorization(
202+
val authorizationCode: String?,
203+
val tokenString: String?,
204+
val token: Token?
200205
)
201206

202207
/**
203-
* Spotify API mutable parameters
208+
* API Utilities
204209
*
205-
* @property credentials A holder for application-specific credentials
206-
* @property authentication A holder for authentication methods. At least one needs to be provided in order to create
207-
* a **client** api
208210
* @property useCache Set whether to cache requests. Default: true
209211
* @property cacheLimit The maximum amount of cached requests allowed at one time. Null means no limit
210212
* @property automaticRefresh Enable or disable automatic refresh of the Spotify access token
211213
* @property retryWhenRateLimited Set whether to block the current thread and wait until the API can retry the request
212214
* @property enableLogger Set whether to enable to the exception logger
215+
* @property testTokenValidity After API creation, test whether the token is valid by performing a lightweight request
216+
* @property enableAllUtilities Whether to enable all provided utilities
217+
*/
218+
class SpotifyUtilitiesBuilder(
219+
var useCache: Boolean = true,
220+
var cacheLimit: Int? = 200,
221+
var automaticRefresh: Boolean = true,
222+
var retryWhenRateLimited: Boolean = true,
223+
var enableLogger: Boolean = true,
224+
var testTokenValidity: Boolean = false,
225+
var enableAllUtilities: Boolean = false
226+
) {
227+
fun build() =
228+
if (enableAllUtilities)
229+
SpotifyUtilities(true,
230+
200,
231+
automaticRefresh = true,
232+
retryWhenRateLimited = true,
233+
enableLogger = true,
234+
testTokenValidity = true
235+
)
236+
else
237+
SpotifyUtilities(
238+
useCache,
239+
cacheLimit,
240+
automaticRefresh,
241+
retryWhenRateLimited,
242+
enableLogger,
243+
testTokenValidity
244+
)
245+
}
246+
247+
data class SpotifyUtilities(
248+
val useCache: Boolean,
249+
val cacheLimit: Int?,
250+
val automaticRefresh: Boolean,
251+
val retryWhenRateLimited: Boolean,
252+
val enableLogger: Boolean,
253+
val testTokenValidity: Boolean
254+
)
255+
256+
/**
257+
* Spotify API mutable parameters
258+
*
259+
* @property credentials A holder for application-specific credentials
260+
* @property authentication A holder for authentication methods. At least one needs to be provided in order to create
261+
* a **client** api
262+
* @property utilities A holder for API utilities such as caching and token refresh
213263
*/
214264
class SpotifyApiBuilderDsl {
215-
private var credentials: SpotifyCredentials = SpotifyCredentials(null, null, null)
216-
private var authentication = SpotifyUserAuthorizationBuilder()
217-
var useCache: Boolean = true
218-
var cacheLimit: Int? = 200
219-
var automaticRefresh: Boolean = true
220-
var retryWhenRateLimited: Boolean = false
221-
var enableLogger: Boolean = false
265+
private var credentials: SpotifyCredentials = SpotifyCredentialsBuilder().build()
266+
private var authentication: SpotifyUserAuthorization = SpotifyUserAuthorizationBuilder().build()
267+
private var utilities: SpotifyUtilities = SpotifyUtilitiesBuilder().build()
222268

223269
/**
224270
* A block in which Spotify application credentials (accessible via the Spotify [dashboard](https://developer.spotify.com/dashboard/applications))
@@ -233,7 +279,14 @@ class SpotifyApiBuilderDsl {
233279
* or build [SpotifyAPI] using a refresh token
234280
*/
235281
fun authentication(block: SpotifyUserAuthorizationBuilder.() -> Unit) {
236-
authentication = SpotifyUserAuthorizationBuilder().apply(block)
282+
authentication = SpotifyUserAuthorizationBuilder().apply(block).build()
283+
}
284+
285+
/**
286+
* Allows you to override default values for caching, token refresh, and logging
287+
*/
288+
fun utilities(block: SpotifyUtilitiesBuilder.() -> Unit) {
289+
utilities = SpotifyUtilitiesBuilder().apply(block).build()
237290
}
238291

239292
/**
@@ -268,8 +321,17 @@ class SpotifyApiBuilderDsl {
268321
}
269322
return when {
270323
authentication.token != null -> {
271-
SpotifyAppAPI(clientId ?: "not-set", clientSecret
272-
?: "not-set", authentication.token!!, useCache, cacheLimit, false, retryWhenRateLimited, enableLogger)
324+
SpotifyAppAPI(
325+
clientId ?: "not-set",
326+
clientSecret ?: "not-set",
327+
authentication.token!!,
328+
utilities.useCache,
329+
utilities.cacheLimit,
330+
false,
331+
utilities.retryWhenRateLimited,
332+
utilities.enableLogger,
333+
utilities.testTokenValidity
334+
)
273335
}
274336
authentication.tokenString != null -> {
275337
SpotifyAppAPI(
@@ -279,17 +341,28 @@ class SpotifyApiBuilderDsl {
279341
authentication.tokenString!!, "client_credentials",
280342
60000, null, null
281343
),
282-
useCache,
283-
cacheLimit,
284-
automaticRefresh,
285-
retryWhenRateLimited,
286-
enableLogger
344+
utilities.useCache,
345+
utilities.cacheLimit,
346+
false,
347+
utilities.retryWhenRateLimited,
348+
utilities.enableLogger,
349+
utilities.testTokenValidity
287350
)
288351
}
289352
else -> try {
290353
if (clientId == null || clientSecret == null) throw IllegalArgumentException("Illegal credentials provided")
291354
val token = getCredentialedToken(clientId, clientSecret, null)
292-
SpotifyAppAPI(clientId, clientSecret, token, useCache, cacheLimit, automaticRefresh, retryWhenRateLimited, enableLogger)
355+
SpotifyAppAPI(
356+
clientId,
357+
clientSecret,
358+
token,
359+
utilities.useCache,
360+
utilities.cacheLimit,
361+
false,
362+
utilities.retryWhenRateLimited,
363+
utilities.enableLogger,
364+
utilities.testTokenValidity
365+
)
293366
} catch (e: Exception) {
294367
throw SpotifyException("Invalid credentials provided in the login process", e)
295368
}
@@ -311,7 +384,8 @@ class SpotifyApiBuilderDsl {
311384
*/
312385
fun buildClient(): SpotifyClientAPI =
313386
buildClient(
314-
authentication.authorizationCode, authentication.tokenString,
387+
authentication.authorizationCode,
388+
authentication.tokenString,
315389
authentication.token
316390
)
317391

@@ -322,8 +396,6 @@ class SpotifyApiBuilderDsl {
322396
* @param authorizationCode Spotify authorization code retrieved after authentication
323397
* @param tokenString Spotify authorization token
324398
* @param token [Token] object (useful if you already have exchanged an authorization code yourself
325-
* @param automaticRefresh automatically refresh the token. otherwise, the authorization will eventually expire. **only** valid when
326-
* [authorizationCode] or [token] is provided
327399
*/
328400
private fun buildClient(
329401
authorizationCode: String? = null,
@@ -356,12 +428,13 @@ class SpotifyApiBuilderDsl {
356428
clientId,
357429
clientSecret,
358430
response.body.toObject(null),
359-
automaticRefresh,
360-
redirectUri ?: throw IllegalArgumentException(),
361-
useCache,
362-
cacheLimit,
363-
retryWhenRateLimited,
364-
enableLogger
431+
utilities.automaticRefresh,
432+
redirectUri ?: throw IllegalArgumentException("No redirect uri provided"),
433+
utilities.useCache,
434+
utilities.cacheLimit,
435+
utilities.retryWhenRateLimited,
436+
utilities.enableLogger,
437+
utilities.testTokenValidity
365438
)
366439
} catch (e: Exception) {
367440
throw SpotifyException("Invalid credentials provided in the login process", e)
@@ -370,12 +443,13 @@ class SpotifyApiBuilderDsl {
370443
clientId ?: "not-set",
371444
clientSecret ?: "not-set",
372445
token,
373-
automaticRefresh,
446+
utilities.automaticRefresh,
374447
redirectUri ?: "not-set",
375-
useCache,
376-
cacheLimit,
377-
retryWhenRateLimited,
378-
enableLogger
448+
utilities.useCache,
449+
utilities.cacheLimit,
450+
utilities.retryWhenRateLimited,
451+
utilities.enableLogger,
452+
utilities.testTokenValidity
379453
)
380454
tokenString != null -> SpotifyClientAPI(
381455
clientId ?: "not-set",
@@ -389,10 +463,11 @@ class SpotifyApiBuilderDsl {
389463
),
390464
false,
391465
redirectUri ?: "not-set",
392-
useCache,
393-
cacheLimit,
394-
retryWhenRateLimited,
395-
enableLogger
466+
utilities.useCache,
467+
utilities.cacheLimit,
468+
utilities.retryWhenRateLimited,
469+
utilities.enableLogger,
470+
utilities.testTokenValidity
396471
)
397472
else -> throw IllegalArgumentException(
398473
"At least one of: authorizationCode, tokenString, or token must be provided " +

0 commit comments

Comments
 (0)