Skip to content

Commit

Permalink
AutoClose ApiClient, and fix all warnings (#640)
Browse files Browse the repository at this point in the history
  • Loading branch information
nomisRev authored Jan 17, 2024
1 parent cae09e8 commit c598fc7
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 59 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,9 @@ import io.ktor.client.statement.HttpResponse
import io.ktor.http.*
import io.ktor.http.content.PartData
import io.ktor.serialization.kotlinx.json.json
import kotlin.Unit
import kotlinx.serialization.json.Json

open class ApiClient(val baseUrl: String) {
open class ApiClient(val baseUrl: String) : AutoCloseable {

lateinit var client: HttpClient

Expand Down Expand Up @@ -49,7 +48,7 @@ open class ApiClient(val baseUrl: String) {
this.client = httpClient
}

private val authentications: kotlin.collections.Map<String, Authentication> by lazy {
private val authentications: Map<String, Authentication> by lazy {
mapOf("ApiKeyAuth" to HttpBearerAuth("bearer"))
}

Expand All @@ -69,9 +68,8 @@ open class ApiClient(val baseUrl: String) {
* @param username Username
*/
fun setUsername(username: String) {
val auth =
authentications?.values?.firstOrNull { it is HttpBasicAuth } as HttpBasicAuth?
?: throw Exception("No HTTP basic authentication configured")
val auth = authentications.values.firstOrNull { it is HttpBasicAuth } as HttpBasicAuth?
requireNotNull(auth) { "No HTTP basic authentication configured" }
auth.username = username
}

Expand All @@ -81,9 +79,8 @@ open class ApiClient(val baseUrl: String) {
* @param password Password
*/
fun setPassword(password: String) {
val auth =
authentications?.values?.firstOrNull { it is HttpBasicAuth } as HttpBasicAuth?
?: throw Exception("No HTTP basic authentication configured")
val auth = authentications.values.firstOrNull { it is HttpBasicAuth } as HttpBasicAuth?
requireNotNull(auth) { "No HTTP basic authentication configured" }
auth.password = password
}

Expand All @@ -95,9 +92,10 @@ open class ApiClient(val baseUrl: String) {
*/
fun setApiKey(apiKey: String, paramName: String? = null) {
val auth =
authentications?.values?.firstOrNull {
authentications.values.firstOrNull {
it is ApiKeyAuth && (paramName == null || paramName == it.paramName)
} as ApiKeyAuth? ?: throw Exception("No API key authentication configured")
} as ApiKeyAuth?
requireNotNull(auth) { "No API key authentication configured" }
auth.apiKey = apiKey
}

Expand All @@ -109,9 +107,10 @@ open class ApiClient(val baseUrl: String) {
*/
fun setApiKeyPrefix(apiKeyPrefix: String, paramName: String? = null) {
val auth =
authentications?.values?.firstOrNull {
authentications.values.firstOrNull {
it is ApiKeyAuth && (paramName == null || paramName == it.paramName)
} as ApiKeyAuth? ?: throw Exception("No API key authentication configured")
} as ApiKeyAuth?
requireNotNull(auth) { "No API key authentication configured" }
auth.apiKeyPrefix = apiKeyPrefix
}

Expand All @@ -121,9 +120,8 @@ open class ApiClient(val baseUrl: String) {
* @param accessToken Access token
*/
fun setAccessToken(accessToken: String) {
val auth =
authentications?.values?.firstOrNull { it is OAuth } as OAuth?
?: throw Exception("No OAuth2 authentication configured")
val auth = authentications.values.firstNotNullOfOrNull { it as? OAuth }
requireNotNull(auth) { "No OAuth2 authentication configured" }
auth.accessToken = accessToken
}

Expand All @@ -133,40 +131,39 @@ open class ApiClient(val baseUrl: String) {
* @param bearerToken The bearer token.
*/
fun setBearerToken(bearerToken: String) {
val auth =
authentications?.values?.firstOrNull { it is HttpBearerAuth } as HttpBearerAuth?
?: throw Exception("No Bearer authentication configured")
val auth = authentications.values.firstNotNullOfOrNull { it as? HttpBearerAuth }
requireNotNull(auth) { "No Bearer authentication configured" }
auth.bearerToken = bearerToken
}

protected suspend fun <T : Any?> multipartFormRequest(
protected suspend fun <T> multipartFormRequest(
requestConfig: RequestConfig<T>,
body: kotlin.collections.List<PartData>?,
authNames: kotlin.collections.List<String>
body: List<PartData>?,
authNames: List<String>
): HttpResponse {
return request(requestConfig, MultiPartFormDataContent(body ?: listOf()), authNames)
}

protected suspend fun <T : Any?> urlEncodedFormRequest(
protected suspend fun <T> urlEncodedFormRequest(
requestConfig: RequestConfig<T>,
body: Parameters?,
authNames: kotlin.collections.List<String>
authNames: List<String>
): HttpResponse {
return request(requestConfig, FormDataContent(body ?: Parameters.Empty), authNames)
}

protected suspend fun <T : Any?> jsonRequest(
protected suspend fun <T> jsonRequest(
requestConfig: RequestConfig<T>,
body: Any? = null,
authNames: kotlin.collections.List<String>
authNames: List<String>
): HttpResponse = request(requestConfig, body, authNames)

protected suspend fun <T : Any?> request(
protected suspend fun <T> request(
requestConfig: RequestConfig<T>,
body: Any? = null,
authNames: kotlin.collections.List<String>
authNames: List<String>
): HttpResponse {
requestConfig.updateForAuth<T>(authNames)
requestConfig.updateForAuth(authNames)
val headers = requestConfig.headers

return client.request {
Expand All @@ -191,21 +188,20 @@ open class ApiClient(val baseUrl: String) {
}
}

fun <T : Any?> RequestConfig<T>.updateForAuth(authNames: kotlin.collections.List<String>) {
fun <T> RequestConfig<T>.updateForAuth(authNames: List<String>) {
for (authName in authNames) {
val auth =
authentications?.get(authName) ?: throw Exception("Authentication undefined: $authName")
val auth = requireNotNull(authentications[authName]) { "Authentication undefined: $authName" }
auth.apply(query, headers)
}
}

fun URLBuilder.appendPath(components: kotlin.collections.List<String>): URLBuilder = apply {
private fun URLBuilder.appendPath(components: List<String>): URLBuilder = apply {
encodedPath =
encodedPath.trimEnd('/') +
components.joinToString("/", prefix = "/") { it.encodeURLQueryComponent() }
}

val RequestMethod.httpMethod: HttpMethod
private val RequestMethod.httpMethod: HttpMethod
get() =
when (this) {
RequestMethod.DELETE -> HttpMethod.Delete
Expand All @@ -216,4 +212,8 @@ open class ApiClient(val baseUrl: String) {
RequestMethod.POST -> HttpMethod.Post
RequestMethod.OPTIONS -> HttpMethod.Options
}

override fun close() {
client.close()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import io.ktor.client.statement.HttpResponse
import io.ktor.http.*
import io.ktor.http.content.PartData
import io.ktor.serialization.kotlinx.json.json
import kotlin.Unit
import kotlin.time.Duration.Companion.seconds
import kotlin.time.DurationUnit
import kotlinx.serialization.json.Json
Expand All @@ -25,7 +24,7 @@ import {{packageName}}.auth.*

{{#nonPublicApi}}internal {{/nonPublicApi}}open class ApiClient(
val baseUrl: String
) {
) : AutoCloseable {
lateinit var client: HttpClient
Expand Down Expand Up @@ -59,7 +58,7 @@ import {{packageName}}.auth.*
}

{{#hasAuthMethods}}
private val authentications: kotlin.collections.Map<String, Authentication> by lazy {
private val authentications: Map<String, Authentication> by lazy {
mapOf({{#authMethods}}{{#isBasic}}{{#isBasicBasic}}
"{{name}}" to HttpBasicAuth(){{/isBasicBasic}}{{#isBasicBearer}}
"{{name}}" to HttpBearerAuth("{{scheme}}"){{/isBasicBearer}}{{/isBasic}}{{#isApiKey}}
Expand All @@ -68,7 +67,7 @@ import {{packageName}}.auth.*
}
{{/hasAuthMethods}}
{{^hasAuthMethods}}
private val authentications: kotlin.collections.Map<String, Authentication>? = null
private val authentications: Map<String, Authentication>? = null
{{/hasAuthMethods}}

{{#nonPublicApi}}internal {{/nonPublicApi}}companion object {
Expand All @@ -87,8 +86,9 @@ import {{packageName}}.auth.*
* @param username Username
*/
fun setUsername(username: String) {
val auth = authentications?.values?.firstOrNull { it is HttpBasicAuth } as HttpBasicAuth?
?: throw Exception("No HTTP basic authentication configured")
val auth =
authentications.values.firstOrNull { it is HttpBasicAuth } as HttpBasicAuth?
requireNotNull(auth) { "No HTTP basic authentication configured" }
auth.username = username
}

Expand All @@ -98,8 +98,9 @@ import {{packageName}}.auth.*
* @param password Password
*/
fun setPassword(password: String) {
val auth = authentications?.values?.firstOrNull { it is HttpBasicAuth } as HttpBasicAuth?
?: throw Exception("No HTTP basic authentication configured")
val auth =
authentications.values.firstOrNull { it is HttpBasicAuth } as HttpBasicAuth?
requireNotNull(auth) { "No HTTP basic authentication configured" }
auth.password = password
}

Expand All @@ -110,8 +111,9 @@ import {{packageName}}.auth.*
* @param paramName The name of the API key parameter, or null or set the first key.
*/
fun setApiKey(apiKey: String, paramName: String? = null) {
val auth = authentications?.values?.firstOrNull { it is ApiKeyAuth && (paramName == null || paramName == it.paramName)} as ApiKeyAuth?
?: throw Exception("No API key authentication configured")
val auth =
authentications.values.firstOrNull { it is ApiKeyAuth && (paramName == null || paramName == it.paramName) } as ApiKeyAuth?
requireNotNull(auth) { "No API key authentication configured" }
auth.apiKey = apiKey
}

Expand All @@ -122,8 +124,9 @@ import {{packageName}}.auth.*
* @param paramName The name of the API key parameter, or null or set the first key.
*/
fun setApiKeyPrefix(apiKeyPrefix: String, paramName: String? = null) {
val auth = authentications?.values?.firstOrNull { it is ApiKeyAuth && (paramName == null || paramName == it.paramName) } as ApiKeyAuth?
?: throw Exception("No API key authentication configured")
val auth =
authentications.values.firstOrNull { it is ApiKeyAuth && (paramName == null || paramName == it.paramName) } as ApiKeyAuth?
requireNotNull(auth) { "No API key authentication configured" }
auth.apiKeyPrefix = apiKeyPrefix
}

Expand All @@ -133,8 +136,8 @@ import {{packageName}}.auth.*
* @param accessToken Access token
*/
fun setAccessToken(accessToken: String) {
val auth = authentications?.values?.firstOrNull { it is OAuth } as OAuth?
?: throw Exception("No OAuth2 authentication configured")
val auth = authentications.values.firstNotNullOfOrNull { it as? OAuth }
requireNotNull(auth) { "No OAuth2 authentication configured" }
auth.accessToken = accessToken
}

Expand All @@ -144,23 +147,24 @@ import {{packageName}}.auth.*
* @param bearerToken The bearer token.
*/
fun setBearerToken(bearerToken: String) {
val auth = authentications?.values?.firstOrNull { it is HttpBearerAuth } as HttpBearerAuth?
?: throw Exception("No Bearer authentication configured")
val auth = authentications.values.firstNotNullOfOrNull { it as? HttpBearerAuth }
requireNotNull(auth) { "No Bearer authentication configured" }
auth.bearerToken = bearerToken
}

protected suspend fun <T: Any?> multipartFormRequest(requestConfig: RequestConfig<T>, body: kotlin.collections.List<PartData>?, authNames: kotlin.collections.List<String>): HttpResponse {
protected suspend fun <T> multipartFormRequest(requestConfig: RequestConfig<T>, body: List<PartData>?, authNames: List<String>): HttpResponse {
return request(requestConfig, MultiPartFormDataContent(body ?: listOf()), authNames)
}

protected suspend fun <T: Any?> urlEncodedFormRequest(requestConfig: RequestConfig<T>, body: Parameters?, authNames: kotlin.collections.List<String>): HttpResponse {
protected suspend fun <T> urlEncodedFormRequest(requestConfig: RequestConfig<T>, body: Parameters?, authNames: List<String>): HttpResponse {
return request(requestConfig, FormDataContent(body ?: Parameters.Empty), authNames)
}

protected suspend fun <T: Any?> jsonRequest(requestConfig: RequestConfig<T>, body: Any? = null, authNames: kotlin.collections.List<String>): HttpResponse = request(requestConfig, body, authNames)
protected suspend fun <T> jsonRequest(requestConfig: RequestConfig<T>, body: Any? = null, authNames: List<String>): HttpResponse =
request(requestConfig, body, authNames)

protected suspend fun <T: Any?> request(requestConfig: RequestConfig<T>, body: Any? = null, authNames: kotlin.collections.List<String>): HttpResponse {
requestConfig.updateForAuth<T>(authNames)
protected suspend fun <T> request(requestConfig: RequestConfig<T>, body: Any? = null, authNames: List<String>): HttpResponse {
requestConfig.updateForAuth(authNames)
val headers = requestConfig.headers
return client.request {
Expand All @@ -183,18 +187,18 @@ import {{packageName}}.auth.*
}
}

fun <T: Any?> RequestConfig<T>.updateForAuth(authNames: kotlin.collections.List<String>) {
fun <T> RequestConfig<T>.updateForAuth(authNames: List<String>) {
for (authName in authNames) {
val auth = authentications?.get(authName) ?: throw Exception("Authentication undefined: $authName")
val auth = requireNotNull(authentications[authName]) { "Authentication undefined: $authName" }
auth.apply(query, headers)
}
}

fun URLBuilder.appendPath(components: kotlin.collections.List<String>): URLBuilder = apply {
private fun URLBuilder.appendPath(components: List<String>): URLBuilder = apply {
encodedPath = encodedPath.trimEnd('/') + components.joinToString("/", prefix = "/") { it.encodeURLQueryComponent() }
}

val RequestMethod.httpMethod: HttpMethod
private val RequestMethod.httpMethod: HttpMethod
get() = when (this) {
RequestMethod.DELETE -> HttpMethod.Delete
RequestMethod.GET -> HttpMethod.Get
Expand All @@ -204,4 +208,8 @@ import {{packageName}}.auth.*
RequestMethod.POST -> HttpMethod.Post
RequestMethod.OPTIONS -> HttpMethod.Options
}

override fun close() {
client.close()
}
}

0 comments on commit c598fc7

Please sign in to comment.