forked from loafle/openapi-generator-original
Feature/update kotlin dependecies template (#12966)
* update Kotlin & Ktor versions * update samples * fix gradle version * update the ktor client templates and project samples * update the ktor client templates and project samples * revert multiplatform upgrade * update kotlin multiplatform * upload kotlin Multiplatform samples * fix gson ktor sample * update samples * fix: unused imports * fix imports of ApiClient * update kotlin samples
This commit is contained in:
parent
f6be1d07bc
commit
ef6d383433
@ -3,15 +3,15 @@ version '{{artifactVersion}}'
|
||||
{{^omitGradleWrapper}}
|
||||
|
||||
wrapper {
|
||||
gradleVersion = '6.8.3'
|
||||
gradleVersion = '7.5'
|
||||
distributionUrl = "https://services.gradle.org/distributions/gradle-$gradleVersion-all.zip"
|
||||
}
|
||||
{{/omitGradleWrapper}}
|
||||
|
||||
buildscript {
|
||||
ext.kotlin_version = '1.5.10'
|
||||
ext.kotlin_version = '1.6.10'
|
||||
{{#jvm-ktor}}
|
||||
ext.ktor_version = '1.6.7'
|
||||
ext.ktor_version = '2.0.3'
|
||||
{{/jvm-ktor}}
|
||||
{{#jvm-retrofit2}}
|
||||
ext.retrofitVersion = '2.9.0'
|
||||
@ -72,46 +72,49 @@ dependencies {
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
|
||||
{{^doNotUseRxAndCoroutines}}
|
||||
{{#useCoroutines}}
|
||||
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.1"
|
||||
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.3"
|
||||
{{/useCoroutines}}
|
||||
{{/doNotUseRxAndCoroutines}}
|
||||
{{#moshi}}
|
||||
{{^moshiCodeGen}}
|
||||
implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
|
||||
implementation "com.squareup.moshi:moshi-kotlin:1.12.0"
|
||||
implementation "com.squareup.moshi:moshi-adapters:1.12.0"
|
||||
implementation "com.squareup.moshi:moshi-kotlin:1.13.0"
|
||||
implementation "com.squareup.moshi:moshi-adapters:1.13.0"
|
||||
{{/moshiCodeGen}}
|
||||
{{#moshiCodeGen}}
|
||||
implementation "com.squareup.moshi:moshi:1.12.0"
|
||||
implementation "com.squareup.moshi:moshi-adapters:1.12.0"
|
||||
kapt "com.squareup.moshi:moshi-kotlin-codegen:1.12.0"
|
||||
implementation "com.squareup.moshi:moshi:1.13.0"
|
||||
implementation "com.squareup.moshi:moshi-adapters:1.13.0"
|
||||
kapt "com.squareup.moshi:moshi-kotlin-codegen:1.13.0"
|
||||
{{/moshiCodeGen}}
|
||||
{{/moshi}}
|
||||
{{#gson}}
|
||||
implementation "com.google.code.gson:gson:2.8.7"
|
||||
implementation "com.google.code.gson:gson:2.9.0"
|
||||
{{/gson}}
|
||||
{{#jackson}}
|
||||
implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
|
||||
implementation "com.fasterxml.jackson.module:jackson-module-kotlin:2.12.3"
|
||||
implementation "com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.12.3"
|
||||
implementation "com.fasterxml.jackson.module:jackson-module-kotlin:2.13.3"
|
||||
implementation "com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.13.3"
|
||||
{{/jackson}}
|
||||
{{#kotlinx_serialization}}
|
||||
implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.2.1"
|
||||
implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.3.3"
|
||||
{{/kotlinx_serialization}}
|
||||
{{#jvm-ktor}}
|
||||
implementation "io.ktor:ktor-client-core:$ktor_version"
|
||||
implementation "io.ktor:ktor-client-content-negotiation:$ktor_version"
|
||||
{{#gson}}
|
||||
implementation "io.ktor:ktor-serialization-gson:$ktor_version"
|
||||
implementation "io.ktor:ktor-client-gson:$ktor_version"
|
||||
{{/gson}}
|
||||
{{#jackson}}
|
||||
implementation "io.ktor:ktor-client-jackson:$ktor_version"
|
||||
implementation "io.ktor:ktor-serialization-jackson:$ktor_version"
|
||||
{{/jackson}}
|
||||
{{/jvm-ktor}}
|
||||
{{#jvm-okhttp3}}
|
||||
implementation "com.squareup.okhttp3:okhttp:3.12.13"
|
||||
{{/jvm-okhttp3}}
|
||||
{{#jvm-okhttp4}}
|
||||
implementation "com.squareup.okhttp3:okhttp:4.9.1"
|
||||
implementation "com.squareup.okhttp3:okhttp:4.10.0"
|
||||
{{/jvm-okhttp4}}
|
||||
{{#threetenbp}}
|
||||
implementation "org.threeten:threetenbp:1.5.1"
|
||||
@ -120,7 +123,7 @@ dependencies {
|
||||
{{#hasOAuthMethods}}
|
||||
implementation "org.apache.oltu.oauth2:org.apache.oltu.oauth2.client:1.0.2"
|
||||
{{/hasOAuthMethods}}
|
||||
implementation "com.squareup.okhttp3:logging-interceptor:4.9.1"
|
||||
implementation "com.squareup.okhttp3:logging-interceptor:4.10.0"
|
||||
{{#useRxJava}}
|
||||
implementation "io.reactivex:rxjava:$rxJavaVersion"
|
||||
implementation "com.squareup.retrofit2:adapter-rxjava:$retrofitVersion"
|
||||
|
@ -9,9 +9,10 @@ import io.ktor.client.HttpClientConfig
|
||||
import io.ktor.client.request.forms.formData
|
||||
import io.ktor.client.engine.HttpClientEngine
|
||||
import io.ktor.http.ParametersBuilder
|
||||
|
||||
{{#gson}}
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.GsonBuilder
|
||||
import java.text.DateFormat
|
||||
{{/gson}}
|
||||
{{#jackson}}
|
||||
import com.fasterxml.jackson.databind.ObjectMapper
|
||||
@ -22,8 +23,13 @@ import com.fasterxml.jackson.databind.ObjectMapper
|
||||
baseUrl: String = ApiClient.BASE_URL,
|
||||
httpClientEngine: HttpClientEngine? = null,
|
||||
httpClientConfig: ((HttpClientConfig<*>) -> Unit)? = null,
|
||||
json: {{#gson}}Gson{{/gson}}{{#jackson}}ObjectMapper{{/jackson}} = ApiClient.JSON_DEFAULT,
|
||||
) : ApiClient(baseUrl, httpClientEngine, httpClientConfig, json) {
|
||||
{{#gson}}
|
||||
jsonBlock: GsonBuilder.() -> Unit = ApiClient.JSON_DEFAULT,
|
||||
{{/gson}}
|
||||
{{#jackson}}
|
||||
jsonBlock: ObjectMapper.() -> Unit = ApiClient.JSON_DEFAULT,
|
||||
{{/jackson}}
|
||||
) : ApiClient(baseUrl, httpClientEngine, httpClientConfig, jsonBlock) {
|
||||
|
||||
{{#operation}}
|
||||
/**
|
||||
|
@ -1,50 +1,68 @@
|
||||
package {{packageName}}.infrastructure
|
||||
|
||||
|
||||
import io.ktor.client.HttpClient
|
||||
import io.ktor.client.HttpClientConfig
|
||||
import io.ktor.client.engine.HttpClientEngine
|
||||
import io.ktor.client.features.json.JsonFeature
|
||||
import io.ktor.client.features.json.JsonSerializer
|
||||
import io.ktor.client.request.*
|
||||
import io.ktor.client.plugins.contentnegotiation.ContentNegotiation
|
||||
import io.ktor.client.request.forms.FormDataContent
|
||||
import io.ktor.client.request.forms.MultiPartFormDataContent
|
||||
import io.ktor.client.request.header
|
||||
import io.ktor.client.request.parameter
|
||||
import io.ktor.client.request.request
|
||||
import io.ktor.client.request.setBody
|
||||
import io.ktor.client.statement.HttpResponse
|
||||
import io.ktor.client.utils.EmptyContent
|
||||
import io.ktor.http.*
|
||||
import io.ktor.http.content.ByteArrayContent
|
||||
import io.ktor.http.content.OutgoingContent
|
||||
import io.ktor.http.HttpHeaders
|
||||
import io.ktor.http.HttpMethod
|
||||
import io.ktor.http.Parameters
|
||||
import io.ktor.http.URLBuilder
|
||||
import io.ktor.http.content.PartData
|
||||
import kotlin.Unit
|
||||
|
||||
import io.ktor.http.encodeURLQueryComponent
|
||||
import io.ktor.http.encodedPath
|
||||
import io.ktor.http.takeFrom
|
||||
{{#gson}}
|
||||
import com.google.gson.Gson
|
||||
import java.nio.charset.StandardCharsets
|
||||
import io.ktor.serialization.gson.*
|
||||
import com.google.gson.GsonBuilder
|
||||
import java.text.DateFormat
|
||||
{{/gson}}
|
||||
{{#jackson}}
|
||||
import io.ktor.serialization.jackson.*
|
||||
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
|
||||
import com.fasterxml.jackson.databind.ObjectMapper
|
||||
import com.fasterxml.jackson.databind.SerializationFeature
|
||||
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule
|
||||
import com.fasterxml.jackson.core.util.DefaultIndenter
|
||||
import com.fasterxml.jackson.core.util.DefaultPrettyPrinter
|
||||
{{/jackson}}
|
||||
|
||||
import org.openapitools.client.auth.ApiKeyAuth
|
||||
import org.openapitools.client.auth.Authentication
|
||||
import org.openapitools.client.auth.HttpBasicAuth
|
||||
import org.openapitools.client.auth.HttpBearerAuth
|
||||
import org.openapitools.client.auth.OAuth
|
||||
import {{packageName}}.auth.*
|
||||
|
||||
{{#nonPublicApi}}internal {{/nonPublicApi}}open class ApiClient(
|
||||
private val baseUrl: String,
|
||||
httpClientEngine: HttpClientEngine?,
|
||||
httpClientConfig: ((HttpClientConfig<*>) -> Unit)? = null,
|
||||
json: {{#gson}}Gson{{/gson}}{{#jackson}}ObjectMapper{{/jackson}},
|
||||
{{#gson}}
|
||||
jsonBlock: GsonBuilder.() -> Unit = JSON_DEFAULT,
|
||||
{{/gson}}
|
||||
{{#jackson}}
|
||||
jsonBlock: ObjectMapper.() -> Unit = JSON_DEFAULT,
|
||||
{{/jackson}}
|
||||
) {
|
||||
|
||||
private val serializer: JsonSerializer by lazy {
|
||||
JsonSerializerImpl(json)
|
||||
}
|
||||
|
||||
private val clientConfig: (HttpClientConfig<*>) -> Unit by lazy {
|
||||
{
|
||||
// Hold a reference to the serializer to avoid freezing the entire ApiClient instance
|
||||
// when the JsonFeature is configured.
|
||||
val serializerReference = serializer
|
||||
it.install(JsonFeature) { serializer = serializerReference }
|
||||
it.install(ContentNegotiation) {
|
||||
{{#gson}}
|
||||
gson { jsonBlock() }
|
||||
{{/gson}}
|
||||
{{#jackson}}
|
||||
jackson { jsonBlock() }
|
||||
{{/jackson}}
|
||||
}
|
||||
httpClientConfig?.invoke(it)
|
||||
}
|
||||
}
|
||||
@ -67,9 +85,24 @@ import {{packageName}}.auth.*
|
||||
{{/hasAuthMethods}}
|
||||
|
||||
{{#nonPublicApi}}internal {{/nonPublicApi}}companion object {
|
||||
const val BASE_URL = "{{{basePath}}}"
|
||||
val JSON_DEFAULT = {{#gson}}Gson(){{/gson}}{{#jackson}}ObjectMapper(){{/jackson}}
|
||||
protected val UNSAFE_HEADERS = listOf(HttpHeaders.ContentType)
|
||||
const val BASE_URL = "{{{basePath}}}"
|
||||
{{#gson}}
|
||||
val JSON_DEFAULT : GsonBuilder.() -> Unit = {
|
||||
setDateFormat(DateFormat.LONG)
|
||||
setPrettyPrinting()
|
||||
}
|
||||
{{/gson}}
|
||||
{{#jackson}}
|
||||
val JSON_DEFAULT: ObjectMapper.() -> Unit = {
|
||||
configure(SerializationFeature.INDENT_OUTPUT, true)
|
||||
setDefaultPrettyPrinter(DefaultPrettyPrinter().apply {
|
||||
indentArraysWith(DefaultPrettyPrinter.FixedSpaceIndenter.instance)
|
||||
indentObjectsWith(DefaultIndenter(" ", "\n"))
|
||||
})
|
||||
registerModule(JavaTimeModule())
|
||||
}
|
||||
{{/jackson}}
|
||||
protected val UNSAFE_HEADERS = listOf(HttpHeaders.ContentType)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -78,7 +111,7 @@ import {{packageName}}.auth.*
|
||||
* @param username Username
|
||||
*/
|
||||
fun setUsername(username: String) {
|
||||
val auth = authentications?.values?.firstOrNull { it is HttpBasicAuth } as HttpBasicAuth?
|
||||
val auth = authentications.values.firstOrNull { it is HttpBasicAuth } as HttpBasicAuth?
|
||||
?: throw Exception("No HTTP basic authentication configured")
|
||||
auth.username = username
|
||||
}
|
||||
@ -89,7 +122,7 @@ import {{packageName}}.auth.*
|
||||
* @param password Password
|
||||
*/
|
||||
fun setPassword(password: String) {
|
||||
val auth = authentications?.values?.firstOrNull { it is HttpBasicAuth } as HttpBasicAuth?
|
||||
val auth = authentications.values.firstOrNull { it is HttpBasicAuth } as HttpBasicAuth?
|
||||
?: throw Exception("No HTTP basic authentication configured")
|
||||
auth.password = password
|
||||
}
|
||||
@ -101,7 +134,7 @@ 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?
|
||||
val auth = authentications.values.firstOrNull { it is ApiKeyAuth && (paramName == null || paramName == it.paramName)} as ApiKeyAuth?
|
||||
?: throw Exception("No API key authentication configured")
|
||||
auth.apiKey = apiKey
|
||||
}
|
||||
@ -113,7 +146,7 @@ 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?
|
||||
val auth = authentications.values.firstOrNull { it is ApiKeyAuth && (paramName == null || paramName == it.paramName) } as ApiKeyAuth?
|
||||
?: throw Exception("No API key authentication configured")
|
||||
auth.apiKeyPrefix = apiKeyPrefix
|
||||
}
|
||||
@ -124,7 +157,7 @@ import {{packageName}}.auth.*
|
||||
* @param accessToken Access token
|
||||
*/
|
||||
fun setAccessToken(accessToken: String) {
|
||||
val auth = authentications?.values?.firstOrNull { it is OAuth } as OAuth?
|
||||
val auth = authentications.values.firstOrNull { it is OAuth } as OAuth?
|
||||
?: throw Exception("No OAuth2 authentication configured")
|
||||
auth.accessToken = accessToken
|
||||
}
|
||||
@ -135,7 +168,7 @@ import {{packageName}}.auth.*
|
||||
* @param bearerToken The bearer token.
|
||||
*/
|
||||
fun setBearerToken(bearerToken: String) {
|
||||
val auth = authentications?.values?.firstOrNull { it is HttpBearerAuth } as HttpBearerAuth?
|
||||
val auth = authentications.values.firstOrNull { it is HttpBearerAuth } as HttpBearerAuth?
|
||||
?: throw Exception("No Bearer authentication configured")
|
||||
auth.bearerToken = bearerToken
|
||||
}
|
||||
@ -148,18 +181,13 @@ import {{packageName}}.auth.*
|
||||
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 {
|
||||
val contentType = (requestConfig.headers[HttpHeaders.ContentType]?.let { ContentType.parse(it) }
|
||||
?: ContentType.Application.Json)
|
||||
return if (body != null) request(requestConfig, serializer.write(body, contentType), authNames)
|
||||
else request(requestConfig, authNames = 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: Any?> request(requestConfig: RequestConfig<T>, body: OutgoingContent = EmptyContent, authNames: kotlin.collections.List<String>): HttpResponse {
|
||||
protected suspend fun <T: Any?> request(requestConfig: RequestConfig<T>, body: Any? = null, authNames: kotlin.collections.List<String>): HttpResponse {
|
||||
requestConfig.updateForAuth<T>(authNames)
|
||||
val headers = requestConfig.headers
|
||||
|
||||
return client.request<HttpResponse> {
|
||||
return client.request {
|
||||
this.url {
|
||||
this.takeFrom(URLBuilder(baseUrl))
|
||||
appendPath(requestConfig.path.trimStart('/').split('/'))
|
||||
@ -172,8 +200,7 @@ import {{packageName}}.auth.*
|
||||
this.method = requestConfig.method.httpMethod
|
||||
headers.filter { header -> !UNSAFE_HEADERS.contains(header.key) }.forEach { header -> this.header(header.key, header.value) }
|
||||
if (requestConfig.method in listOf(RequestMethod.PUT, RequestMethod.POST, RequestMethod.PATCH))
|
||||
this.body = body
|
||||
|
||||
setBody(body)
|
||||
}
|
||||
}
|
||||
|
||||
@ -199,13 +226,3 @@ import {{packageName}}.auth.*
|
||||
RequestMethod.OPTIONS -> HttpMethod.Options
|
||||
}
|
||||
}
|
||||
|
||||
{{#gson}}private class JsonSerializerImpl(private val gson: Gson) : JsonSerializer {
|
||||
override fun write(data: Any, contentType: ContentType): OutgoingContent =
|
||||
ByteArrayContent(gson.toJson(data).toByteArray(StandardCharsets.UTF_8), contentType)
|
||||
}{{/gson}}
|
||||
|
||||
{{#jackson}}private class JsonSerializerImpl(private val objectMapper: ObjectMapper) : JsonSerializer {
|
||||
override fun write(data: Any, contentType: ContentType): OutgoingContent =
|
||||
ByteArrayContent(objectMapper.writeValueAsBytes(data), contentType)
|
||||
}{{/jackson}}
|
||||
|
@ -1,9 +1,9 @@
|
||||
package {{packageName}}.infrastructure
|
||||
|
||||
import io.ktor.client.call.TypeInfo
|
||||
import io.ktor.client.call.typeInfo
|
||||
import io.ktor.http.Headers
|
||||
import io.ktor.http.isSuccess
|
||||
import io.ktor.util.reflect.TypeInfo
|
||||
import io.ktor.util.reflect.typeInfo
|
||||
|
||||
{{#nonPublicApi}}internal {{/nonPublicApi}}open class HttpResponse<T : Any>(val response: io.ktor.client.statement.HttpResponse, val provider: BodyProvider<T>) {
|
||||
val status: Int = response.status.value
|
||||
@ -29,11 +29,11 @@ import io.ktor.http.isSuccess
|
||||
{{#nonPublicApi}}internal {{/nonPublicApi}}class TypedBodyProvider<T : Any>(private val type: TypeInfo) : BodyProvider<T> {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
override suspend fun body(response: io.ktor.client.statement.HttpResponse): T =
|
||||
response.call.receive(type) as T
|
||||
response.call.body(type) as T
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
override suspend fun <V : Any> typedBody(response: io.ktor.client.statement.HttpResponse, type: TypeInfo): V =
|
||||
response.call.receive(type) as V
|
||||
response.call.body(type) as V
|
||||
}
|
||||
|
||||
{{#nonPublicApi}}internal {{/nonPublicApi}}class MappedBodyProvider<S : Any, T : Any>(private val provider: BodyProvider<S>, private val block: S.() -> T) : BodyProvider<T> {
|
||||
|
@ -8,7 +8,6 @@ import {{packageName}}.infrastructure.*
|
||||
import io.ktor.client.HttpClientConfig
|
||||
import io.ktor.client.request.forms.formData
|
||||
import io.ktor.client.engine.HttpClientEngine
|
||||
import io.ktor.client.features.json.serializer.KotlinxSerializer
|
||||
import kotlinx.serialization.json.Json
|
||||
import io.ktor.http.ParametersBuilder
|
||||
import kotlinx.serialization.*
|
||||
|
@ -8,10 +8,10 @@ plugins {
|
||||
group = "{{groupId}}"
|
||||
version = "{{artifactVersion}}"
|
||||
|
||||
val kotlin_version = "1.6.0"
|
||||
val coroutines_version = "1.5.2"
|
||||
val serialization_version = "1.3.0"
|
||||
val ktor_version = "1.6.4"
|
||||
val kotlin_version = "1.6.10"
|
||||
val coroutines_version = "1.6.3"
|
||||
val serialization_version = "1.3.3"
|
||||
val ktor_version = "2.0.3"
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
@ -30,9 +30,11 @@ kotlin {
|
||||
dependencies {
|
||||
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutines_version")
|
||||
implementation("org.jetbrains.kotlinx:kotlinx-serialization-core:$serialization_version")
|
||||
|
||||
api("io.ktor:ktor-client-core:$ktor_version")
|
||||
api("io.ktor:ktor-client-json:$ktor_version")
|
||||
api("io.ktor:ktor-client-serialization:$ktor_version")
|
||||
api("io.ktor:ktor-client-content-negotiation:$ktor_version")
|
||||
api("io.ktor:ktor-serialization-kotlinx-json:$ktor_version")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3,43 +3,31 @@ package {{packageName}}.infrastructure
|
||||
import io.ktor.client.HttpClient
|
||||
import io.ktor.client.HttpClientConfig
|
||||
import io.ktor.client.engine.HttpClientEngine
|
||||
import io.ktor.client.features.json.JsonFeature
|
||||
import io.ktor.client.features.json.JsonSerializer
|
||||
import io.ktor.client.features.json.serializer.KotlinxSerializer
|
||||
import io.ktor.client.plugins.contentnegotiation.ContentNegotiation
|
||||
import io.ktor.serialization.kotlinx.json.*
|
||||
import io.ktor.client.request.*
|
||||
import io.ktor.client.request.forms.FormDataContent
|
||||
import io.ktor.client.request.forms.MultiPartFormDataContent
|
||||
import io.ktor.client.request.header
|
||||
import io.ktor.client.request.parameter
|
||||
import io.ktor.client.statement.HttpResponse
|
||||
import io.ktor.client.utils.EmptyContent
|
||||
import io.ktor.http.*
|
||||
import io.ktor.http.content.OutgoingContent
|
||||
import io.ktor.http.content.PartData
|
||||
import kotlin.Unit
|
||||
import kotlinx.serialization.json.Json
|
||||
|
||||
import {{apiPackage}}.*
|
||||
import {{modelPackage}}.*
|
||||
import {{packageName}}.auth.*
|
||||
|
||||
{{#nonPublicApi}}internal {{/nonPublicApi}}open class ApiClient(
|
||||
private val baseUrl: String,
|
||||
httpClientEngine: HttpClientEngine?,
|
||||
httpClientConfig: ((HttpClientConfig<*>) -> Unit)? = null,
|
||||
private val json: Json
|
||||
private val jsonBlock: Json
|
||||
) {
|
||||
|
||||
private val serializer: JsonSerializer by lazy {
|
||||
KotlinxSerializer(json).ignoreOutgoingContent()
|
||||
}
|
||||
|
||||
private val clientConfig: (HttpClientConfig<*>) -> Unit by lazy {
|
||||
{
|
||||
// Hold a reference to the serializer to avoid freezing the entire ApiClient instance
|
||||
// when the JsonFeature is configured.
|
||||
val serializerReference = serializer
|
||||
it.install(JsonFeature) { serializer = serializerReference }
|
||||
it.install(ContentNegotiation) { json(jsonBlock) }
|
||||
httpClientConfig?.invoke(it)
|
||||
}
|
||||
}
|
||||
@ -63,7 +51,11 @@ import {{packageName}}.auth.*
|
||||
|
||||
{{#nonPublicApi}}internal {{/nonPublicApi}}companion object {
|
||||
const val BASE_URL = "{{{basePath}}}"
|
||||
val JSON_DEFAULT = Json { ignoreUnknownKeys = true }
|
||||
val JSON_DEFAULT = Json {
|
||||
ignoreUnknownKeys = true
|
||||
prettyPrint = true
|
||||
isLenient = true
|
||||
}
|
||||
protected val UNSAFE_HEADERS = listOf(HttpHeaders.ContentType)
|
||||
}
|
||||
|
||||
@ -143,18 +135,13 @@ import {{packageName}}.auth.*
|
||||
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 {
|
||||
val contentType = (requestConfig.headers[HttpHeaders.ContentType]?.let { ContentType.parse(it) }
|
||||
?: ContentType.Application.Json)
|
||||
return if (body != null) request(requestConfig, serializer.write(body, contentType), authNames)
|
||||
else request(requestConfig, authNames = 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: Any?> request(requestConfig: RequestConfig<T>, body: OutgoingContent = EmptyContent, authNames: kotlin.collections.List<String>): HttpResponse {
|
||||
protected suspend fun <T: Any?> request(requestConfig: RequestConfig<T>, body: Any? = null, authNames: kotlin.collections.List<String>): HttpResponse {
|
||||
requestConfig.updateForAuth<T>(authNames)
|
||||
val headers = requestConfig.headers
|
||||
|
||||
return client.request<HttpResponse> {
|
||||
return client.request {
|
||||
this.url {
|
||||
this.takeFrom(URLBuilder(baseUrl))
|
||||
appendPath(requestConfig.path.trimStart('/').split('/'))
|
||||
@ -167,7 +154,7 @@ import {{packageName}}.auth.*
|
||||
this.method = requestConfig.method.httpMethod
|
||||
headers.filter { header -> !UNSAFE_HEADERS.contains(header.key) }.forEach { header -> this.header(header.key, header.value) }
|
||||
if (requestConfig.method in listOf(RequestMethod.PUT, RequestMethod.POST, RequestMethod.PATCH))
|
||||
this.body = body
|
||||
this.setBody(body)
|
||||
|
||||
}
|
||||
}
|
||||
@ -194,13 +181,3 @@ import {{packageName}}.auth.*
|
||||
RequestMethod.OPTIONS -> HttpMethod.Options
|
||||
}
|
||||
}
|
||||
|
||||
// https://github.com/ktorio/ktor/issues/851
|
||||
private fun JsonSerializer.ignoreOutgoingContent() = IgnoreOutgoingContentJsonSerializer(this)
|
||||
|
||||
private class IgnoreOutgoingContentJsonSerializer(private val delegate: JsonSerializer) : JsonSerializer by delegate {
|
||||
override fun write(data: Any): OutgoingContent {
|
||||
if (data is OutgoingContent) return data
|
||||
return delegate.write(data)
|
||||
}
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ private fun ByteArray.clearFrom(from: Int) = (from until size).forEach { this[it
|
||||
private fun Int.toBase64(): Char = BASE64_ALPHABET[this]
|
||||
private fun Byte.fromBase64(): Byte = BASE64_INVERSE_ALPHABET[toInt() and 0xff].toByte() and BASE64_MASK
|
||||
internal fun ByteArray.encodeBase64(): String = buildPacket { writeFully(this@encodeBase64) }.encodeBase64()
|
||||
internal fun String.decodeBase64Bytes(): ByteArray = buildPacket { writeStringUtf8(dropLastWhile { it == BASE64_PAD }) }.decodeBase64Bytes().readBytes()
|
||||
internal fun String.decodeBase64Bytes(): ByteArray = buildPacket { dropLastWhile { it == BASE64_PAD } }.decodeBase64Bytes().readBytes()
|
||||
|
||||
/**
|
||||
* Encode [bytes] as a HEX string with no spaces, newlines and `0x` prefixes.
|
||||
|
@ -1,9 +1,9 @@
|
||||
package {{packageName}}.infrastructure
|
||||
|
||||
import io.ktor.client.call.TypeInfo
|
||||
import io.ktor.client.call.typeInfo
|
||||
import io.ktor.http.Headers
|
||||
import io.ktor.http.isSuccess
|
||||
import io.ktor.util.reflect.TypeInfo
|
||||
import io.ktor.util.reflect.typeInfo
|
||||
|
||||
{{#nonPublicApi}}internal {{/nonPublicApi}}open class HttpResponse<T : Any>(val response: io.ktor.client.statement.HttpResponse, val provider: BodyProvider<T>) {
|
||||
val status: Int = response.status.value
|
||||
@ -29,11 +29,11 @@ import io.ktor.http.isSuccess
|
||||
{{#nonPublicApi}}internal {{/nonPublicApi}}class TypedBodyProvider<T : Any>(private val type: TypeInfo) : BodyProvider<T> {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
override suspend fun body(response: io.ktor.client.statement.HttpResponse): T =
|
||||
response.call.receive(type) as T
|
||||
response.call.body(type) as T
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
override suspend fun <V : Any> typedBody(response: io.ktor.client.statement.HttpResponse, type: TypeInfo): V =
|
||||
response.call.receive(type) as V
|
||||
response.call.body(type) as V
|
||||
}
|
||||
|
||||
{{#nonPublicApi}}internal {{/nonPublicApi}}class MappedBodyProvider<S : Any, T : Any>(private val provider: BodyProvider<S>, private val block: S.() -> T) : BodyProvider<T> {
|
||||
|
@ -2,12 +2,12 @@ group 'org.openapitools'
|
||||
version '1.0.0'
|
||||
|
||||
wrapper {
|
||||
gradleVersion = '6.8.3'
|
||||
gradleVersion = '7.5'
|
||||
distributionUrl = "https://services.gradle.org/distributions/gradle-$gradleVersion-all.zip"
|
||||
}
|
||||
|
||||
buildscript {
|
||||
ext.kotlin_version = '1.5.10'
|
||||
ext.kotlin_version = '1.6.10'
|
||||
|
||||
repositories {
|
||||
maven { url "https://repo1.maven.org/maven2" }
|
||||
@ -30,8 +30,8 @@ test {
|
||||
dependencies {
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
|
||||
implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
|
||||
implementation "com.squareup.moshi:moshi-kotlin:1.12.0"
|
||||
implementation "com.squareup.moshi:moshi-adapters:1.12.0"
|
||||
implementation "com.squareup.okhttp3:okhttp:4.9.1"
|
||||
implementation "com.squareup.moshi:moshi-kotlin:1.13.0"
|
||||
implementation "com.squareup.moshi:moshi-adapters:1.13.0"
|
||||
implementation "com.squareup.okhttp3:okhttp:4.10.0"
|
||||
testImplementation "io.kotlintest:kotlintest-runner-junit5:3.4.2"
|
||||
}
|
||||
|
@ -2,12 +2,12 @@ group 'org.openapitools'
|
||||
version '1.0.0'
|
||||
|
||||
wrapper {
|
||||
gradleVersion = '6.8.3'
|
||||
gradleVersion = '7.5'
|
||||
distributionUrl = "https://services.gradle.org/distributions/gradle-$gradleVersion-all.zip"
|
||||
}
|
||||
|
||||
buildscript {
|
||||
ext.kotlin_version = '1.5.10'
|
||||
ext.kotlin_version = '1.6.10'
|
||||
|
||||
repositories {
|
||||
maven { url "https://repo1.maven.org/maven2" }
|
||||
@ -30,8 +30,8 @@ test {
|
||||
dependencies {
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
|
||||
implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
|
||||
implementation "com.squareup.moshi:moshi-kotlin:1.12.0"
|
||||
implementation "com.squareup.moshi:moshi-adapters:1.12.0"
|
||||
implementation "com.squareup.moshi:moshi-kotlin:1.13.0"
|
||||
implementation "com.squareup.moshi:moshi-adapters:1.13.0"
|
||||
implementation "com.squareup.okhttp3:okhttp:3.12.13"
|
||||
testImplementation "io.kotlintest:kotlintest-runner-junit5:3.4.2"
|
||||
}
|
||||
|
@ -2,12 +2,12 @@ group 'org.openapitools'
|
||||
version '1.0.0'
|
||||
|
||||
wrapper {
|
||||
gradleVersion = '6.8.3'
|
||||
gradleVersion = '7.5'
|
||||
distributionUrl = "https://services.gradle.org/distributions/gradle-$gradleVersion-all.zip"
|
||||
}
|
||||
|
||||
buildscript {
|
||||
ext.kotlin_version = '1.5.10'
|
||||
ext.kotlin_version = '1.6.10'
|
||||
|
||||
repositories {
|
||||
maven { url "https://repo1.maven.org/maven2" }
|
||||
@ -30,8 +30,8 @@ test {
|
||||
dependencies {
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
|
||||
implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
|
||||
implementation "com.squareup.moshi:moshi-kotlin:1.12.0"
|
||||
implementation "com.squareup.moshi:moshi-adapters:1.12.0"
|
||||
implementation "com.squareup.okhttp3:okhttp:4.9.1"
|
||||
implementation "com.squareup.moshi:moshi-kotlin:1.13.0"
|
||||
implementation "com.squareup.moshi:moshi-adapters:1.13.0"
|
||||
implementation "com.squareup.okhttp3:okhttp:4.10.0"
|
||||
testImplementation "io.kotlintest:kotlintest-runner-junit5:3.4.2"
|
||||
}
|
||||
|
@ -8,10 +8,10 @@ plugins {
|
||||
group = "org.openapitools"
|
||||
version = "1.0.0"
|
||||
|
||||
val kotlin_version = "1.6.0"
|
||||
val coroutines_version = "1.5.2"
|
||||
val serialization_version = "1.3.0"
|
||||
val ktor_version = "1.6.4"
|
||||
val kotlin_version = "1.6.10"
|
||||
val coroutines_version = "1.6.3"
|
||||
val serialization_version = "1.3.3"
|
||||
val ktor_version = "2.0.3"
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
@ -30,9 +30,11 @@ kotlin {
|
||||
dependencies {
|
||||
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutines_version")
|
||||
implementation("org.jetbrains.kotlinx:kotlinx-serialization-core:$serialization_version")
|
||||
|
||||
api("io.ktor:ktor-client-core:$ktor_version")
|
||||
api("io.ktor:ktor-client-json:$ktor_version")
|
||||
api("io.ktor:ktor-client-serialization:$ktor_version")
|
||||
api("io.ktor:ktor-client-content-negotiation:$ktor_version")
|
||||
api("io.ktor:ktor-serialization-kotlinx-json:$ktor_version")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -25,7 +25,6 @@ import org.openapitools.client.infrastructure.*
|
||||
import io.ktor.client.HttpClientConfig
|
||||
import io.ktor.client.request.forms.formData
|
||||
import io.ktor.client.engine.HttpClientEngine
|
||||
import io.ktor.client.features.json.serializer.KotlinxSerializer
|
||||
import kotlinx.serialization.json.Json
|
||||
import io.ktor.http.ParametersBuilder
|
||||
import kotlinx.serialization.*
|
||||
|
@ -3,43 +3,31 @@ package org.openapitools.client.infrastructure
|
||||
import io.ktor.client.HttpClient
|
||||
import io.ktor.client.HttpClientConfig
|
||||
import io.ktor.client.engine.HttpClientEngine
|
||||
import io.ktor.client.features.json.JsonFeature
|
||||
import io.ktor.client.features.json.JsonSerializer
|
||||
import io.ktor.client.features.json.serializer.KotlinxSerializer
|
||||
import io.ktor.client.plugins.contentnegotiation.ContentNegotiation
|
||||
import io.ktor.serialization.kotlinx.json.*
|
||||
import io.ktor.client.request.*
|
||||
import io.ktor.client.request.forms.FormDataContent
|
||||
import io.ktor.client.request.forms.MultiPartFormDataContent
|
||||
import io.ktor.client.request.header
|
||||
import io.ktor.client.request.parameter
|
||||
import io.ktor.client.statement.HttpResponse
|
||||
import io.ktor.client.utils.EmptyContent
|
||||
import io.ktor.http.*
|
||||
import io.ktor.http.content.OutgoingContent
|
||||
import io.ktor.http.content.PartData
|
||||
import kotlin.Unit
|
||||
import kotlinx.serialization.json.Json
|
||||
|
||||
import org.openapitools.client.apis.*
|
||||
import org.openapitools.client.models.*
|
||||
import org.openapitools.client.auth.*
|
||||
|
||||
open class ApiClient(
|
||||
private val baseUrl: String,
|
||||
httpClientEngine: HttpClientEngine?,
|
||||
httpClientConfig: ((HttpClientConfig<*>) -> Unit)? = null,
|
||||
private val json: Json
|
||||
private val jsonBlock: Json
|
||||
) {
|
||||
|
||||
private val serializer: JsonSerializer by lazy {
|
||||
KotlinxSerializer(json).ignoreOutgoingContent()
|
||||
}
|
||||
|
||||
private val clientConfig: (HttpClientConfig<*>) -> Unit by lazy {
|
||||
{
|
||||
// Hold a reference to the serializer to avoid freezing the entire ApiClient instance
|
||||
// when the JsonFeature is configured.
|
||||
val serializerReference = serializer
|
||||
it.install(JsonFeature) { serializer = serializerReference }
|
||||
it.install(ContentNegotiation) { json(jsonBlock) }
|
||||
httpClientConfig?.invoke(it)
|
||||
}
|
||||
}
|
||||
@ -52,7 +40,11 @@ open class ApiClient(
|
||||
|
||||
companion object {
|
||||
const val BASE_URL = "http://localhost"
|
||||
val JSON_DEFAULT = Json { ignoreUnknownKeys = true }
|
||||
val JSON_DEFAULT = Json {
|
||||
ignoreUnknownKeys = true
|
||||
prettyPrint = true
|
||||
isLenient = true
|
||||
}
|
||||
protected val UNSAFE_HEADERS = listOf(HttpHeaders.ContentType)
|
||||
}
|
||||
|
||||
@ -132,18 +124,13 @@ open class ApiClient(
|
||||
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 {
|
||||
val contentType = (requestConfig.headers[HttpHeaders.ContentType]?.let { ContentType.parse(it) }
|
||||
?: ContentType.Application.Json)
|
||||
return if (body != null) request(requestConfig, serializer.write(body, contentType), authNames)
|
||||
else request(requestConfig, authNames = 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: Any?> request(requestConfig: RequestConfig<T>, body: OutgoingContent = EmptyContent, authNames: kotlin.collections.List<String>): HttpResponse {
|
||||
protected suspend fun <T: Any?> request(requestConfig: RequestConfig<T>, body: Any? = null, authNames: kotlin.collections.List<String>): HttpResponse {
|
||||
requestConfig.updateForAuth<T>(authNames)
|
||||
val headers = requestConfig.headers
|
||||
|
||||
return client.request<HttpResponse> {
|
||||
return client.request {
|
||||
this.url {
|
||||
this.takeFrom(URLBuilder(baseUrl))
|
||||
appendPath(requestConfig.path.trimStart('/').split('/'))
|
||||
@ -156,7 +143,7 @@ open class ApiClient(
|
||||
this.method = requestConfig.method.httpMethod
|
||||
headers.filter { header -> !UNSAFE_HEADERS.contains(header.key) }.forEach { header -> this.header(header.key, header.value) }
|
||||
if (requestConfig.method in listOf(RequestMethod.PUT, RequestMethod.POST, RequestMethod.PATCH))
|
||||
this.body = body
|
||||
this.setBody(body)
|
||||
|
||||
}
|
||||
}
|
||||
@ -183,13 +170,3 @@ open class ApiClient(
|
||||
RequestMethod.OPTIONS -> HttpMethod.Options
|
||||
}
|
||||
}
|
||||
|
||||
// https://github.com/ktorio/ktor/issues/851
|
||||
private fun JsonSerializer.ignoreOutgoingContent() = IgnoreOutgoingContentJsonSerializer(this)
|
||||
|
||||
private class IgnoreOutgoingContentJsonSerializer(private val delegate: JsonSerializer) : JsonSerializer by delegate {
|
||||
override fun write(data: Any): OutgoingContent {
|
||||
if (data is OutgoingContent) return data
|
||||
return delegate.write(data)
|
||||
}
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ private fun ByteArray.clearFrom(from: Int) = (from until size).forEach { this[it
|
||||
private fun Int.toBase64(): Char = BASE64_ALPHABET[this]
|
||||
private fun Byte.fromBase64(): Byte = BASE64_INVERSE_ALPHABET[toInt() and 0xff].toByte() and BASE64_MASK
|
||||
internal fun ByteArray.encodeBase64(): String = buildPacket { writeFully(this@encodeBase64) }.encodeBase64()
|
||||
internal fun String.decodeBase64Bytes(): ByteArray = buildPacket { writeStringUtf8(dropLastWhile { it == BASE64_PAD }) }.decodeBase64Bytes().readBytes()
|
||||
internal fun String.decodeBase64Bytes(): ByteArray = buildPacket { dropLastWhile { it == BASE64_PAD } }.decodeBase64Bytes().readBytes()
|
||||
|
||||
/**
|
||||
* Encode [bytes] as a HEX string with no spaces, newlines and `0x` prefixes.
|
||||
|
@ -1,9 +1,9 @@
|
||||
package org.openapitools.client.infrastructure
|
||||
|
||||
import io.ktor.client.call.TypeInfo
|
||||
import io.ktor.client.call.typeInfo
|
||||
import io.ktor.http.Headers
|
||||
import io.ktor.http.isSuccess
|
||||
import io.ktor.util.reflect.TypeInfo
|
||||
import io.ktor.util.reflect.typeInfo
|
||||
|
||||
open class HttpResponse<T : Any>(val response: io.ktor.client.statement.HttpResponse, val provider: BodyProvider<T>) {
|
||||
val status: Int = response.status.value
|
||||
@ -29,11 +29,11 @@ interface BodyProvider<T : Any> {
|
||||
class TypedBodyProvider<T : Any>(private val type: TypeInfo) : BodyProvider<T> {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
override suspend fun body(response: io.ktor.client.statement.HttpResponse): T =
|
||||
response.call.receive(type) as T
|
||||
response.call.body(type) as T
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
override suspend fun <V : Any> typedBody(response: io.ktor.client.statement.HttpResponse, type: TypeInfo): V =
|
||||
response.call.receive(type) as V
|
||||
response.call.body(type) as V
|
||||
}
|
||||
|
||||
class MappedBodyProvider<S : Any, T : Any>(private val provider: BodyProvider<S>, private val block: S.() -> T) : BodyProvider<T> {
|
||||
|
@ -8,10 +8,10 @@ plugins {
|
||||
group = "org.openapitools"
|
||||
version = "1.0.0"
|
||||
|
||||
val kotlin_version = "1.6.0"
|
||||
val coroutines_version = "1.5.2"
|
||||
val serialization_version = "1.3.0"
|
||||
val ktor_version = "1.6.4"
|
||||
val kotlin_version = "1.6.10"
|
||||
val coroutines_version = "1.6.3"
|
||||
val serialization_version = "1.3.3"
|
||||
val ktor_version = "2.0.3"
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
@ -30,9 +30,11 @@ kotlin {
|
||||
dependencies {
|
||||
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutines_version")
|
||||
implementation("org.jetbrains.kotlinx:kotlinx-serialization-core:$serialization_version")
|
||||
|
||||
api("io.ktor:ktor-client-core:$ktor_version")
|
||||
api("io.ktor:ktor-client-json:$ktor_version")
|
||||
api("io.ktor:ktor-client-serialization:$ktor_version")
|
||||
api("io.ktor:ktor-client-content-negotiation:$ktor_version")
|
||||
api("io.ktor:ktor-serialization-kotlinx-json:$ktor_version")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -26,7 +26,6 @@ import org.openapitools.client.infrastructure.*
|
||||
import io.ktor.client.HttpClientConfig
|
||||
import io.ktor.client.request.forms.formData
|
||||
import io.ktor.client.engine.HttpClientEngine
|
||||
import io.ktor.client.features.json.serializer.KotlinxSerializer
|
||||
import kotlinx.serialization.json.Json
|
||||
import io.ktor.http.ParametersBuilder
|
||||
import kotlinx.serialization.*
|
||||
|
@ -3,43 +3,31 @@ package org.openapitools.client.infrastructure
|
||||
import io.ktor.client.HttpClient
|
||||
import io.ktor.client.HttpClientConfig
|
||||
import io.ktor.client.engine.HttpClientEngine
|
||||
import io.ktor.client.features.json.JsonFeature
|
||||
import io.ktor.client.features.json.JsonSerializer
|
||||
import io.ktor.client.features.json.serializer.KotlinxSerializer
|
||||
import io.ktor.client.plugins.contentnegotiation.ContentNegotiation
|
||||
import io.ktor.serialization.kotlinx.json.*
|
||||
import io.ktor.client.request.*
|
||||
import io.ktor.client.request.forms.FormDataContent
|
||||
import io.ktor.client.request.forms.MultiPartFormDataContent
|
||||
import io.ktor.client.request.header
|
||||
import io.ktor.client.request.parameter
|
||||
import io.ktor.client.statement.HttpResponse
|
||||
import io.ktor.client.utils.EmptyContent
|
||||
import io.ktor.http.*
|
||||
import io.ktor.http.content.OutgoingContent
|
||||
import io.ktor.http.content.PartData
|
||||
import kotlin.Unit
|
||||
import kotlinx.serialization.json.Json
|
||||
|
||||
import org.openapitools.client.apis.*
|
||||
import org.openapitools.client.models.*
|
||||
import org.openapitools.client.auth.*
|
||||
|
||||
open class ApiClient(
|
||||
private val baseUrl: String,
|
||||
httpClientEngine: HttpClientEngine?,
|
||||
httpClientConfig: ((HttpClientConfig<*>) -> Unit)? = null,
|
||||
private val json: Json
|
||||
private val jsonBlock: Json
|
||||
) {
|
||||
|
||||
private val serializer: JsonSerializer by lazy {
|
||||
KotlinxSerializer(json).ignoreOutgoingContent()
|
||||
}
|
||||
|
||||
private val clientConfig: (HttpClientConfig<*>) -> Unit by lazy {
|
||||
{
|
||||
// Hold a reference to the serializer to avoid freezing the entire ApiClient instance
|
||||
// when the JsonFeature is configured.
|
||||
val serializerReference = serializer
|
||||
it.install(JsonFeature) { serializer = serializerReference }
|
||||
it.install(ContentNegotiation) { json(jsonBlock) }
|
||||
httpClientConfig?.invoke(it)
|
||||
}
|
||||
}
|
||||
@ -52,7 +40,11 @@ open class ApiClient(
|
||||
|
||||
companion object {
|
||||
const val BASE_URL = "http://localhost"
|
||||
val JSON_DEFAULT = Json { ignoreUnknownKeys = true }
|
||||
val JSON_DEFAULT = Json {
|
||||
ignoreUnknownKeys = true
|
||||
prettyPrint = true
|
||||
isLenient = true
|
||||
}
|
||||
protected val UNSAFE_HEADERS = listOf(HttpHeaders.ContentType)
|
||||
}
|
||||
|
||||
@ -132,18 +124,13 @@ open class ApiClient(
|
||||
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 {
|
||||
val contentType = (requestConfig.headers[HttpHeaders.ContentType]?.let { ContentType.parse(it) }
|
||||
?: ContentType.Application.Json)
|
||||
return if (body != null) request(requestConfig, serializer.write(body, contentType), authNames)
|
||||
else request(requestConfig, authNames = 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: Any?> request(requestConfig: RequestConfig<T>, body: OutgoingContent = EmptyContent, authNames: kotlin.collections.List<String>): HttpResponse {
|
||||
protected suspend fun <T: Any?> request(requestConfig: RequestConfig<T>, body: Any? = null, authNames: kotlin.collections.List<String>): HttpResponse {
|
||||
requestConfig.updateForAuth<T>(authNames)
|
||||
val headers = requestConfig.headers
|
||||
|
||||
return client.request<HttpResponse> {
|
||||
return client.request {
|
||||
this.url {
|
||||
this.takeFrom(URLBuilder(baseUrl))
|
||||
appendPath(requestConfig.path.trimStart('/').split('/'))
|
||||
@ -156,7 +143,7 @@ open class ApiClient(
|
||||
this.method = requestConfig.method.httpMethod
|
||||
headers.filter { header -> !UNSAFE_HEADERS.contains(header.key) }.forEach { header -> this.header(header.key, header.value) }
|
||||
if (requestConfig.method in listOf(RequestMethod.PUT, RequestMethod.POST, RequestMethod.PATCH))
|
||||
this.body = body
|
||||
this.setBody(body)
|
||||
|
||||
}
|
||||
}
|
||||
@ -183,13 +170,3 @@ open class ApiClient(
|
||||
RequestMethod.OPTIONS -> HttpMethod.Options
|
||||
}
|
||||
}
|
||||
|
||||
// https://github.com/ktorio/ktor/issues/851
|
||||
private fun JsonSerializer.ignoreOutgoingContent() = IgnoreOutgoingContentJsonSerializer(this)
|
||||
|
||||
private class IgnoreOutgoingContentJsonSerializer(private val delegate: JsonSerializer) : JsonSerializer by delegate {
|
||||
override fun write(data: Any): OutgoingContent {
|
||||
if (data is OutgoingContent) return data
|
||||
return delegate.write(data)
|
||||
}
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ private fun ByteArray.clearFrom(from: Int) = (from until size).forEach { this[it
|
||||
private fun Int.toBase64(): Char = BASE64_ALPHABET[this]
|
||||
private fun Byte.fromBase64(): Byte = BASE64_INVERSE_ALPHABET[toInt() and 0xff].toByte() and BASE64_MASK
|
||||
internal fun ByteArray.encodeBase64(): String = buildPacket { writeFully(this@encodeBase64) }.encodeBase64()
|
||||
internal fun String.decodeBase64Bytes(): ByteArray = buildPacket { writeStringUtf8(dropLastWhile { it == BASE64_PAD }) }.decodeBase64Bytes().readBytes()
|
||||
internal fun String.decodeBase64Bytes(): ByteArray = buildPacket { dropLastWhile { it == BASE64_PAD } }.decodeBase64Bytes().readBytes()
|
||||
|
||||
/**
|
||||
* Encode [bytes] as a HEX string with no spaces, newlines and `0x` prefixes.
|
||||
|
@ -1,9 +1,9 @@
|
||||
package org.openapitools.client.infrastructure
|
||||
|
||||
import io.ktor.client.call.TypeInfo
|
||||
import io.ktor.client.call.typeInfo
|
||||
import io.ktor.http.Headers
|
||||
import io.ktor.http.isSuccess
|
||||
import io.ktor.util.reflect.TypeInfo
|
||||
import io.ktor.util.reflect.typeInfo
|
||||
|
||||
open class HttpResponse<T : Any>(val response: io.ktor.client.statement.HttpResponse, val provider: BodyProvider<T>) {
|
||||
val status: Int = response.status.value
|
||||
@ -29,11 +29,11 @@ interface BodyProvider<T : Any> {
|
||||
class TypedBodyProvider<T : Any>(private val type: TypeInfo) : BodyProvider<T> {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
override suspend fun body(response: io.ktor.client.statement.HttpResponse): T =
|
||||
response.call.receive(type) as T
|
||||
response.call.body(type) as T
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
override suspend fun <V : Any> typedBody(response: io.ktor.client.statement.HttpResponse, type: TypeInfo): V =
|
||||
response.call.receive(type) as V
|
||||
response.call.body(type) as V
|
||||
}
|
||||
|
||||
class MappedBodyProvider<S : Any, T : Any>(private val provider: BodyProvider<S>, private val block: S.() -> T) : BodyProvider<T> {
|
||||
|
@ -2,12 +2,12 @@ group 'org.openapitools'
|
||||
version '1.0.0'
|
||||
|
||||
wrapper {
|
||||
gradleVersion = '6.8.3'
|
||||
gradleVersion = '7.5'
|
||||
distributionUrl = "https://services.gradle.org/distributions/gradle-$gradleVersion-all.zip"
|
||||
}
|
||||
|
||||
buildscript {
|
||||
ext.kotlin_version = '1.5.10'
|
||||
ext.kotlin_version = '1.6.10'
|
||||
|
||||
repositories {
|
||||
maven { url "https://repo1.maven.org/maven2" }
|
||||
@ -30,8 +30,8 @@ test {
|
||||
dependencies {
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
|
||||
implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
|
||||
implementation "com.squareup.moshi:moshi-kotlin:1.12.0"
|
||||
implementation "com.squareup.moshi:moshi-adapters:1.12.0"
|
||||
implementation "com.squareup.okhttp3:okhttp:4.9.1"
|
||||
implementation "com.squareup.moshi:moshi-kotlin:1.13.0"
|
||||
implementation "com.squareup.moshi:moshi-adapters:1.13.0"
|
||||
implementation "com.squareup.okhttp3:okhttp:4.10.0"
|
||||
testImplementation "io.kotlintest:kotlintest-runner-junit5:3.4.2"
|
||||
}
|
||||
|
@ -2,12 +2,12 @@ group 'org.openapitools'
|
||||
version '1.0.0'
|
||||
|
||||
wrapper {
|
||||
gradleVersion = '6.8.3'
|
||||
gradleVersion = '7.5'
|
||||
distributionUrl = "https://services.gradle.org/distributions/gradle-$gradleVersion-all.zip"
|
||||
}
|
||||
|
||||
buildscript {
|
||||
ext.kotlin_version = '1.5.10'
|
||||
ext.kotlin_version = '1.6.10'
|
||||
|
||||
repositories {
|
||||
maven { url "https://repo1.maven.org/maven2" }
|
||||
@ -30,8 +30,8 @@ test {
|
||||
dependencies {
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
|
||||
implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
|
||||
implementation "com.squareup.moshi:moshi-kotlin:1.12.0"
|
||||
implementation "com.squareup.moshi:moshi-adapters:1.12.0"
|
||||
implementation "com.squareup.moshi:moshi-kotlin:1.13.0"
|
||||
implementation "com.squareup.moshi:moshi-adapters:1.13.0"
|
||||
implementation "com.squareup.okhttp3:okhttp:3.12.13"
|
||||
testImplementation "io.kotlintest:kotlintest-runner-junit5:3.4.2"
|
||||
}
|
||||
|
@ -2,12 +2,12 @@ group 'org.openapitools'
|
||||
version '1.0.0'
|
||||
|
||||
wrapper {
|
||||
gradleVersion = '6.8.3'
|
||||
gradleVersion = '7.5'
|
||||
distributionUrl = "https://services.gradle.org/distributions/gradle-$gradleVersion-all.zip"
|
||||
}
|
||||
|
||||
buildscript {
|
||||
ext.kotlin_version = '1.5.10'
|
||||
ext.kotlin_version = '1.6.10'
|
||||
|
||||
repositories {
|
||||
maven { url "https://repo1.maven.org/maven2" }
|
||||
@ -30,8 +30,8 @@ test {
|
||||
dependencies {
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
|
||||
implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
|
||||
implementation "com.squareup.moshi:moshi-kotlin:1.12.0"
|
||||
implementation "com.squareup.moshi:moshi-adapters:1.12.0"
|
||||
implementation "com.squareup.okhttp3:okhttp:4.9.1"
|
||||
implementation "com.squareup.moshi:moshi-kotlin:1.13.0"
|
||||
implementation "com.squareup.moshi:moshi-adapters:1.13.0"
|
||||
implementation "com.squareup.okhttp3:okhttp:4.10.0"
|
||||
testImplementation "io.kotlintest:kotlintest-runner-junit5:3.4.2"
|
||||
}
|
||||
|
@ -2,12 +2,12 @@ group 'org.openapitools'
|
||||
version '1.0.0'
|
||||
|
||||
wrapper {
|
||||
gradleVersion = '6.8.3'
|
||||
gradleVersion = '7.5'
|
||||
distributionUrl = "https://services.gradle.org/distributions/gradle-$gradleVersion-all.zip"
|
||||
}
|
||||
|
||||
buildscript {
|
||||
ext.kotlin_version = '1.5.10'
|
||||
ext.kotlin_version = '1.6.10'
|
||||
ext.retrofitVersion = '2.9.0'
|
||||
|
||||
repositories {
|
||||
@ -31,9 +31,9 @@ test {
|
||||
dependencies {
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
|
||||
implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
|
||||
implementation "com.squareup.moshi:moshi-kotlin:1.12.0"
|
||||
implementation "com.squareup.moshi:moshi-adapters:1.12.0"
|
||||
implementation "com.squareup.okhttp3:logging-interceptor:4.9.1"
|
||||
implementation "com.squareup.moshi:moshi-kotlin:1.13.0"
|
||||
implementation "com.squareup.moshi:moshi-adapters:1.13.0"
|
||||
implementation "com.squareup.okhttp3:logging-interceptor:4.10.0"
|
||||
implementation "com.squareup.retrofit2:retrofit:$retrofitVersion"
|
||||
implementation "com.squareup.retrofit2:converter-moshi:$retrofitVersion"
|
||||
implementation "com.squareup.retrofit2:converter-scalars:$retrofitVersion"
|
||||
|
@ -8,10 +8,10 @@ plugins {
|
||||
group = "org.openapitools"
|
||||
version = "1.0.0"
|
||||
|
||||
val kotlin_version = "1.6.0"
|
||||
val coroutines_version = "1.5.2"
|
||||
val serialization_version = "1.3.0"
|
||||
val ktor_version = "1.6.4"
|
||||
val kotlin_version = "1.6.10"
|
||||
val coroutines_version = "1.6.3"
|
||||
val serialization_version = "1.3.3"
|
||||
val ktor_version = "2.0.3"
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
@ -30,9 +30,11 @@ kotlin {
|
||||
dependencies {
|
||||
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutines_version")
|
||||
implementation("org.jetbrains.kotlinx:kotlinx-serialization-core:$serialization_version")
|
||||
|
||||
api("io.ktor:ktor-client-core:$ktor_version")
|
||||
api("io.ktor:ktor-client-json:$ktor_version")
|
||||
api("io.ktor:ktor-client-serialization:$ktor_version")
|
||||
api("io.ktor:ktor-client-content-negotiation:$ktor_version")
|
||||
api("io.ktor:ktor-serialization-kotlinx-json:$ktor_version")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -25,7 +25,6 @@ import org.openapitools.client.infrastructure.*
|
||||
import io.ktor.client.HttpClientConfig
|
||||
import io.ktor.client.request.forms.formData
|
||||
import io.ktor.client.engine.HttpClientEngine
|
||||
import io.ktor.client.features.json.serializer.KotlinxSerializer
|
||||
import kotlinx.serialization.json.Json
|
||||
import io.ktor.http.ParametersBuilder
|
||||
import kotlinx.serialization.*
|
||||
|
@ -3,43 +3,31 @@ package org.openapitools.client.infrastructure
|
||||
import io.ktor.client.HttpClient
|
||||
import io.ktor.client.HttpClientConfig
|
||||
import io.ktor.client.engine.HttpClientEngine
|
||||
import io.ktor.client.features.json.JsonFeature
|
||||
import io.ktor.client.features.json.JsonSerializer
|
||||
import io.ktor.client.features.json.serializer.KotlinxSerializer
|
||||
import io.ktor.client.plugins.contentnegotiation.ContentNegotiation
|
||||
import io.ktor.serialization.kotlinx.json.*
|
||||
import io.ktor.client.request.*
|
||||
import io.ktor.client.request.forms.FormDataContent
|
||||
import io.ktor.client.request.forms.MultiPartFormDataContent
|
||||
import io.ktor.client.request.header
|
||||
import io.ktor.client.request.parameter
|
||||
import io.ktor.client.statement.HttpResponse
|
||||
import io.ktor.client.utils.EmptyContent
|
||||
import io.ktor.http.*
|
||||
import io.ktor.http.content.OutgoingContent
|
||||
import io.ktor.http.content.PartData
|
||||
import kotlin.Unit
|
||||
import kotlinx.serialization.json.Json
|
||||
|
||||
import org.openapitools.client.apis.*
|
||||
import org.openapitools.client.models.*
|
||||
import org.openapitools.client.auth.*
|
||||
|
||||
open class ApiClient(
|
||||
private val baseUrl: String,
|
||||
httpClientEngine: HttpClientEngine?,
|
||||
httpClientConfig: ((HttpClientConfig<*>) -> Unit)? = null,
|
||||
private val json: Json
|
||||
private val jsonBlock: Json
|
||||
) {
|
||||
|
||||
private val serializer: JsonSerializer by lazy {
|
||||
KotlinxSerializer(json).ignoreOutgoingContent()
|
||||
}
|
||||
|
||||
private val clientConfig: (HttpClientConfig<*>) -> Unit by lazy {
|
||||
{
|
||||
// Hold a reference to the serializer to avoid freezing the entire ApiClient instance
|
||||
// when the JsonFeature is configured.
|
||||
val serializerReference = serializer
|
||||
it.install(JsonFeature) { serializer = serializerReference }
|
||||
it.install(ContentNegotiation) { json(jsonBlock) }
|
||||
httpClientConfig?.invoke(it)
|
||||
}
|
||||
}
|
||||
@ -52,7 +40,11 @@ open class ApiClient(
|
||||
|
||||
companion object {
|
||||
const val BASE_URL = "http://localhost"
|
||||
val JSON_DEFAULT = Json { ignoreUnknownKeys = true }
|
||||
val JSON_DEFAULT = Json {
|
||||
ignoreUnknownKeys = true
|
||||
prettyPrint = true
|
||||
isLenient = true
|
||||
}
|
||||
protected val UNSAFE_HEADERS = listOf(HttpHeaders.ContentType)
|
||||
}
|
||||
|
||||
@ -132,18 +124,13 @@ open class ApiClient(
|
||||
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 {
|
||||
val contentType = (requestConfig.headers[HttpHeaders.ContentType]?.let { ContentType.parse(it) }
|
||||
?: ContentType.Application.Json)
|
||||
return if (body != null) request(requestConfig, serializer.write(body, contentType), authNames)
|
||||
else request(requestConfig, authNames = 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: Any?> request(requestConfig: RequestConfig<T>, body: OutgoingContent = EmptyContent, authNames: kotlin.collections.List<String>): HttpResponse {
|
||||
protected suspend fun <T: Any?> request(requestConfig: RequestConfig<T>, body: Any? = null, authNames: kotlin.collections.List<String>): HttpResponse {
|
||||
requestConfig.updateForAuth<T>(authNames)
|
||||
val headers = requestConfig.headers
|
||||
|
||||
return client.request<HttpResponse> {
|
||||
return client.request {
|
||||
this.url {
|
||||
this.takeFrom(URLBuilder(baseUrl))
|
||||
appendPath(requestConfig.path.trimStart('/').split('/'))
|
||||
@ -156,7 +143,7 @@ open class ApiClient(
|
||||
this.method = requestConfig.method.httpMethod
|
||||
headers.filter { header -> !UNSAFE_HEADERS.contains(header.key) }.forEach { header -> this.header(header.key, header.value) }
|
||||
if (requestConfig.method in listOf(RequestMethod.PUT, RequestMethod.POST, RequestMethod.PATCH))
|
||||
this.body = body
|
||||
this.setBody(body)
|
||||
|
||||
}
|
||||
}
|
||||
@ -183,13 +170,3 @@ open class ApiClient(
|
||||
RequestMethod.OPTIONS -> HttpMethod.Options
|
||||
}
|
||||
}
|
||||
|
||||
// https://github.com/ktorio/ktor/issues/851
|
||||
private fun JsonSerializer.ignoreOutgoingContent() = IgnoreOutgoingContentJsonSerializer(this)
|
||||
|
||||
private class IgnoreOutgoingContentJsonSerializer(private val delegate: JsonSerializer) : JsonSerializer by delegate {
|
||||
override fun write(data: Any): OutgoingContent {
|
||||
if (data is OutgoingContent) return data
|
||||
return delegate.write(data)
|
||||
}
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ private fun ByteArray.clearFrom(from: Int) = (from until size).forEach { this[it
|
||||
private fun Int.toBase64(): Char = BASE64_ALPHABET[this]
|
||||
private fun Byte.fromBase64(): Byte = BASE64_INVERSE_ALPHABET[toInt() and 0xff].toByte() and BASE64_MASK
|
||||
internal fun ByteArray.encodeBase64(): String = buildPacket { writeFully(this@encodeBase64) }.encodeBase64()
|
||||
internal fun String.decodeBase64Bytes(): ByteArray = buildPacket { writeStringUtf8(dropLastWhile { it == BASE64_PAD }) }.decodeBase64Bytes().readBytes()
|
||||
internal fun String.decodeBase64Bytes(): ByteArray = buildPacket { dropLastWhile { it == BASE64_PAD } }.decodeBase64Bytes().readBytes()
|
||||
|
||||
/**
|
||||
* Encode [bytes] as a HEX string with no spaces, newlines and `0x` prefixes.
|
||||
|
@ -1,9 +1,9 @@
|
||||
package org.openapitools.client.infrastructure
|
||||
|
||||
import io.ktor.client.call.TypeInfo
|
||||
import io.ktor.client.call.typeInfo
|
||||
import io.ktor.http.Headers
|
||||
import io.ktor.http.isSuccess
|
||||
import io.ktor.util.reflect.TypeInfo
|
||||
import io.ktor.util.reflect.typeInfo
|
||||
|
||||
open class HttpResponse<T : Any>(val response: io.ktor.client.statement.HttpResponse, val provider: BodyProvider<T>) {
|
||||
val status: Int = response.status.value
|
||||
@ -29,11 +29,11 @@ interface BodyProvider<T : Any> {
|
||||
class TypedBodyProvider<T : Any>(private val type: TypeInfo) : BodyProvider<T> {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
override suspend fun body(response: io.ktor.client.statement.HttpResponse): T =
|
||||
response.call.receive(type) as T
|
||||
response.call.body(type) as T
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
override suspend fun <V : Any> typedBody(response: io.ktor.client.statement.HttpResponse, type: TypeInfo): V =
|
||||
response.call.receive(type) as V
|
||||
response.call.body(type) as V
|
||||
}
|
||||
|
||||
class MappedBodyProvider<S : Any, T : Any>(private val provider: BodyProvider<S>, private val block: S.() -> T) : BodyProvider<T> {
|
||||
|
@ -2,12 +2,12 @@ group 'org.openapitools'
|
||||
version '1.0.0'
|
||||
|
||||
wrapper {
|
||||
gradleVersion = '6.8.3'
|
||||
gradleVersion = '7.5'
|
||||
distributionUrl = "https://services.gradle.org/distributions/gradle-$gradleVersion-all.zip"
|
||||
}
|
||||
|
||||
buildscript {
|
||||
ext.kotlin_version = '1.5.10'
|
||||
ext.kotlin_version = '1.6.10'
|
||||
|
||||
repositories {
|
||||
maven { url "https://repo1.maven.org/maven2" }
|
||||
@ -30,8 +30,8 @@ test {
|
||||
dependencies {
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
|
||||
implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
|
||||
implementation "com.squareup.moshi:moshi-kotlin:1.12.0"
|
||||
implementation "com.squareup.moshi:moshi-adapters:1.12.0"
|
||||
implementation "com.squareup.okhttp3:okhttp:4.9.1"
|
||||
implementation "com.squareup.moshi:moshi-kotlin:1.13.0"
|
||||
implementation "com.squareup.moshi:moshi-adapters:1.13.0"
|
||||
implementation "com.squareup.okhttp3:okhttp:4.10.0"
|
||||
testImplementation "io.kotlintest:kotlintest-runner-junit5:3.4.2"
|
||||
}
|
||||
|
@ -2,12 +2,12 @@ group 'org.openapitools'
|
||||
version '1.0.0'
|
||||
|
||||
wrapper {
|
||||
gradleVersion = '6.8.3'
|
||||
gradleVersion = '7.5'
|
||||
distributionUrl = "https://services.gradle.org/distributions/gradle-$gradleVersion-all.zip"
|
||||
}
|
||||
|
||||
buildscript {
|
||||
ext.kotlin_version = '1.5.10'
|
||||
ext.kotlin_version = '1.6.10'
|
||||
|
||||
repositories {
|
||||
maven { url "https://repo1.maven.org/maven2" }
|
||||
@ -29,7 +29,7 @@ test {
|
||||
|
||||
dependencies {
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
|
||||
implementation "com.google.code.gson:gson:2.8.7"
|
||||
implementation "com.squareup.okhttp3:okhttp:4.9.1"
|
||||
implementation "com.google.code.gson:gson:2.9.0"
|
||||
implementation "com.squareup.okhttp3:okhttp:4.10.0"
|
||||
testImplementation "io.kotlintest:kotlintest-runner-junit5:3.4.2"
|
||||
}
|
||||
|
@ -2,12 +2,12 @@ group 'org.openapitools'
|
||||
version '1.0.0'
|
||||
|
||||
wrapper {
|
||||
gradleVersion = '6.8.3'
|
||||
gradleVersion = '7.5'
|
||||
distributionUrl = "https://services.gradle.org/distributions/gradle-$gradleVersion-all.zip"
|
||||
}
|
||||
|
||||
buildscript {
|
||||
ext.kotlin_version = '1.5.10'
|
||||
ext.kotlin_version = '1.6.10'
|
||||
|
||||
repositories {
|
||||
maven { url "https://repo1.maven.org/maven2" }
|
||||
@ -30,8 +30,8 @@ test {
|
||||
dependencies {
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
|
||||
implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
|
||||
implementation "com.fasterxml.jackson.module:jackson-module-kotlin:2.12.3"
|
||||
implementation "com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.12.3"
|
||||
implementation "com.squareup.okhttp3:okhttp:4.9.1"
|
||||
implementation "com.fasterxml.jackson.module:jackson-module-kotlin:2.13.3"
|
||||
implementation "com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.13.3"
|
||||
implementation "com.squareup.okhttp3:okhttp:4.10.0"
|
||||
testImplementation "io.kotlintest:kotlintest-runner-junit5:3.4.2"
|
||||
}
|
||||
|
@ -2,12 +2,12 @@ group 'org.openapitools'
|
||||
version '1.0.0'
|
||||
|
||||
wrapper {
|
||||
gradleVersion = '6.8.3'
|
||||
gradleVersion = '7.5'
|
||||
distributionUrl = "https://services.gradle.org/distributions/gradle-$gradleVersion-all.zip"
|
||||
}
|
||||
|
||||
buildscript {
|
||||
ext.kotlin_version = '1.5.10'
|
||||
ext.kotlin_version = '1.6.10'
|
||||
|
||||
repositories {
|
||||
maven { url "https://repo1.maven.org/maven2" }
|
||||
@ -32,8 +32,8 @@ test {
|
||||
|
||||
dependencies {
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
|
||||
implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.2.1"
|
||||
implementation "com.squareup.okhttp3:okhttp:4.9.1"
|
||||
implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.3.3"
|
||||
implementation "com.squareup.okhttp3:okhttp:4.10.0"
|
||||
testImplementation "io.kotlintest:kotlintest-runner-junit5:3.4.2"
|
||||
}
|
||||
|
||||
|
@ -2,13 +2,13 @@ group 'org.openapitools'
|
||||
version '1.0.0'
|
||||
|
||||
wrapper {
|
||||
gradleVersion = '6.8.3'
|
||||
gradleVersion = '7.5'
|
||||
distributionUrl = "https://services.gradle.org/distributions/gradle-$gradleVersion-all.zip"
|
||||
}
|
||||
|
||||
buildscript {
|
||||
ext.kotlin_version = '1.5.10'
|
||||
ext.ktor_version = '1.6.7'
|
||||
ext.kotlin_version = '1.6.10'
|
||||
ext.ktor_version = '2.0.3'
|
||||
|
||||
repositories {
|
||||
maven { url "https://repo1.maven.org/maven2" }
|
||||
@ -30,8 +30,10 @@ test {
|
||||
|
||||
dependencies {
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
|
||||
implementation "com.google.code.gson:gson:2.8.7"
|
||||
implementation "com.google.code.gson:gson:2.9.0"
|
||||
implementation "io.ktor:ktor-client-core:$ktor_version"
|
||||
implementation "io.ktor:ktor-client-content-negotiation:$ktor_version"
|
||||
implementation "io.ktor:ktor-serialization-gson:$ktor_version"
|
||||
implementation "io.ktor:ktor-client-gson:$ktor_version"
|
||||
testImplementation "io.kotlintest:kotlintest-runner-junit5:3.4.2"
|
||||
}
|
||||
|
@ -28,15 +28,16 @@ import io.ktor.client.HttpClientConfig
|
||||
import io.ktor.client.request.forms.formData
|
||||
import io.ktor.client.engine.HttpClientEngine
|
||||
import io.ktor.http.ParametersBuilder
|
||||
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.GsonBuilder
|
||||
import java.text.DateFormat
|
||||
|
||||
open class PetApi(
|
||||
baseUrl: String = ApiClient.BASE_URL,
|
||||
httpClientEngine: HttpClientEngine? = null,
|
||||
httpClientConfig: ((HttpClientConfig<*>) -> Unit)? = null,
|
||||
json: Gson = ApiClient.JSON_DEFAULT,
|
||||
) : ApiClient(baseUrl, httpClientEngine, httpClientConfig, json) {
|
||||
jsonBlock: GsonBuilder.() -> Unit = ApiClient.JSON_DEFAULT,
|
||||
) : ApiClient(baseUrl, httpClientEngine, httpClientConfig, jsonBlock) {
|
||||
|
||||
/**
|
||||
* Add a new pet to the store
|
||||
|
@ -27,15 +27,16 @@ import io.ktor.client.HttpClientConfig
|
||||
import io.ktor.client.request.forms.formData
|
||||
import io.ktor.client.engine.HttpClientEngine
|
||||
import io.ktor.http.ParametersBuilder
|
||||
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.GsonBuilder
|
||||
import java.text.DateFormat
|
||||
|
||||
open class StoreApi(
|
||||
baseUrl: String = ApiClient.BASE_URL,
|
||||
httpClientEngine: HttpClientEngine? = null,
|
||||
httpClientConfig: ((HttpClientConfig<*>) -> Unit)? = null,
|
||||
json: Gson = ApiClient.JSON_DEFAULT,
|
||||
) : ApiClient(baseUrl, httpClientEngine, httpClientConfig, json) {
|
||||
jsonBlock: GsonBuilder.() -> Unit = ApiClient.JSON_DEFAULT,
|
||||
) : ApiClient(baseUrl, httpClientEngine, httpClientConfig, jsonBlock) {
|
||||
|
||||
/**
|
||||
* Delete purchase order by ID
|
||||
|
@ -27,15 +27,16 @@ import io.ktor.client.HttpClientConfig
|
||||
import io.ktor.client.request.forms.formData
|
||||
import io.ktor.client.engine.HttpClientEngine
|
||||
import io.ktor.http.ParametersBuilder
|
||||
|
||||
import com.google.gson.Gson
|
||||
import com.google.gson.GsonBuilder
|
||||
import java.text.DateFormat
|
||||
|
||||
open class UserApi(
|
||||
baseUrl: String = ApiClient.BASE_URL,
|
||||
httpClientEngine: HttpClientEngine? = null,
|
||||
httpClientConfig: ((HttpClientConfig<*>) -> Unit)? = null,
|
||||
json: Gson = ApiClient.JSON_DEFAULT,
|
||||
) : ApiClient(baseUrl, httpClientEngine, httpClientConfig, json) {
|
||||
jsonBlock: GsonBuilder.() -> Unit = ApiClient.JSON_DEFAULT,
|
||||
) : ApiClient(baseUrl, httpClientEngine, httpClientConfig, jsonBlock) {
|
||||
|
||||
/**
|
||||
* Create user
|
||||
|
@ -1,45 +1,47 @@
|
||||
package org.openapitools.client.infrastructure
|
||||
|
||||
|
||||
import io.ktor.client.HttpClient
|
||||
import io.ktor.client.HttpClientConfig
|
||||
import io.ktor.client.engine.HttpClientEngine
|
||||
import io.ktor.client.features.json.JsonFeature
|
||||
import io.ktor.client.features.json.JsonSerializer
|
||||
import io.ktor.client.request.*
|
||||
import io.ktor.client.plugins.contentnegotiation.ContentNegotiation
|
||||
import io.ktor.client.request.forms.FormDataContent
|
||||
import io.ktor.client.request.forms.MultiPartFormDataContent
|
||||
import io.ktor.client.request.header
|
||||
import io.ktor.client.request.parameter
|
||||
import io.ktor.client.request.request
|
||||
import io.ktor.client.request.setBody
|
||||
import io.ktor.client.statement.HttpResponse
|
||||
import io.ktor.client.utils.EmptyContent
|
||||
import io.ktor.http.*
|
||||
import io.ktor.http.content.ByteArrayContent
|
||||
import io.ktor.http.content.OutgoingContent
|
||||
import io.ktor.http.HttpHeaders
|
||||
import io.ktor.http.HttpMethod
|
||||
import io.ktor.http.Parameters
|
||||
import io.ktor.http.URLBuilder
|
||||
import io.ktor.http.content.PartData
|
||||
import kotlin.Unit
|
||||
|
||||
import com.google.gson.Gson
|
||||
import java.nio.charset.StandardCharsets
|
||||
|
||||
import io.ktor.http.encodeURLQueryComponent
|
||||
import io.ktor.http.encodedPath
|
||||
import io.ktor.http.takeFrom
|
||||
import io.ktor.serialization.gson.*
|
||||
import com.google.gson.GsonBuilder
|
||||
import java.text.DateFormat
|
||||
import org.openapitools.client.auth.ApiKeyAuth
|
||||
import org.openapitools.client.auth.Authentication
|
||||
import org.openapitools.client.auth.HttpBasicAuth
|
||||
import org.openapitools.client.auth.HttpBearerAuth
|
||||
import org.openapitools.client.auth.OAuth
|
||||
import org.openapitools.client.auth.*
|
||||
|
||||
open class ApiClient(
|
||||
private val baseUrl: String,
|
||||
httpClientEngine: HttpClientEngine?,
|
||||
httpClientConfig: ((HttpClientConfig<*>) -> Unit)? = null,
|
||||
json: Gson,
|
||||
jsonBlock: GsonBuilder.() -> Unit = JSON_DEFAULT,
|
||||
) {
|
||||
|
||||
private val serializer: JsonSerializer by lazy {
|
||||
JsonSerializerImpl(json)
|
||||
}
|
||||
|
||||
private val clientConfig: (HttpClientConfig<*>) -> Unit by lazy {
|
||||
{
|
||||
// Hold a reference to the serializer to avoid freezing the entire ApiClient instance
|
||||
// when the JsonFeature is configured.
|
||||
val serializerReference = serializer
|
||||
it.install(JsonFeature) { serializer = serializerReference }
|
||||
it.install(ContentNegotiation) {
|
||||
gson { jsonBlock() }
|
||||
}
|
||||
httpClientConfig?.invoke(it)
|
||||
}
|
||||
}
|
||||
@ -55,9 +57,12 @@ open class ApiClient(
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val BASE_URL = "http://petstore.swagger.io/v2"
|
||||
val JSON_DEFAULT = Gson()
|
||||
protected val UNSAFE_HEADERS = listOf(HttpHeaders.ContentType)
|
||||
const val BASE_URL = "http://petstore.swagger.io/v2"
|
||||
val JSON_DEFAULT : GsonBuilder.() -> Unit = {
|
||||
setDateFormat(DateFormat.LONG)
|
||||
setPrettyPrinting()
|
||||
}
|
||||
protected val UNSAFE_HEADERS = listOf(HttpHeaders.ContentType)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -66,7 +71,7 @@ open class ApiClient(
|
||||
* @param username Username
|
||||
*/
|
||||
fun setUsername(username: String) {
|
||||
val auth = authentications?.values?.firstOrNull { it is HttpBasicAuth } as HttpBasicAuth?
|
||||
val auth = authentications.values.firstOrNull { it is HttpBasicAuth } as HttpBasicAuth?
|
||||
?: throw Exception("No HTTP basic authentication configured")
|
||||
auth.username = username
|
||||
}
|
||||
@ -77,7 +82,7 @@ open class ApiClient(
|
||||
* @param password Password
|
||||
*/
|
||||
fun setPassword(password: String) {
|
||||
val auth = authentications?.values?.firstOrNull { it is HttpBasicAuth } as HttpBasicAuth?
|
||||
val auth = authentications.values.firstOrNull { it is HttpBasicAuth } as HttpBasicAuth?
|
||||
?: throw Exception("No HTTP basic authentication configured")
|
||||
auth.password = password
|
||||
}
|
||||
@ -89,7 +94,7 @@ open class ApiClient(
|
||||
* @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?
|
||||
val auth = authentications.values.firstOrNull { it is ApiKeyAuth && (paramName == null || paramName == it.paramName)} as ApiKeyAuth?
|
||||
?: throw Exception("No API key authentication configured")
|
||||
auth.apiKey = apiKey
|
||||
}
|
||||
@ -101,7 +106,7 @@ open class ApiClient(
|
||||
* @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?
|
||||
val auth = authentications.values.firstOrNull { it is ApiKeyAuth && (paramName == null || paramName == it.paramName) } as ApiKeyAuth?
|
||||
?: throw Exception("No API key authentication configured")
|
||||
auth.apiKeyPrefix = apiKeyPrefix
|
||||
}
|
||||
@ -112,7 +117,7 @@ open class ApiClient(
|
||||
* @param accessToken Access token
|
||||
*/
|
||||
fun setAccessToken(accessToken: String) {
|
||||
val auth = authentications?.values?.firstOrNull { it is OAuth } as OAuth?
|
||||
val auth = authentications.values.firstOrNull { it is OAuth } as OAuth?
|
||||
?: throw Exception("No OAuth2 authentication configured")
|
||||
auth.accessToken = accessToken
|
||||
}
|
||||
@ -123,7 +128,7 @@ open class ApiClient(
|
||||
* @param bearerToken The bearer token.
|
||||
*/
|
||||
fun setBearerToken(bearerToken: String) {
|
||||
val auth = authentications?.values?.firstOrNull { it is HttpBearerAuth } as HttpBearerAuth?
|
||||
val auth = authentications.values.firstOrNull { it is HttpBearerAuth } as HttpBearerAuth?
|
||||
?: throw Exception("No Bearer authentication configured")
|
||||
auth.bearerToken = bearerToken
|
||||
}
|
||||
@ -136,18 +141,13 @@ open class ApiClient(
|
||||
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 {
|
||||
val contentType = (requestConfig.headers[HttpHeaders.ContentType]?.let { ContentType.parse(it) }
|
||||
?: ContentType.Application.Json)
|
||||
return if (body != null) request(requestConfig, serializer.write(body, contentType), authNames)
|
||||
else request(requestConfig, authNames = 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: Any?> request(requestConfig: RequestConfig<T>, body: OutgoingContent = EmptyContent, authNames: kotlin.collections.List<String>): HttpResponse {
|
||||
protected suspend fun <T: Any?> request(requestConfig: RequestConfig<T>, body: Any? = null, authNames: kotlin.collections.List<String>): HttpResponse {
|
||||
requestConfig.updateForAuth<T>(authNames)
|
||||
val headers = requestConfig.headers
|
||||
|
||||
return client.request<HttpResponse> {
|
||||
return client.request {
|
||||
this.url {
|
||||
this.takeFrom(URLBuilder(baseUrl))
|
||||
appendPath(requestConfig.path.trimStart('/').split('/'))
|
||||
@ -160,8 +160,7 @@ open class ApiClient(
|
||||
this.method = requestConfig.method.httpMethod
|
||||
headers.filter { header -> !UNSAFE_HEADERS.contains(header.key) }.forEach { header -> this.header(header.key, header.value) }
|
||||
if (requestConfig.method in listOf(RequestMethod.PUT, RequestMethod.POST, RequestMethod.PATCH))
|
||||
this.body = body
|
||||
|
||||
setBody(body)
|
||||
}
|
||||
}
|
||||
|
||||
@ -187,10 +186,3 @@ open class ApiClient(
|
||||
RequestMethod.OPTIONS -> HttpMethod.Options
|
||||
}
|
||||
}
|
||||
|
||||
private class JsonSerializerImpl(private val gson: Gson) : JsonSerializer {
|
||||
override fun write(data: Any, contentType: ContentType): OutgoingContent =
|
||||
ByteArrayContent(gson.toJson(data).toByteArray(StandardCharsets.UTF_8), contentType)
|
||||
}
|
||||
|
||||
|
||||
|
@ -1,9 +1,9 @@
|
||||
package org.openapitools.client.infrastructure
|
||||
|
||||
import io.ktor.client.call.TypeInfo
|
||||
import io.ktor.client.call.typeInfo
|
||||
import io.ktor.http.Headers
|
||||
import io.ktor.http.isSuccess
|
||||
import io.ktor.util.reflect.TypeInfo
|
||||
import io.ktor.util.reflect.typeInfo
|
||||
|
||||
open class HttpResponse<T : Any>(val response: io.ktor.client.statement.HttpResponse, val provider: BodyProvider<T>) {
|
||||
val status: Int = response.status.value
|
||||
@ -29,11 +29,11 @@ interface BodyProvider<T : Any> {
|
||||
class TypedBodyProvider<T : Any>(private val type: TypeInfo) : BodyProvider<T> {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
override suspend fun body(response: io.ktor.client.statement.HttpResponse): T =
|
||||
response.call.receive(type) as T
|
||||
response.call.body(type) as T
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
override suspend fun <V : Any> typedBody(response: io.ktor.client.statement.HttpResponse, type: TypeInfo): V =
|
||||
response.call.receive(type) as V
|
||||
response.call.body(type) as V
|
||||
}
|
||||
|
||||
class MappedBodyProvider<S : Any, T : Any>(private val provider: BodyProvider<S>, private val block: S.() -> T) : BodyProvider<T> {
|
||||
|
@ -2,13 +2,13 @@ group 'org.openapitools'
|
||||
version '1.0.0'
|
||||
|
||||
wrapper {
|
||||
gradleVersion = '6.8.3'
|
||||
gradleVersion = '7.5'
|
||||
distributionUrl = "https://services.gradle.org/distributions/gradle-$gradleVersion-all.zip"
|
||||
}
|
||||
|
||||
buildscript {
|
||||
ext.kotlin_version = '1.5.10'
|
||||
ext.ktor_version = '1.6.7'
|
||||
ext.kotlin_version = '1.6.10'
|
||||
ext.ktor_version = '2.0.3'
|
||||
|
||||
repositories {
|
||||
maven { url "https://repo1.maven.org/maven2" }
|
||||
@ -31,9 +31,11 @@ test {
|
||||
dependencies {
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
|
||||
implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
|
||||
implementation "com.fasterxml.jackson.module:jackson-module-kotlin:2.12.3"
|
||||
implementation "com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.12.3"
|
||||
implementation "com.fasterxml.jackson.module:jackson-module-kotlin:2.13.3"
|
||||
implementation "com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.13.3"
|
||||
implementation "io.ktor:ktor-client-core:$ktor_version"
|
||||
implementation "io.ktor:ktor-client-content-negotiation:$ktor_version"
|
||||
implementation "io.ktor:ktor-client-jackson:$ktor_version"
|
||||
implementation "io.ktor:ktor-serialization-jackson:$ktor_version"
|
||||
testImplementation "io.kotlintest:kotlintest-runner-junit5:3.4.2"
|
||||
}
|
||||
|
@ -28,15 +28,14 @@ import io.ktor.client.HttpClientConfig
|
||||
import io.ktor.client.request.forms.formData
|
||||
import io.ktor.client.engine.HttpClientEngine
|
||||
import io.ktor.http.ParametersBuilder
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper
|
||||
|
||||
open class PetApi(
|
||||
baseUrl: String = ApiClient.BASE_URL,
|
||||
httpClientEngine: HttpClientEngine? = null,
|
||||
httpClientConfig: ((HttpClientConfig<*>) -> Unit)? = null,
|
||||
json: ObjectMapper = ApiClient.JSON_DEFAULT,
|
||||
) : ApiClient(baseUrl, httpClientEngine, httpClientConfig, json) {
|
||||
jsonBlock: ObjectMapper.() -> Unit = ApiClient.JSON_DEFAULT,
|
||||
) : ApiClient(baseUrl, httpClientEngine, httpClientConfig, jsonBlock) {
|
||||
|
||||
/**
|
||||
* Add a new pet to the store
|
||||
|
@ -27,15 +27,14 @@ import io.ktor.client.HttpClientConfig
|
||||
import io.ktor.client.request.forms.formData
|
||||
import io.ktor.client.engine.HttpClientEngine
|
||||
import io.ktor.http.ParametersBuilder
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper
|
||||
|
||||
open class StoreApi(
|
||||
baseUrl: String = ApiClient.BASE_URL,
|
||||
httpClientEngine: HttpClientEngine? = null,
|
||||
httpClientConfig: ((HttpClientConfig<*>) -> Unit)? = null,
|
||||
json: ObjectMapper = ApiClient.JSON_DEFAULT,
|
||||
) : ApiClient(baseUrl, httpClientEngine, httpClientConfig, json) {
|
||||
jsonBlock: ObjectMapper.() -> Unit = ApiClient.JSON_DEFAULT,
|
||||
) : ApiClient(baseUrl, httpClientEngine, httpClientConfig, jsonBlock) {
|
||||
|
||||
/**
|
||||
* Delete purchase order by ID
|
||||
|
@ -27,15 +27,14 @@ import io.ktor.client.HttpClientConfig
|
||||
import io.ktor.client.request.forms.formData
|
||||
import io.ktor.client.engine.HttpClientEngine
|
||||
import io.ktor.http.ParametersBuilder
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper
|
||||
|
||||
open class UserApi(
|
||||
baseUrl: String = ApiClient.BASE_URL,
|
||||
httpClientEngine: HttpClientEngine? = null,
|
||||
httpClientConfig: ((HttpClientConfig<*>) -> Unit)? = null,
|
||||
json: ObjectMapper = ApiClient.JSON_DEFAULT,
|
||||
) : ApiClient(baseUrl, httpClientEngine, httpClientConfig, json) {
|
||||
jsonBlock: ObjectMapper.() -> Unit = ApiClient.JSON_DEFAULT,
|
||||
) : ApiClient(baseUrl, httpClientEngine, httpClientConfig, jsonBlock) {
|
||||
|
||||
/**
|
||||
* Create user
|
||||
|
@ -1,44 +1,51 @@
|
||||
package org.openapitools.client.infrastructure
|
||||
|
||||
|
||||
import io.ktor.client.HttpClient
|
||||
import io.ktor.client.HttpClientConfig
|
||||
import io.ktor.client.engine.HttpClientEngine
|
||||
import io.ktor.client.features.json.JsonFeature
|
||||
import io.ktor.client.features.json.JsonSerializer
|
||||
import io.ktor.client.request.*
|
||||
import io.ktor.client.plugins.contentnegotiation.ContentNegotiation
|
||||
import io.ktor.client.request.forms.FormDataContent
|
||||
import io.ktor.client.request.forms.MultiPartFormDataContent
|
||||
import io.ktor.client.request.header
|
||||
import io.ktor.client.request.parameter
|
||||
import io.ktor.client.request.request
|
||||
import io.ktor.client.request.setBody
|
||||
import io.ktor.client.statement.HttpResponse
|
||||
import io.ktor.client.utils.EmptyContent
|
||||
import io.ktor.http.*
|
||||
import io.ktor.http.content.ByteArrayContent
|
||||
import io.ktor.http.content.OutgoingContent
|
||||
import io.ktor.http.HttpHeaders
|
||||
import io.ktor.http.HttpMethod
|
||||
import io.ktor.http.Parameters
|
||||
import io.ktor.http.URLBuilder
|
||||
import io.ktor.http.content.PartData
|
||||
import kotlin.Unit
|
||||
|
||||
import io.ktor.http.encodeURLQueryComponent
|
||||
import io.ktor.http.encodedPath
|
||||
import io.ktor.http.takeFrom
|
||||
import io.ktor.serialization.jackson.*
|
||||
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
|
||||
import com.fasterxml.jackson.databind.ObjectMapper
|
||||
|
||||
import com.fasterxml.jackson.databind.SerializationFeature
|
||||
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule
|
||||
import com.fasterxml.jackson.core.util.DefaultIndenter
|
||||
import com.fasterxml.jackson.core.util.DefaultPrettyPrinter
|
||||
import org.openapitools.client.auth.ApiKeyAuth
|
||||
import org.openapitools.client.auth.Authentication
|
||||
import org.openapitools.client.auth.HttpBasicAuth
|
||||
import org.openapitools.client.auth.HttpBearerAuth
|
||||
import org.openapitools.client.auth.OAuth
|
||||
import org.openapitools.client.auth.*
|
||||
|
||||
open class ApiClient(
|
||||
private val baseUrl: String,
|
||||
httpClientEngine: HttpClientEngine?,
|
||||
httpClientConfig: ((HttpClientConfig<*>) -> Unit)? = null,
|
||||
json: ObjectMapper,
|
||||
jsonBlock: ObjectMapper.() -> Unit = JSON_DEFAULT,
|
||||
) {
|
||||
|
||||
private val serializer: JsonSerializer by lazy {
|
||||
JsonSerializerImpl(json)
|
||||
}
|
||||
|
||||
private val clientConfig: (HttpClientConfig<*>) -> Unit by lazy {
|
||||
{
|
||||
// Hold a reference to the serializer to avoid freezing the entire ApiClient instance
|
||||
// when the JsonFeature is configured.
|
||||
val serializerReference = serializer
|
||||
it.install(JsonFeature) { serializer = serializerReference }
|
||||
it.install(ContentNegotiation) {
|
||||
jackson { jsonBlock() }
|
||||
}
|
||||
httpClientConfig?.invoke(it)
|
||||
}
|
||||
}
|
||||
@ -54,9 +61,16 @@ open class ApiClient(
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val BASE_URL = "http://petstore.swagger.io/v2"
|
||||
val JSON_DEFAULT = ObjectMapper()
|
||||
protected val UNSAFE_HEADERS = listOf(HttpHeaders.ContentType)
|
||||
const val BASE_URL = "http://petstore.swagger.io/v2"
|
||||
val JSON_DEFAULT: ObjectMapper.() -> Unit = {
|
||||
configure(SerializationFeature.INDENT_OUTPUT, true)
|
||||
setDefaultPrettyPrinter(DefaultPrettyPrinter().apply {
|
||||
indentArraysWith(DefaultPrettyPrinter.FixedSpaceIndenter.instance)
|
||||
indentObjectsWith(DefaultIndenter(" ", "\n"))
|
||||
})
|
||||
registerModule(JavaTimeModule())
|
||||
}
|
||||
protected val UNSAFE_HEADERS = listOf(HttpHeaders.ContentType)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -65,7 +79,7 @@ open class ApiClient(
|
||||
* @param username Username
|
||||
*/
|
||||
fun setUsername(username: String) {
|
||||
val auth = authentications?.values?.firstOrNull { it is HttpBasicAuth } as HttpBasicAuth?
|
||||
val auth = authentications.values.firstOrNull { it is HttpBasicAuth } as HttpBasicAuth?
|
||||
?: throw Exception("No HTTP basic authentication configured")
|
||||
auth.username = username
|
||||
}
|
||||
@ -76,7 +90,7 @@ open class ApiClient(
|
||||
* @param password Password
|
||||
*/
|
||||
fun setPassword(password: String) {
|
||||
val auth = authentications?.values?.firstOrNull { it is HttpBasicAuth } as HttpBasicAuth?
|
||||
val auth = authentications.values.firstOrNull { it is HttpBasicAuth } as HttpBasicAuth?
|
||||
?: throw Exception("No HTTP basic authentication configured")
|
||||
auth.password = password
|
||||
}
|
||||
@ -88,7 +102,7 @@ open class ApiClient(
|
||||
* @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?
|
||||
val auth = authentications.values.firstOrNull { it is ApiKeyAuth && (paramName == null || paramName == it.paramName)} as ApiKeyAuth?
|
||||
?: throw Exception("No API key authentication configured")
|
||||
auth.apiKey = apiKey
|
||||
}
|
||||
@ -100,7 +114,7 @@ open class ApiClient(
|
||||
* @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?
|
||||
val auth = authentications.values.firstOrNull { it is ApiKeyAuth && (paramName == null || paramName == it.paramName) } as ApiKeyAuth?
|
||||
?: throw Exception("No API key authentication configured")
|
||||
auth.apiKeyPrefix = apiKeyPrefix
|
||||
}
|
||||
@ -111,7 +125,7 @@ open class ApiClient(
|
||||
* @param accessToken Access token
|
||||
*/
|
||||
fun setAccessToken(accessToken: String) {
|
||||
val auth = authentications?.values?.firstOrNull { it is OAuth } as OAuth?
|
||||
val auth = authentications.values.firstOrNull { it is OAuth } as OAuth?
|
||||
?: throw Exception("No OAuth2 authentication configured")
|
||||
auth.accessToken = accessToken
|
||||
}
|
||||
@ -122,7 +136,7 @@ open class ApiClient(
|
||||
* @param bearerToken The bearer token.
|
||||
*/
|
||||
fun setBearerToken(bearerToken: String) {
|
||||
val auth = authentications?.values?.firstOrNull { it is HttpBearerAuth } as HttpBearerAuth?
|
||||
val auth = authentications.values.firstOrNull { it is HttpBearerAuth } as HttpBearerAuth?
|
||||
?: throw Exception("No Bearer authentication configured")
|
||||
auth.bearerToken = bearerToken
|
||||
}
|
||||
@ -135,18 +149,13 @@ open class ApiClient(
|
||||
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 {
|
||||
val contentType = (requestConfig.headers[HttpHeaders.ContentType]?.let { ContentType.parse(it) }
|
||||
?: ContentType.Application.Json)
|
||||
return if (body != null) request(requestConfig, serializer.write(body, contentType), authNames)
|
||||
else request(requestConfig, authNames = 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: Any?> request(requestConfig: RequestConfig<T>, body: OutgoingContent = EmptyContent, authNames: kotlin.collections.List<String>): HttpResponse {
|
||||
protected suspend fun <T: Any?> request(requestConfig: RequestConfig<T>, body: Any? = null, authNames: kotlin.collections.List<String>): HttpResponse {
|
||||
requestConfig.updateForAuth<T>(authNames)
|
||||
val headers = requestConfig.headers
|
||||
|
||||
return client.request<HttpResponse> {
|
||||
return client.request {
|
||||
this.url {
|
||||
this.takeFrom(URLBuilder(baseUrl))
|
||||
appendPath(requestConfig.path.trimStart('/').split('/'))
|
||||
@ -159,8 +168,7 @@ open class ApiClient(
|
||||
this.method = requestConfig.method.httpMethod
|
||||
headers.filter { header -> !UNSAFE_HEADERS.contains(header.key) }.forEach { header -> this.header(header.key, header.value) }
|
||||
if (requestConfig.method in listOf(RequestMethod.PUT, RequestMethod.POST, RequestMethod.PATCH))
|
||||
this.body = body
|
||||
|
||||
setBody(body)
|
||||
}
|
||||
}
|
||||
|
||||
@ -186,10 +194,3 @@ open class ApiClient(
|
||||
RequestMethod.OPTIONS -> HttpMethod.Options
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
private class JsonSerializerImpl(private val objectMapper: ObjectMapper) : JsonSerializer {
|
||||
override fun write(data: Any, contentType: ContentType): OutgoingContent =
|
||||
ByteArrayContent(objectMapper.writeValueAsBytes(data), contentType)
|
||||
}
|
||||
|
@ -1,9 +1,9 @@
|
||||
package org.openapitools.client.infrastructure
|
||||
|
||||
import io.ktor.client.call.TypeInfo
|
||||
import io.ktor.client.call.typeInfo
|
||||
import io.ktor.http.Headers
|
||||
import io.ktor.http.isSuccess
|
||||
import io.ktor.util.reflect.TypeInfo
|
||||
import io.ktor.util.reflect.typeInfo
|
||||
|
||||
open class HttpResponse<T : Any>(val response: io.ktor.client.statement.HttpResponse, val provider: BodyProvider<T>) {
|
||||
val status: Int = response.status.value
|
||||
@ -29,11 +29,11 @@ interface BodyProvider<T : Any> {
|
||||
class TypedBodyProvider<T : Any>(private val type: TypeInfo) : BodyProvider<T> {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
override suspend fun body(response: io.ktor.client.statement.HttpResponse): T =
|
||||
response.call.receive(type) as T
|
||||
response.call.body(type) as T
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
override suspend fun <V : Any> typedBody(response: io.ktor.client.statement.HttpResponse, type: TypeInfo): V =
|
||||
response.call.receive(type) as V
|
||||
response.call.body(type) as V
|
||||
}
|
||||
|
||||
class MappedBodyProvider<S : Any, T : Any>(private val provider: BodyProvider<S>, private val block: S.() -> T) : BodyProvider<T> {
|
||||
|
@ -2,12 +2,12 @@ group 'org.openapitools'
|
||||
version '1.0.0'
|
||||
|
||||
wrapper {
|
||||
gradleVersion = '6.8.3'
|
||||
gradleVersion = '7.5'
|
||||
distributionUrl = "https://services.gradle.org/distributions/gradle-$gradleVersion-all.zip"
|
||||
}
|
||||
|
||||
buildscript {
|
||||
ext.kotlin_version = '1.5.10'
|
||||
ext.kotlin_version = '1.6.10'
|
||||
|
||||
repositories {
|
||||
maven { url "https://repo1.maven.org/maven2" }
|
||||
@ -29,8 +29,8 @@ test {
|
||||
|
||||
dependencies {
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
|
||||
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.5.1"
|
||||
implementation "com.google.code.gson:gson:2.8.7"
|
||||
implementation "com.squareup.okhttp3:okhttp:4.9.1"
|
||||
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.3"
|
||||
implementation "com.google.code.gson:gson:2.9.0"
|
||||
implementation "com.squareup.okhttp3:okhttp:4.10.0"
|
||||
testImplementation "io.kotlintest:kotlintest-runner-junit5:3.4.2"
|
||||
}
|
||||
|
@ -2,12 +2,12 @@ group 'org.openapitools'
|
||||
version '1.0.0'
|
||||
|
||||
wrapper {
|
||||
gradleVersion = '6.8.3'
|
||||
gradleVersion = '7.5'
|
||||
distributionUrl = "https://services.gradle.org/distributions/gradle-$gradleVersion-all.zip"
|
||||
}
|
||||
|
||||
buildscript {
|
||||
ext.kotlin_version = '1.5.10'
|
||||
ext.kotlin_version = '1.6.10'
|
||||
|
||||
repositories {
|
||||
maven { url "https://repo1.maven.org/maven2" }
|
||||
@ -30,8 +30,8 @@ test {
|
||||
dependencies {
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
|
||||
implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
|
||||
implementation "com.squareup.moshi:moshi-kotlin:1.12.0"
|
||||
implementation "com.squareup.moshi:moshi-adapters:1.12.0"
|
||||
implementation "com.squareup.okhttp3:okhttp:4.9.1"
|
||||
implementation "com.squareup.moshi:moshi-kotlin:1.13.0"
|
||||
implementation "com.squareup.moshi:moshi-adapters:1.13.0"
|
||||
implementation "com.squareup.okhttp3:okhttp:4.10.0"
|
||||
testImplementation "io.kotlintest:kotlintest-runner-junit5:3.4.2"
|
||||
}
|
||||
|
@ -2,12 +2,12 @@ group 'org.openapitools'
|
||||
version '1.0.0'
|
||||
|
||||
wrapper {
|
||||
gradleVersion = '6.8.3'
|
||||
gradleVersion = '7.5'
|
||||
distributionUrl = "https://services.gradle.org/distributions/gradle-$gradleVersion-all.zip"
|
||||
}
|
||||
|
||||
buildscript {
|
||||
ext.kotlin_version = '1.5.10'
|
||||
ext.kotlin_version = '1.6.10'
|
||||
|
||||
repositories {
|
||||
maven { url "https://repo1.maven.org/maven2" }
|
||||
@ -30,9 +30,9 @@ test {
|
||||
|
||||
dependencies {
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
|
||||
implementation "com.squareup.moshi:moshi:1.12.0"
|
||||
implementation "com.squareup.moshi:moshi-adapters:1.12.0"
|
||||
kapt "com.squareup.moshi:moshi-kotlin-codegen:1.12.0"
|
||||
implementation "com.squareup.okhttp3:okhttp:4.9.1"
|
||||
implementation "com.squareup.moshi:moshi:1.13.0"
|
||||
implementation "com.squareup.moshi:moshi-adapters:1.13.0"
|
||||
kapt "com.squareup.moshi:moshi-kotlin-codegen:1.13.0"
|
||||
implementation "com.squareup.okhttp3:okhttp:4.10.0"
|
||||
testImplementation "io.kotlintest:kotlintest-runner-junit5:3.4.2"
|
||||
}
|
||||
|
@ -8,10 +8,10 @@ plugins {
|
||||
group = "org.openapitools"
|
||||
version = "1.0.0"
|
||||
|
||||
val kotlin_version = "1.6.0"
|
||||
val coroutines_version = "1.5.2"
|
||||
val serialization_version = "1.3.0"
|
||||
val ktor_version = "1.6.4"
|
||||
val kotlin_version = "1.6.10"
|
||||
val coroutines_version = "1.6.3"
|
||||
val serialization_version = "1.3.3"
|
||||
val ktor_version = "2.0.3"
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
@ -30,9 +30,11 @@ kotlin {
|
||||
dependencies {
|
||||
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutines_version")
|
||||
implementation("org.jetbrains.kotlinx:kotlinx-serialization-core:$serialization_version")
|
||||
|
||||
api("io.ktor:ktor-client-core:$ktor_version")
|
||||
api("io.ktor:ktor-client-json:$ktor_version")
|
||||
api("io.ktor:ktor-client-serialization:$ktor_version")
|
||||
api("io.ktor:ktor-client-content-negotiation:$ktor_version")
|
||||
api("io.ktor:ktor-serialization-kotlinx-json:$ktor_version")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -27,7 +27,6 @@ import org.openapitools.client.infrastructure.*
|
||||
import io.ktor.client.HttpClientConfig
|
||||
import io.ktor.client.request.forms.formData
|
||||
import io.ktor.client.engine.HttpClientEngine
|
||||
import io.ktor.client.features.json.serializer.KotlinxSerializer
|
||||
import kotlinx.serialization.json.Json
|
||||
import io.ktor.http.ParametersBuilder
|
||||
import kotlinx.serialization.*
|
||||
|
@ -26,7 +26,6 @@ import org.openapitools.client.infrastructure.*
|
||||
import io.ktor.client.HttpClientConfig
|
||||
import io.ktor.client.request.forms.formData
|
||||
import io.ktor.client.engine.HttpClientEngine
|
||||
import io.ktor.client.features.json.serializer.KotlinxSerializer
|
||||
import kotlinx.serialization.json.Json
|
||||
import io.ktor.http.ParametersBuilder
|
||||
import kotlinx.serialization.*
|
||||
|
@ -26,7 +26,6 @@ import org.openapitools.client.infrastructure.*
|
||||
import io.ktor.client.HttpClientConfig
|
||||
import io.ktor.client.request.forms.formData
|
||||
import io.ktor.client.engine.HttpClientEngine
|
||||
import io.ktor.client.features.json.serializer.KotlinxSerializer
|
||||
import kotlinx.serialization.json.Json
|
||||
import io.ktor.http.ParametersBuilder
|
||||
import kotlinx.serialization.*
|
||||
|
@ -3,43 +3,31 @@ package org.openapitools.client.infrastructure
|
||||
import io.ktor.client.HttpClient
|
||||
import io.ktor.client.HttpClientConfig
|
||||
import io.ktor.client.engine.HttpClientEngine
|
||||
import io.ktor.client.features.json.JsonFeature
|
||||
import io.ktor.client.features.json.JsonSerializer
|
||||
import io.ktor.client.features.json.serializer.KotlinxSerializer
|
||||
import io.ktor.client.plugins.contentnegotiation.ContentNegotiation
|
||||
import io.ktor.serialization.kotlinx.json.*
|
||||
import io.ktor.client.request.*
|
||||
import io.ktor.client.request.forms.FormDataContent
|
||||
import io.ktor.client.request.forms.MultiPartFormDataContent
|
||||
import io.ktor.client.request.header
|
||||
import io.ktor.client.request.parameter
|
||||
import io.ktor.client.statement.HttpResponse
|
||||
import io.ktor.client.utils.EmptyContent
|
||||
import io.ktor.http.*
|
||||
import io.ktor.http.content.OutgoingContent
|
||||
import io.ktor.http.content.PartData
|
||||
import kotlin.Unit
|
||||
import kotlinx.serialization.json.Json
|
||||
|
||||
import org.openapitools.client.apis.*
|
||||
import org.openapitools.client.models.*
|
||||
import org.openapitools.client.auth.*
|
||||
|
||||
open class ApiClient(
|
||||
private val baseUrl: String,
|
||||
httpClientEngine: HttpClientEngine?,
|
||||
httpClientConfig: ((HttpClientConfig<*>) -> Unit)? = null,
|
||||
private val json: Json
|
||||
private val jsonBlock: Json
|
||||
) {
|
||||
|
||||
private val serializer: JsonSerializer by lazy {
|
||||
KotlinxSerializer(json).ignoreOutgoingContent()
|
||||
}
|
||||
|
||||
private val clientConfig: (HttpClientConfig<*>) -> Unit by lazy {
|
||||
{
|
||||
// Hold a reference to the serializer to avoid freezing the entire ApiClient instance
|
||||
// when the JsonFeature is configured.
|
||||
val serializerReference = serializer
|
||||
it.install(JsonFeature) { serializer = serializerReference }
|
||||
it.install(ContentNegotiation) { json(jsonBlock) }
|
||||
httpClientConfig?.invoke(it)
|
||||
}
|
||||
}
|
||||
@ -56,7 +44,11 @@ open class ApiClient(
|
||||
|
||||
companion object {
|
||||
const val BASE_URL = "http://petstore.swagger.io/v2"
|
||||
val JSON_DEFAULT = Json { ignoreUnknownKeys = true }
|
||||
val JSON_DEFAULT = Json {
|
||||
ignoreUnknownKeys = true
|
||||
prettyPrint = true
|
||||
isLenient = true
|
||||
}
|
||||
protected val UNSAFE_HEADERS = listOf(HttpHeaders.ContentType)
|
||||
}
|
||||
|
||||
@ -136,18 +128,13 @@ open class ApiClient(
|
||||
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 {
|
||||
val contentType = (requestConfig.headers[HttpHeaders.ContentType]?.let { ContentType.parse(it) }
|
||||
?: ContentType.Application.Json)
|
||||
return if (body != null) request(requestConfig, serializer.write(body, contentType), authNames)
|
||||
else request(requestConfig, authNames = 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: Any?> request(requestConfig: RequestConfig<T>, body: OutgoingContent = EmptyContent, authNames: kotlin.collections.List<String>): HttpResponse {
|
||||
protected suspend fun <T: Any?> request(requestConfig: RequestConfig<T>, body: Any? = null, authNames: kotlin.collections.List<String>): HttpResponse {
|
||||
requestConfig.updateForAuth<T>(authNames)
|
||||
val headers = requestConfig.headers
|
||||
|
||||
return client.request<HttpResponse> {
|
||||
return client.request {
|
||||
this.url {
|
||||
this.takeFrom(URLBuilder(baseUrl))
|
||||
appendPath(requestConfig.path.trimStart('/').split('/'))
|
||||
@ -160,7 +147,7 @@ open class ApiClient(
|
||||
this.method = requestConfig.method.httpMethod
|
||||
headers.filter { header -> !UNSAFE_HEADERS.contains(header.key) }.forEach { header -> this.header(header.key, header.value) }
|
||||
if (requestConfig.method in listOf(RequestMethod.PUT, RequestMethod.POST, RequestMethod.PATCH))
|
||||
this.body = body
|
||||
this.setBody(body)
|
||||
|
||||
}
|
||||
}
|
||||
@ -187,13 +174,3 @@ open class ApiClient(
|
||||
RequestMethod.OPTIONS -> HttpMethod.Options
|
||||
}
|
||||
}
|
||||
|
||||
// https://github.com/ktorio/ktor/issues/851
|
||||
private fun JsonSerializer.ignoreOutgoingContent() = IgnoreOutgoingContentJsonSerializer(this)
|
||||
|
||||
private class IgnoreOutgoingContentJsonSerializer(private val delegate: JsonSerializer) : JsonSerializer by delegate {
|
||||
override fun write(data: Any): OutgoingContent {
|
||||
if (data is OutgoingContent) return data
|
||||
return delegate.write(data)
|
||||
}
|
||||
}
|
||||
|
@ -14,7 +14,7 @@ private fun ByteArray.clearFrom(from: Int) = (from until size).forEach { this[it
|
||||
private fun Int.toBase64(): Char = BASE64_ALPHABET[this]
|
||||
private fun Byte.fromBase64(): Byte = BASE64_INVERSE_ALPHABET[toInt() and 0xff].toByte() and BASE64_MASK
|
||||
internal fun ByteArray.encodeBase64(): String = buildPacket { writeFully(this@encodeBase64) }.encodeBase64()
|
||||
internal fun String.decodeBase64Bytes(): ByteArray = buildPacket { writeStringUtf8(dropLastWhile { it == BASE64_PAD }) }.decodeBase64Bytes().readBytes()
|
||||
internal fun String.decodeBase64Bytes(): ByteArray = buildPacket { dropLastWhile { it == BASE64_PAD } }.decodeBase64Bytes().readBytes()
|
||||
|
||||
/**
|
||||
* Encode [bytes] as a HEX string with no spaces, newlines and `0x` prefixes.
|
||||
|
@ -1,9 +1,9 @@
|
||||
package org.openapitools.client.infrastructure
|
||||
|
||||
import io.ktor.client.call.TypeInfo
|
||||
import io.ktor.client.call.typeInfo
|
||||
import io.ktor.http.Headers
|
||||
import io.ktor.http.isSuccess
|
||||
import io.ktor.util.reflect.TypeInfo
|
||||
import io.ktor.util.reflect.typeInfo
|
||||
|
||||
open class HttpResponse<T : Any>(val response: io.ktor.client.statement.HttpResponse, val provider: BodyProvider<T>) {
|
||||
val status: Int = response.status.value
|
||||
@ -29,11 +29,11 @@ interface BodyProvider<T : Any> {
|
||||
class TypedBodyProvider<T : Any>(private val type: TypeInfo) : BodyProvider<T> {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
override suspend fun body(response: io.ktor.client.statement.HttpResponse): T =
|
||||
response.call.receive(type) as T
|
||||
response.call.body(type) as T
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
override suspend fun <V : Any> typedBody(response: io.ktor.client.statement.HttpResponse, type: TypeInfo): V =
|
||||
response.call.receive(type) as V
|
||||
response.call.body(type) as V
|
||||
}
|
||||
|
||||
class MappedBodyProvider<S : Any, T : Any>(private val provider: BodyProvider<S>, private val block: S.() -> T) : BodyProvider<T> {
|
||||
|
@ -2,12 +2,12 @@ group 'org.openapitools'
|
||||
version '1.0.0'
|
||||
|
||||
wrapper {
|
||||
gradleVersion = '6.8.3'
|
||||
gradleVersion = '7.5'
|
||||
distributionUrl = "https://services.gradle.org/distributions/gradle-$gradleVersion-all.zip"
|
||||
}
|
||||
|
||||
buildscript {
|
||||
ext.kotlin_version = '1.5.10'
|
||||
ext.kotlin_version = '1.6.10'
|
||||
|
||||
repositories {
|
||||
maven { url "https://repo1.maven.org/maven2" }
|
||||
@ -30,8 +30,8 @@ test {
|
||||
dependencies {
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
|
||||
implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
|
||||
implementation "com.squareup.moshi:moshi-kotlin:1.12.0"
|
||||
implementation "com.squareup.moshi:moshi-adapters:1.12.0"
|
||||
implementation "com.squareup.okhttp3:okhttp:4.9.1"
|
||||
implementation "com.squareup.moshi:moshi-kotlin:1.13.0"
|
||||
implementation "com.squareup.moshi:moshi-adapters:1.13.0"
|
||||
implementation "com.squareup.okhttp3:okhttp:4.10.0"
|
||||
testImplementation "io.kotlintest:kotlintest-runner-junit5:3.4.2"
|
||||
}
|
||||
|
@ -2,12 +2,12 @@ group 'org.openapitools'
|
||||
version '1.0.0'
|
||||
|
||||
wrapper {
|
||||
gradleVersion = '6.8.3'
|
||||
gradleVersion = '7.5'
|
||||
distributionUrl = "https://services.gradle.org/distributions/gradle-$gradleVersion-all.zip"
|
||||
}
|
||||
|
||||
buildscript {
|
||||
ext.kotlin_version = '1.5.10'
|
||||
ext.kotlin_version = '1.6.10'
|
||||
|
||||
repositories {
|
||||
maven { url "https://repo1.maven.org/maven2" }
|
||||
@ -30,8 +30,8 @@ test {
|
||||
dependencies {
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
|
||||
implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
|
||||
implementation "com.squareup.moshi:moshi-kotlin:1.12.0"
|
||||
implementation "com.squareup.moshi:moshi-adapters:1.12.0"
|
||||
implementation "com.squareup.okhttp3:okhttp:4.9.1"
|
||||
implementation "com.squareup.moshi:moshi-kotlin:1.13.0"
|
||||
implementation "com.squareup.moshi:moshi-adapters:1.13.0"
|
||||
implementation "com.squareup.okhttp3:okhttp:4.10.0"
|
||||
testImplementation "io.kotlintest:kotlintest-runner-junit5:3.4.2"
|
||||
}
|
||||
|
@ -2,12 +2,12 @@ group 'org.openapitools'
|
||||
version '1.0.0'
|
||||
|
||||
wrapper {
|
||||
gradleVersion = '6.8.3'
|
||||
gradleVersion = '7.5'
|
||||
distributionUrl = "https://services.gradle.org/distributions/gradle-$gradleVersion-all.zip"
|
||||
}
|
||||
|
||||
buildscript {
|
||||
ext.kotlin_version = '1.5.10'
|
||||
ext.kotlin_version = '1.6.10'
|
||||
|
||||
repositories {
|
||||
maven { url "https://repo1.maven.org/maven2" }
|
||||
@ -30,8 +30,8 @@ test {
|
||||
dependencies {
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
|
||||
implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
|
||||
implementation "com.squareup.moshi:moshi-kotlin:1.12.0"
|
||||
implementation "com.squareup.moshi:moshi-adapters:1.12.0"
|
||||
implementation "com.squareup.moshi:moshi-kotlin:1.13.0"
|
||||
implementation "com.squareup.moshi:moshi-adapters:1.13.0"
|
||||
implementation "com.squareup.okhttp3:okhttp:3.12.13"
|
||||
testImplementation "io.kotlintest:kotlintest-runner-junit5:3.4.2"
|
||||
}
|
||||
|
@ -2,12 +2,12 @@ group 'org.openapitools'
|
||||
version '1.0.0'
|
||||
|
||||
wrapper {
|
||||
gradleVersion = '6.8.3'
|
||||
gradleVersion = '7.5'
|
||||
distributionUrl = "https://services.gradle.org/distributions/gradle-$gradleVersion-all.zip"
|
||||
}
|
||||
|
||||
buildscript {
|
||||
ext.kotlin_version = '1.5.10'
|
||||
ext.kotlin_version = '1.6.10'
|
||||
ext.retrofitVersion = '2.9.0'
|
||||
|
||||
repositories {
|
||||
@ -32,9 +32,9 @@ test {
|
||||
|
||||
dependencies {
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
|
||||
implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.2.1"
|
||||
implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.3.3"
|
||||
implementation "org.apache.oltu.oauth2:org.apache.oltu.oauth2.client:1.0.2"
|
||||
implementation "com.squareup.okhttp3:logging-interceptor:4.9.1"
|
||||
implementation "com.squareup.okhttp3:logging-interceptor:4.10.0"
|
||||
implementation "com.squareup.retrofit2:retrofit:$retrofitVersion"
|
||||
implementation "com.jakewharton.retrofit:retrofit2-kotlinx-serialization-converter:0.8.0"
|
||||
implementation "com.squareup.retrofit2:converter-scalars:$retrofitVersion"
|
||||
|
@ -2,12 +2,12 @@ group 'org.openapitools'
|
||||
version '1.0.0'
|
||||
|
||||
wrapper {
|
||||
gradleVersion = '6.8.3'
|
||||
gradleVersion = '7.5'
|
||||
distributionUrl = "https://services.gradle.org/distributions/gradle-$gradleVersion-all.zip"
|
||||
}
|
||||
|
||||
buildscript {
|
||||
ext.kotlin_version = '1.5.10'
|
||||
ext.kotlin_version = '1.6.10'
|
||||
ext.retrofitVersion = '2.9.0'
|
||||
ext.rxJava3Version = '3.0.12'
|
||||
|
||||
@ -32,10 +32,10 @@ test {
|
||||
dependencies {
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
|
||||
implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
|
||||
implementation "com.squareup.moshi:moshi-kotlin:1.12.0"
|
||||
implementation "com.squareup.moshi:moshi-adapters:1.12.0"
|
||||
implementation "com.squareup.moshi:moshi-kotlin:1.13.0"
|
||||
implementation "com.squareup.moshi:moshi-adapters:1.13.0"
|
||||
implementation "org.apache.oltu.oauth2:org.apache.oltu.oauth2.client:1.0.2"
|
||||
implementation "com.squareup.okhttp3:logging-interceptor:4.9.1"
|
||||
implementation "com.squareup.okhttp3:logging-interceptor:4.10.0"
|
||||
implementation "io.reactivex.rxjava3:rxjava:$rxJava3Version"
|
||||
implementation "com.squareup.retrofit2:adapter-rxjava3:2.9.0"
|
||||
implementation "com.squareup.retrofit2:retrofit:$retrofitVersion"
|
||||
|
@ -2,12 +2,12 @@ group 'org.openapitools'
|
||||
version '1.0.0'
|
||||
|
||||
wrapper {
|
||||
gradleVersion = '6.8.3'
|
||||
gradleVersion = '7.5'
|
||||
distributionUrl = "https://services.gradle.org/distributions/gradle-$gradleVersion-all.zip"
|
||||
}
|
||||
|
||||
buildscript {
|
||||
ext.kotlin_version = '1.5.10'
|
||||
ext.kotlin_version = '1.6.10'
|
||||
ext.retrofitVersion = '2.9.0'
|
||||
|
||||
repositories {
|
||||
@ -31,10 +31,10 @@ test {
|
||||
dependencies {
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
|
||||
implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
|
||||
implementation "com.squareup.moshi:moshi-kotlin:1.12.0"
|
||||
implementation "com.squareup.moshi:moshi-adapters:1.12.0"
|
||||
implementation "com.squareup.moshi:moshi-kotlin:1.13.0"
|
||||
implementation "com.squareup.moshi:moshi-adapters:1.13.0"
|
||||
implementation "org.apache.oltu.oauth2:org.apache.oltu.oauth2.client:1.0.2"
|
||||
implementation "com.squareup.okhttp3:logging-interceptor:4.9.1"
|
||||
implementation "com.squareup.okhttp3:logging-interceptor:4.10.0"
|
||||
implementation "com.squareup.retrofit2:retrofit:$retrofitVersion"
|
||||
implementation "com.squareup.retrofit2:converter-moshi:$retrofitVersion"
|
||||
implementation "com.squareup.retrofit2:converter-scalars:$retrofitVersion"
|
||||
|
@ -2,12 +2,12 @@ group 'org.openapitools'
|
||||
version '1.0.0'
|
||||
|
||||
wrapper {
|
||||
gradleVersion = '6.8.3'
|
||||
gradleVersion = '7.5'
|
||||
distributionUrl = "https://services.gradle.org/distributions/gradle-$gradleVersion-all.zip"
|
||||
}
|
||||
|
||||
buildscript {
|
||||
ext.kotlin_version = '1.5.10'
|
||||
ext.kotlin_version = '1.6.10'
|
||||
|
||||
repositories {
|
||||
maven { url "https://repo1.maven.org/maven2" }
|
||||
@ -30,8 +30,8 @@ test {
|
||||
dependencies {
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
|
||||
implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
|
||||
implementation "com.squareup.moshi:moshi-kotlin:1.12.0"
|
||||
implementation "com.squareup.moshi:moshi-adapters:1.12.0"
|
||||
implementation "com.squareup.okhttp3:okhttp:4.9.1"
|
||||
implementation "com.squareup.moshi:moshi-kotlin:1.13.0"
|
||||
implementation "com.squareup.moshi:moshi-adapters:1.13.0"
|
||||
implementation "com.squareup.okhttp3:okhttp:4.10.0"
|
||||
testImplementation "io.kotlintest:kotlintest-runner-junit5:3.4.2"
|
||||
}
|
||||
|
@ -2,12 +2,12 @@ group 'org.openapitools'
|
||||
version '1.0.0'
|
||||
|
||||
wrapper {
|
||||
gradleVersion = '6.8.3'
|
||||
gradleVersion = '7.5'
|
||||
distributionUrl = "https://services.gradle.org/distributions/gradle-$gradleVersion-all.zip"
|
||||
}
|
||||
|
||||
buildscript {
|
||||
ext.kotlin_version = '1.5.10'
|
||||
ext.kotlin_version = '1.6.10'
|
||||
|
||||
repositories {
|
||||
maven { url "https://repo1.maven.org/maven2" }
|
||||
@ -30,9 +30,9 @@ test {
|
||||
dependencies {
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
|
||||
implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
|
||||
implementation "com.squareup.moshi:moshi-kotlin:1.12.0"
|
||||
implementation "com.squareup.moshi:moshi-adapters:1.12.0"
|
||||
implementation "com.squareup.okhttp3:okhttp:4.9.1"
|
||||
implementation "com.squareup.moshi:moshi-kotlin:1.13.0"
|
||||
implementation "com.squareup.moshi:moshi-adapters:1.13.0"
|
||||
implementation "com.squareup.okhttp3:okhttp:4.10.0"
|
||||
implementation "org.threeten:threetenbp:1.5.1"
|
||||
testImplementation "io.kotlintest:kotlintest-runner-junit5:3.4.2"
|
||||
}
|
||||
|
@ -2,12 +2,12 @@ group 'org.openapitools'
|
||||
version '1.0.0'
|
||||
|
||||
wrapper {
|
||||
gradleVersion = '6.8.3'
|
||||
gradleVersion = '7.5'
|
||||
distributionUrl = "https://services.gradle.org/distributions/gradle-$gradleVersion-all.zip"
|
||||
}
|
||||
|
||||
buildscript {
|
||||
ext.kotlin_version = '1.5.10'
|
||||
ext.kotlin_version = '1.6.10'
|
||||
|
||||
repositories {
|
||||
maven { url "https://repo1.maven.org/maven2" }
|
||||
@ -31,8 +31,8 @@ test {
|
||||
|
||||
dependencies {
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
|
||||
implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.2.1"
|
||||
implementation "com.squareup.okhttp3:okhttp:4.9.1"
|
||||
implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.3.3"
|
||||
implementation "com.squareup.okhttp3:okhttp:4.10.0"
|
||||
testImplementation "io.kotlintest:kotlintest-runner-junit5:3.4.2"
|
||||
}
|
||||
|
||||
|
@ -2,12 +2,12 @@ group 'org.openapitools'
|
||||
version '1.0.0'
|
||||
|
||||
wrapper {
|
||||
gradleVersion = '6.8.3'
|
||||
gradleVersion = '7.5'
|
||||
distributionUrl = "https://services.gradle.org/distributions/gradle-$gradleVersion-all.zip"
|
||||
}
|
||||
|
||||
buildscript {
|
||||
ext.kotlin_version = '1.5.10'
|
||||
ext.kotlin_version = '1.6.10'
|
||||
|
||||
repositories {
|
||||
maven { url "https://repo1.maven.org/maven2" }
|
||||
@ -30,8 +30,8 @@ test {
|
||||
dependencies {
|
||||
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
|
||||
implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
|
||||
implementation "com.squareup.moshi:moshi-kotlin:1.12.0"
|
||||
implementation "com.squareup.moshi:moshi-adapters:1.12.0"
|
||||
implementation "com.squareup.okhttp3:okhttp:4.9.1"
|
||||
implementation "com.squareup.moshi:moshi-kotlin:1.13.0"
|
||||
implementation "com.squareup.moshi:moshi-adapters:1.13.0"
|
||||
implementation "com.squareup.okhttp3:okhttp:4.10.0"
|
||||
testImplementation "io.kotlintest:kotlintest-runner-junit5:3.4.2"
|
||||
}
|
||||
|
@ -1,32 +0,0 @@
|
||||
# coding: utf-8
|
||||
|
||||
import sys
|
||||
|
||||
if sys.version_info < (3, 7):
|
||||
import typing
|
||||
|
||||
def is_generic(klass):
|
||||
""" Determine whether klass is a generic class """
|
||||
return type(klass) == typing.GenericMeta
|
||||
|
||||
def is_dict(klass):
|
||||
""" Determine whether klass is a Dict """
|
||||
return klass.__extra__ == dict
|
||||
|
||||
def is_list(klass):
|
||||
""" Determine whether klass is a List """
|
||||
return klass.__extra__ == list
|
||||
|
||||
else:
|
||||
|
||||
def is_generic(klass):
|
||||
""" Determine whether klass is a generic class """
|
||||
return hasattr(klass, '__origin__')
|
||||
|
||||
def is_dict(klass):
|
||||
""" Determine whether klass is a Dict """
|
||||
return klass.__origin__ == dict
|
||||
|
||||
def is_list(klass):
|
||||
""" Determine whether klass is a List """
|
||||
return klass.__origin__ == list
|
Loading…
x
Reference in New Issue
Block a user