Kotlin multiplatform client (#3900)

* Includes Kotlin multiplatform client

Kotlin multiplatform allows Kotlin code to be shared across various target platforms.
This implementation generates Swagger clients for JVM and iOS platforms.

* Includes Kotlin Multiplatform sample scripts

* Updates existing Kotlin samples

* Includes Kotlin Multiplatform samples

* Fixes incorrect Windows sample resource location

* Updates Kotlin client documentation

* Removes unnecessary workaround to remove duplicate entries

* Includes additional multiplatform type and import mappings

* Fixes Kotlin client definitions with multiple enums

https://github.com/OpenAPITools/openapi-generator/issues/3917

* Updates Kotlin samples
This commit is contained in:
Andrew Emery
2019-09-21 23:48:41 +10:00
committed by William Cheng
parent 0ea1ead59e
commit 21e0e0d5d5
223 changed files with 11192 additions and 58 deletions

View File

@@ -0,0 +1,365 @@
/**
* OpenAPI Petstore
* This is a sample server Petstore server. For this sample, you can use the api key `special-key` to test the authorization filters.
*
* The version of the OpenAPI document: 1.0.0
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
* Do not edit the class manually.
*/
package org.openapitools.client.apis
import org.openapitools.client.models.ApiResponse
import org.openapitools.client.models.Pet
import org.openapitools.client.infrastructure.*
import io.ktor.client.request.forms.formData
import kotlinx.serialization.UnstableDefault
import io.ktor.client.engine.HttpClientEngine
import io.ktor.client.features.json.serializer.KotlinxSerializer
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonConfiguration
import io.ktor.http.ParametersBuilder
import kotlinx.serialization.*
import kotlinx.serialization.internal.StringDescriptor
class PetApi @UseExperimental(UnstableDefault::class) constructor(
baseUrl: kotlin.String = "http://petstore.swagger.io/v2",
httpClientEngine: HttpClientEngine? = null,
serializer: KotlinxSerializer)
: ApiClient(baseUrl, httpClientEngine, serializer) {
@UseExperimental(UnstableDefault::class)
constructor(
baseUrl: kotlin.String = "http://petstore.swagger.io/v2",
httpClientEngine: HttpClientEngine? = null,
jsonConfiguration: JsonConfiguration = JsonConfiguration.Default)
: this(baseUrl, httpClientEngine, KotlinxSerializer(Json(jsonConfiguration)))
/**
* Add a new pet to the store
*
* @param body Pet object that needs to be added to the store
* @return void
*/
suspend fun addPet(body: Pet) : HttpResponse<Unit> {
val localVariableBody = body
val localVariableQuery = mutableMapOf<String, List<String>>()
val localVariableHeaders = mutableMapOf<String, String>()
val localVariableConfig = RequestConfig(
RequestMethod.POST,
"/pet",
query = localVariableQuery,
headers = localVariableHeaders
)
return jsonRequest(
localVariableConfig,
localVariableBody
).wrap()
}
/**
* Deletes a pet
*
* @param petId Pet id to delete
* @param apiKey (optional)
* @return void
*/
suspend fun deletePet(petId: kotlin.Long, apiKey: kotlin.String?) : HttpResponse<Unit> {
val localVariableBody =
io.ktor.client.utils.EmptyContent
val localVariableQuery = mutableMapOf<String, List<String>>()
val localVariableHeaders = mutableMapOf<String, String>()
apiKey?.apply { localVariableHeaders["api_key"] = this.toString() }
val localVariableConfig = RequestConfig(
RequestMethod.DELETE,
"/pet/{petId}".replace("{"+"petId"+"}", "$petId"),
query = localVariableQuery,
headers = localVariableHeaders
)
return request(
localVariableConfig,
localVariableBody
).wrap()
}
/**
* Finds Pets by status
* Multiple status values can be provided with comma separated strings
* @param status Status values that need to be considered for filter
* @return kotlin.Array<Pet>
*/
@Suppress("UNCHECKED_CAST")
suspend fun findPetsByStatus(status: kotlin.Array<kotlin.String>) : HttpResponse<kotlin.Array<Pet>> {
val localVariableBody =
io.ktor.client.utils.EmptyContent
val localVariableQuery = mutableMapOf<String, List<String>>()
status?.apply { localVariableQuery["status"] = toMultiValue(this, "csv") }
val localVariableHeaders = mutableMapOf<String, String>()
val localVariableConfig = RequestConfig(
RequestMethod.GET,
"/pet/findByStatus",
query = localVariableQuery,
headers = localVariableHeaders
)
return request(
localVariableConfig,
localVariableBody
).wrap<FindPetsByStatusResponse>().map { value.toTypedArray() }
}
@Serializable
private class FindPetsByStatusResponse(val value: List<Pet>) {
@Serializer(FindPetsByStatusResponse::class)
companion object : KSerializer<FindPetsByStatusResponse> {
private val serializer: KSerializer<List<Pet>> = Pet.serializer().list
override val descriptor = StringDescriptor.withName("FindPetsByStatusResponse")
override fun serialize(encoder: Encoder, obj: FindPetsByStatusResponse) = serializer.serialize(encoder, obj.value)
override fun deserialize(decoder: Decoder) = FindPetsByStatusResponse(serializer.deserialize(decoder))
}
}
/**
* Finds Pets by tags
* Multiple tags can be provided with comma separated strings. Use tag1, tag2, tag3 for testing.
* @param tags Tags to filter by
* @return kotlin.Array<Pet>
*/
@Suppress("UNCHECKED_CAST")
suspend fun findPetsByTags(tags: kotlin.Array<kotlin.String>) : HttpResponse<kotlin.Array<Pet>> {
val localVariableBody =
io.ktor.client.utils.EmptyContent
val localVariableQuery = mutableMapOf<String, List<String>>()
tags?.apply { localVariableQuery["tags"] = toMultiValue(this, "csv") }
val localVariableHeaders = mutableMapOf<String, String>()
val localVariableConfig = RequestConfig(
RequestMethod.GET,
"/pet/findByTags",
query = localVariableQuery,
headers = localVariableHeaders
)
return request(
localVariableConfig,
localVariableBody
).wrap<FindPetsByTagsResponse>().map { value.toTypedArray() }
}
@Serializable
private class FindPetsByTagsResponse(val value: List<Pet>) {
@Serializer(FindPetsByTagsResponse::class)
companion object : KSerializer<FindPetsByTagsResponse> {
private val serializer: KSerializer<List<Pet>> = Pet.serializer().list
override val descriptor = StringDescriptor.withName("FindPetsByTagsResponse")
override fun serialize(encoder: Encoder, obj: FindPetsByTagsResponse) = serializer.serialize(encoder, obj.value)
override fun deserialize(decoder: Decoder) = FindPetsByTagsResponse(serializer.deserialize(decoder))
}
}
/**
* Find pet by ID
* Returns a single pet
* @param petId ID of pet to return
* @return Pet
*/
@Suppress("UNCHECKED_CAST")
suspend fun getPetById(petId: kotlin.Long) : HttpResponse<Pet> {
val localVariableBody =
io.ktor.client.utils.EmptyContent
val localVariableQuery = mutableMapOf<String, List<String>>()
val localVariableHeaders = mutableMapOf<String, String>()
val localVariableConfig = RequestConfig(
RequestMethod.GET,
"/pet/{petId}".replace("{"+"petId"+"}", "$petId"),
query = localVariableQuery,
headers = localVariableHeaders
)
return request(
localVariableConfig,
localVariableBody
).wrap()
}
/**
* Update an existing pet
*
* @param body Pet object that needs to be added to the store
* @return void
*/
suspend fun updatePet(body: Pet) : HttpResponse<Unit> {
val localVariableBody = body
val localVariableQuery = mutableMapOf<String, List<String>>()
val localVariableHeaders = mutableMapOf<String, String>()
val localVariableConfig = RequestConfig(
RequestMethod.PUT,
"/pet",
query = localVariableQuery,
headers = localVariableHeaders
)
return jsonRequest(
localVariableConfig,
localVariableBody
).wrap()
}
/**
* Updates a pet in the store with form data
*
* @param petId ID of pet that needs to be updated
* @param name Updated name of the pet (optional)
* @param status Updated status of the pet (optional)
* @return void
*/
suspend fun updatePetWithForm(petId: kotlin.Long, name: kotlin.String?, status: kotlin.String?) : HttpResponse<Unit> {
val localVariableBody =
ParametersBuilder().also {
name?.apply { it.append("name", name) }
status?.apply { it.append("status", status) }
}.build()
val localVariableQuery = mutableMapOf<String, List<String>>()
val localVariableHeaders = mutableMapOf<String, String>()
val localVariableConfig = RequestConfig(
RequestMethod.POST,
"/pet/{petId}".replace("{"+"petId"+"}", "$petId"),
query = localVariableQuery,
headers = localVariableHeaders
)
return urlEncodedFormRequest(
localVariableConfig,
localVariableBody
).wrap()
}
/**
* uploads an image
*
* @param petId ID of pet to update
* @param additionalMetadata Additional data to pass to server (optional)
* @param file file to upload (optional)
* @return ApiResponse
*/
@Suppress("UNCHECKED_CAST")
suspend fun uploadFile(petId: kotlin.Long, additionalMetadata: kotlin.String?, file: io.ktor.client.request.forms.InputProvider?) : HttpResponse<ApiResponse> {
val localVariableBody =
formData {
additionalMetadata?.apply { append("additionalMetadata", additionalMetadata) }
file?.apply { append("file", file) }
}
val localVariableQuery = mutableMapOf<String, List<String>>()
val localVariableHeaders = mutableMapOf<String, String>()
val localVariableConfig = RequestConfig(
RequestMethod.POST,
"/pet/{petId}/uploadImage".replace("{"+"petId"+"}", "$petId"),
query = localVariableQuery,
headers = localVariableHeaders
)
return multipartFormRequest(
localVariableConfig,
localVariableBody
).wrap()
}
companion object {
internal fun setMappers(serializer: KotlinxSerializer) {
serializer.setMapper(FindPetsByStatusResponse::class, FindPetsByStatusResponse.serializer())
serializer.setMapper(FindPetsByTagsResponse::class, FindPetsByTagsResponse.serializer())
}
}
}

View File

@@ -0,0 +1,196 @@
/**
* OpenAPI Petstore
* This is a sample server Petstore server. For this sample, you can use the api key `special-key` to test the authorization filters.
*
* The version of the OpenAPI document: 1.0.0
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
* Do not edit the class manually.
*/
package org.openapitools.client.apis
import org.openapitools.client.models.Order
import org.openapitools.client.infrastructure.*
import io.ktor.client.request.forms.formData
import kotlinx.serialization.UnstableDefault
import io.ktor.client.engine.HttpClientEngine
import io.ktor.client.features.json.serializer.KotlinxSerializer
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonConfiguration
import io.ktor.http.ParametersBuilder
import kotlinx.serialization.*
import kotlinx.serialization.internal.StringDescriptor
class StoreApi @UseExperimental(UnstableDefault::class) constructor(
baseUrl: kotlin.String = "http://petstore.swagger.io/v2",
httpClientEngine: HttpClientEngine? = null,
serializer: KotlinxSerializer)
: ApiClient(baseUrl, httpClientEngine, serializer) {
@UseExperimental(UnstableDefault::class)
constructor(
baseUrl: kotlin.String = "http://petstore.swagger.io/v2",
httpClientEngine: HttpClientEngine? = null,
jsonConfiguration: JsonConfiguration = JsonConfiguration.Default)
: this(baseUrl, httpClientEngine, KotlinxSerializer(Json(jsonConfiguration)))
/**
* Delete purchase order by ID
* For valid response try integer IDs with value &lt; 1000. Anything above 1000 or nonintegers will generate API errors
* @param orderId ID of the order that needs to be deleted
* @return void
*/
suspend fun deleteOrder(orderId: kotlin.String) : HttpResponse<Unit> {
val localVariableBody =
io.ktor.client.utils.EmptyContent
val localVariableQuery = mutableMapOf<String, List<String>>()
val localVariableHeaders = mutableMapOf<String, String>()
val localVariableConfig = RequestConfig(
RequestMethod.DELETE,
"/store/order/{orderId}".replace("{"+"orderId"+"}", "$orderId"),
query = localVariableQuery,
headers = localVariableHeaders
)
return request(
localVariableConfig,
localVariableBody
).wrap()
}
/**
* Returns pet inventories by status
* Returns a map of status codes to quantities
* @return kotlin.collections.Map<kotlin.String, kotlin.Int>
*/
@Suppress("UNCHECKED_CAST")
suspend fun getInventory() : HttpResponse<kotlin.collections.Map<kotlin.String, kotlin.Int>> {
val localVariableBody =
io.ktor.client.utils.EmptyContent
val localVariableQuery = mutableMapOf<String, List<String>>()
val localVariableHeaders = mutableMapOf<String, String>()
val localVariableConfig = RequestConfig(
RequestMethod.GET,
"/store/inventory",
query = localVariableQuery,
headers = localVariableHeaders
)
return request(
localVariableConfig,
localVariableBody
).wrap<GetInventoryResponse>().map { value }
}
@Serializable
private class GetInventoryResponse(val value: Map<kotlin.String, kotlin.Int>) {
@Serializer(GetInventoryResponse::class)
companion object : KSerializer<GetInventoryResponse> {
private val serializer: KSerializer<Map<kotlin.String, kotlin.Int>> = (kotlin.String.serializer() to kotlin.Int.serializer()).map
override val descriptor = StringDescriptor.withName("GetInventoryResponse")
override fun serialize(encoder: Encoder, obj: GetInventoryResponse) = serializer.serialize(encoder, obj.value)
override fun deserialize(decoder: Decoder) = GetInventoryResponse(serializer.deserialize(decoder))
}
}
/**
* Find purchase order by ID
* For valid response try integer IDs with value &lt;&#x3D; 5 or &gt; 10. Other values will generated exceptions
* @param orderId ID of pet that needs to be fetched
* @return Order
*/
@Suppress("UNCHECKED_CAST")
suspend fun getOrderById(orderId: kotlin.Long) : HttpResponse<Order> {
val localVariableBody =
io.ktor.client.utils.EmptyContent
val localVariableQuery = mutableMapOf<String, List<String>>()
val localVariableHeaders = mutableMapOf<String, String>()
val localVariableConfig = RequestConfig(
RequestMethod.GET,
"/store/order/{orderId}".replace("{"+"orderId"+"}", "$orderId"),
query = localVariableQuery,
headers = localVariableHeaders
)
return request(
localVariableConfig,
localVariableBody
).wrap()
}
/**
* Place an order for a pet
*
* @param body order placed for purchasing the pet
* @return Order
*/
@Suppress("UNCHECKED_CAST")
suspend fun placeOrder(body: Order) : HttpResponse<Order> {
val localVariableBody = body
val localVariableQuery = mutableMapOf<String, List<String>>()
val localVariableHeaders = mutableMapOf<String, String>()
val localVariableConfig = RequestConfig(
RequestMethod.POST,
"/store/order",
query = localVariableQuery,
headers = localVariableHeaders
)
return jsonRequest(
localVariableConfig,
localVariableBody
).wrap()
}
companion object {
internal fun setMappers(serializer: KotlinxSerializer) {
serializer.setMapper(GetInventoryResponse::class, GetInventoryResponse.serializer())
}
}
}

View File

@@ -0,0 +1,350 @@
/**
* OpenAPI Petstore
* This is a sample server Petstore server. For this sample, you can use the api key `special-key` to test the authorization filters.
*
* The version of the OpenAPI document: 1.0.0
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
* Do not edit the class manually.
*/
package org.openapitools.client.apis
import org.openapitools.client.models.User
import org.openapitools.client.infrastructure.*
import io.ktor.client.request.forms.formData
import kotlinx.serialization.UnstableDefault
import io.ktor.client.engine.HttpClientEngine
import io.ktor.client.features.json.serializer.KotlinxSerializer
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonConfiguration
import io.ktor.http.ParametersBuilder
import kotlinx.serialization.*
import kotlinx.serialization.internal.StringDescriptor
class UserApi @UseExperimental(UnstableDefault::class) constructor(
baseUrl: kotlin.String = "http://petstore.swagger.io/v2",
httpClientEngine: HttpClientEngine? = null,
serializer: KotlinxSerializer)
: ApiClient(baseUrl, httpClientEngine, serializer) {
@UseExperimental(UnstableDefault::class)
constructor(
baseUrl: kotlin.String = "http://petstore.swagger.io/v2",
httpClientEngine: HttpClientEngine? = null,
jsonConfiguration: JsonConfiguration = JsonConfiguration.Default)
: this(baseUrl, httpClientEngine, KotlinxSerializer(Json(jsonConfiguration)))
/**
* Create user
* This can only be done by the logged in user.
* @param body Created user object
* @return void
*/
suspend fun createUser(body: User) : HttpResponse<Unit> {
val localVariableBody = body
val localVariableQuery = mutableMapOf<String, List<String>>()
val localVariableHeaders = mutableMapOf<String, String>()
val localVariableConfig = RequestConfig(
RequestMethod.POST,
"/user",
query = localVariableQuery,
headers = localVariableHeaders
)
return jsonRequest(
localVariableConfig,
localVariableBody
).wrap()
}
/**
* Creates list of users with given input array
*
* @param body List of user object
* @return void
*/
suspend fun createUsersWithArrayInput(body: kotlin.Array<User>) : HttpResponse<Unit> {
val localVariableBody = CreateUsersWithArrayInputRequest(body.asList())
val localVariableQuery = mutableMapOf<String, List<String>>()
val localVariableHeaders = mutableMapOf<String, String>()
val localVariableConfig = RequestConfig(
RequestMethod.POST,
"/user/createWithArray",
query = localVariableQuery,
headers = localVariableHeaders
)
return jsonRequest(
localVariableConfig,
localVariableBody
).wrap()
}
@Serializable
private class CreateUsersWithArrayInputRequest(val value: List<User>) {
@Serializer(CreateUsersWithArrayInputRequest::class)
companion object : KSerializer<CreateUsersWithArrayInputRequest> {
private val serializer: KSerializer<List<User>> = User.serializer().list
override val descriptor = StringDescriptor.withName("CreateUsersWithArrayInputRequest")
override fun serialize(encoder: Encoder, obj: CreateUsersWithArrayInputRequest) = serializer.serialize(encoder, obj.value)
override fun deserialize(decoder: Decoder) = CreateUsersWithArrayInputRequest(serializer.deserialize(decoder))
}
}
/**
* Creates list of users with given input array
*
* @param body List of user object
* @return void
*/
suspend fun createUsersWithListInput(body: kotlin.Array<User>) : HttpResponse<Unit> {
val localVariableBody = CreateUsersWithListInputRequest(body.asList())
val localVariableQuery = mutableMapOf<String, List<String>>()
val localVariableHeaders = mutableMapOf<String, String>()
val localVariableConfig = RequestConfig(
RequestMethod.POST,
"/user/createWithList",
query = localVariableQuery,
headers = localVariableHeaders
)
return jsonRequest(
localVariableConfig,
localVariableBody
).wrap()
}
@Serializable
private class CreateUsersWithListInputRequest(val value: List<User>) {
@Serializer(CreateUsersWithListInputRequest::class)
companion object : KSerializer<CreateUsersWithListInputRequest> {
private val serializer: KSerializer<List<User>> = User.serializer().list
override val descriptor = StringDescriptor.withName("CreateUsersWithListInputRequest")
override fun serialize(encoder: Encoder, obj: CreateUsersWithListInputRequest) = serializer.serialize(encoder, obj.value)
override fun deserialize(decoder: Decoder) = CreateUsersWithListInputRequest(serializer.deserialize(decoder))
}
}
/**
* Delete user
* This can only be done by the logged in user.
* @param username The name that needs to be deleted
* @return void
*/
suspend fun deleteUser(username: kotlin.String) : HttpResponse<Unit> {
val localVariableBody =
io.ktor.client.utils.EmptyContent
val localVariableQuery = mutableMapOf<String, List<String>>()
val localVariableHeaders = mutableMapOf<String, String>()
val localVariableConfig = RequestConfig(
RequestMethod.DELETE,
"/user/{username}".replace("{"+"username"+"}", "$username"),
query = localVariableQuery,
headers = localVariableHeaders
)
return request(
localVariableConfig,
localVariableBody
).wrap()
}
/**
* Get user by user name
*
* @param username The name that needs to be fetched. Use user1 for testing.
* @return User
*/
@Suppress("UNCHECKED_CAST")
suspend fun getUserByName(username: kotlin.String) : HttpResponse<User> {
val localVariableBody =
io.ktor.client.utils.EmptyContent
val localVariableQuery = mutableMapOf<String, List<String>>()
val localVariableHeaders = mutableMapOf<String, String>()
val localVariableConfig = RequestConfig(
RequestMethod.GET,
"/user/{username}".replace("{"+"username"+"}", "$username"),
query = localVariableQuery,
headers = localVariableHeaders
)
return request(
localVariableConfig,
localVariableBody
).wrap()
}
/**
* Logs user into the system
*
* @param username The user name for login
* @param password The password for login in clear text
* @return kotlin.String
*/
@Suppress("UNCHECKED_CAST")
suspend fun loginUser(username: kotlin.String, password: kotlin.String) : HttpResponse<kotlin.String> {
val localVariableBody =
io.ktor.client.utils.EmptyContent
val localVariableQuery = mutableMapOf<String, List<String>>()
username?.apply { localVariableQuery["username"] = listOf("$username") }
password?.apply { localVariableQuery["password"] = listOf("$password") }
val localVariableHeaders = mutableMapOf<String, String>()
val localVariableConfig = RequestConfig(
RequestMethod.GET,
"/user/login",
query = localVariableQuery,
headers = localVariableHeaders
)
return request(
localVariableConfig,
localVariableBody
).wrap()
}
/**
* Logs out current logged in user session
*
* @return void
*/
suspend fun logoutUser() : HttpResponse<Unit> {
val localVariableBody =
io.ktor.client.utils.EmptyContent
val localVariableQuery = mutableMapOf<String, List<String>>()
val localVariableHeaders = mutableMapOf<String, String>()
val localVariableConfig = RequestConfig(
RequestMethod.GET,
"/user/logout",
query = localVariableQuery,
headers = localVariableHeaders
)
return request(
localVariableConfig,
localVariableBody
).wrap()
}
/**
* Updated user
* This can only be done by the logged in user.
* @param username name that need to be deleted
* @param body Updated user object
* @return void
*/
suspend fun updateUser(username: kotlin.String, body: User) : HttpResponse<Unit> {
val localVariableBody = body
val localVariableQuery = mutableMapOf<String, List<String>>()
val localVariableHeaders = mutableMapOf<String, String>()
val localVariableConfig = RequestConfig(
RequestMethod.PUT,
"/user/{username}".replace("{"+"username"+"}", "$username"),
query = localVariableQuery,
headers = localVariableHeaders
)
return jsonRequest(
localVariableConfig,
localVariableBody
).wrap()
}
companion object {
internal fun setMappers(serializer: KotlinxSerializer) {
serializer.setMapper(CreateUsersWithArrayInputRequest::class, CreateUsersWithArrayInputRequest.serializer())
serializer.setMapper(CreateUsersWithListInputRequest::class, CreateUsersWithListInputRequest.serializer())
}
}
}

View File

@@ -0,0 +1,23 @@
package org.openapitools.client.infrastructure
typealias MultiValueMap = Map<String,List<String>>
fun collectionDelimiter(collectionFormat: String) = when(collectionFormat) {
"csv" -> ","
"tsv" -> "\t"
"pipes" -> "|"
"ssv" -> " "
else -> ""
}
val defaultMultiValueConverter: (item: Any?) -> String = { item -> "$item" }
fun <T : Any?> toMultiValue(items: Array<T>, collectionFormat: String, map: (item: T) -> String = defaultMultiValueConverter)
= toMultiValue(items.asIterable(), collectionFormat, map)
fun <T : Any?> toMultiValue(items: Iterable<T>, collectionFormat: String, map: (item: T) -> String = defaultMultiValueConverter): List<String> {
return when(collectionFormat) {
"multi" -> items.map(map)
else -> listOf(items.joinToString(separator = collectionDelimiter(collectionFormat), transform = map))
}
}

View File

@@ -0,0 +1,129 @@
package org.openapitools.client.infrastructure
import io.ktor.client.HttpClient
import io.ktor.client.HttpClientConfig
import io.ktor.client.call.call
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.request.accept
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.response.HttpResponse
import io.ktor.client.utils.EmptyContent
import io.ktor.http.*
import io.ktor.http.content.OutgoingContent
import io.ktor.http.content.PartData
import kotlinx.serialization.UnstableDefault
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonConfiguration
import org.openapitools.client.apis.*
import org.openapitools.client.models.*
open class ApiClient(
private val baseUrl: String,
httpClientEngine: HttpClientEngine?,
serializer: KotlinxSerializer) {
@UseExperimental(UnstableDefault::class)
constructor(
baseUrl: String,
httpClientEngine: HttpClientEngine?,
jsonConfiguration: JsonConfiguration) :
this(baseUrl, httpClientEngine, KotlinxSerializer(Json(jsonConfiguration)))
private val serializer: JsonSerializer by lazy {
serializer.apply { setMappers(this) }.ignoreOutgoingContent()
}
private val client: HttpClient by lazy {
val jsonConfig: JsonFeature.Config.() -> Unit = { this.serializer = this@ApiClient.serializer }
val clientConfig: (HttpClientConfig<*>) -> Unit = { it.install(JsonFeature, jsonConfig) }
httpClientEngine?.let { HttpClient(it, clientConfig) } ?: HttpClient(clientConfig)
}
companion object {
protected val UNSAFE_HEADERS = listOf(HttpHeaders.ContentType)
private fun setMappers(serializer: KotlinxSerializer) {
PetApi.setMappers(serializer)
StoreApi.setMappers(serializer)
UserApi.setMappers(serializer)
serializer.setMapper(ApiResponse::class, ApiResponse.serializer())
serializer.setMapper(Category::class, Category.serializer())
serializer.setMapper(Order::class, Order.serializer())
serializer.setMapper(Pet::class, Pet.serializer())
serializer.setMapper(Tag::class, Tag.serializer())
serializer.setMapper(User::class, User.serializer())
}
}
protected suspend fun multipartFormRequest(requestConfig: RequestConfig, body: List<PartData>?): HttpResponse {
return request(requestConfig, MultiPartFormDataContent(body ?: listOf()))
}
protected suspend fun urlEncodedFormRequest(requestConfig: RequestConfig, body: Parameters?): HttpResponse {
return request(requestConfig, FormDataContent(body ?: Parameters.Empty))
}
protected suspend fun jsonRequest(requestConfig: RequestConfig, body: Any? = null): HttpResponse {
val contentType = (requestConfig.headers[HttpHeaders.ContentType]?.let { ContentType.parse(it) }
?: ContentType.Application.Json)
return if (body != null) request(requestConfig, serializer.write(body, contentType))
else request(requestConfig)
}
protected suspend fun request(requestConfig: RequestConfig, body: OutgoingContent = EmptyContent): HttpResponse {
val headers = requestConfig.headers
return client.call {
this.url {
this.takeFrom(URLBuilder(baseUrl))
appendPath(requestConfig.path.trimStart('/').split('/'))
requestConfig.query.forEach { query ->
query.value.forEach { value ->
parameter(query.key, value)
}
}
}
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
}.response
}
private fun URLBuilder.appendPath(components: List<String>): URLBuilder = apply {
encodedPath = encodedPath.trimEnd('/') + components.joinToString("/", prefix = "/") { it.encodeURLQueryComponent() }
}
private val RequestMethod.httpMethod: HttpMethod
get() = when (this) {
RequestMethod.DELETE -> HttpMethod.Delete
RequestMethod.GET -> HttpMethod.Get
RequestMethod.HEAD -> HttpMethod.Head
RequestMethod.PATCH -> HttpMethod.Patch
RequestMethod.PUT -> HttpMethod.Put
RequestMethod.POST -> HttpMethod.Post
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)
}
}

View File

@@ -0,0 +1,51 @@
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
open class HttpResponse<T : Any>(val response: io.ktor.client.response.HttpResponse, val provider: BodyProvider<T>) {
val status: Int = response.status.value
val success: Boolean = response.status.isSuccess()
val headers: Map<String, List<String>> = response.headers.mapEntries()
suspend fun body(): T = provider.body(response)
suspend fun <V : Any> typedBody(type: TypeInfo): V = provider.typedBody(response, type)
companion object {
private fun Headers.mapEntries(): Map<String, List<String>> {
val result = mutableMapOf<String, List<String>>()
entries().forEach { result[it.key] = it.value }
return result
}
}
}
interface BodyProvider<T : Any> {
suspend fun body(response: io.ktor.client.response.HttpResponse): T
suspend fun <V : Any> typedBody(response: io.ktor.client.response.HttpResponse, type: TypeInfo): V
}
class TypedBodyProvider<T : Any>(private val type: TypeInfo) : BodyProvider<T> {
@Suppress("UNCHECKED_CAST")
override suspend fun body(response: io.ktor.client.response.HttpResponse): T =
response.call.receive(type) as T
@Suppress("UNCHECKED_CAST")
override suspend fun <V : Any> typedBody(response: io.ktor.client.response.HttpResponse, type: TypeInfo): V =
response.call.receive(type) as V
}
class MappedBodyProvider<S : Any, T : Any>(private val provider: BodyProvider<S>, private val block: S.() -> T) : BodyProvider<T> {
override suspend fun body(response: io.ktor.client.response.HttpResponse): T =
block(provider.body(response))
override suspend fun <V : Any> typedBody(response: io.ktor.client.response.HttpResponse, type: TypeInfo): V =
provider.typedBody(response, type)
}
inline fun <reified T : Any> io.ktor.client.response.HttpResponse.wrap(): HttpResponse<T> =
HttpResponse(this, TypedBodyProvider(typeInfo<T>()))
fun <T : Any, V : Any> HttpResponse<T>.map(block: T.() -> V): HttpResponse<V> =
HttpResponse(response, MappedBodyProvider(provider, block))

View File

@@ -0,0 +1,16 @@
package org.openapitools.client.infrastructure
/**
* Defines a config object for a given request.
* NOTE: This object doesn't include 'body' because it
* allows for caching of the constructed object
* for many request definitions.
* NOTE: Headers is a Map<String,String> because rfc2616 defines
* multi-valued headers as csv-only.
*/
data class RequestConfig(
val method: RequestMethod,
val path: String,
val headers: MutableMap<String, String> = mutableMapOf(),
val query: Map<String, List<String>> = mapOf()
)

View File

@@ -0,0 +1,8 @@
package org.openapitools.client.infrastructure
/**
* Provides enumerated HTTP verbs
*/
enum class RequestMethod {
GET, DELETE, HEAD, OPTIONS, PATCH, POST, PUT
}

View File

@@ -0,0 +1,30 @@
/**
* OpenAPI Petstore
* This is a sample server Petstore server. For this sample, you can use the api key `special-key` to test the authorization filters.
*
* The version of the OpenAPI document: 1.0.0
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
* Do not edit the class manually.
*/
package org.openapitools.client.models
import kotlinx.serialization.*
import kotlinx.serialization.internal.CommonEnumSerializer
/**
* Describes the result of uploading an image resource
* @param code
* @param type
* @param message
*/
@Serializable
data class ApiResponse (
@SerialName(value = "code") val code: kotlin.Int? = null,
@SerialName(value = "type") val type: kotlin.String? = null,
@SerialName(value = "message") val message: kotlin.String? = null
)

View File

@@ -0,0 +1,28 @@
/**
* OpenAPI Petstore
* This is a sample server Petstore server. For this sample, you can use the api key `special-key` to test the authorization filters.
*
* The version of the OpenAPI document: 1.0.0
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
* Do not edit the class manually.
*/
package org.openapitools.client.models
import kotlinx.serialization.*
import kotlinx.serialization.internal.CommonEnumSerializer
/**
* A category for a pet
* @param id
* @param name
*/
@Serializable
data class Category (
@SerialName(value = "id") val id: kotlin.Long? = null,
@SerialName(value = "name") val name: kotlin.String? = null
)

View File

@@ -0,0 +1,56 @@
/**
* OpenAPI Petstore
* This is a sample server Petstore server. For this sample, you can use the api key `special-key` to test the authorization filters.
*
* The version of the OpenAPI document: 1.0.0
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
* Do not edit the class manually.
*/
package org.openapitools.client.models
import kotlinx.serialization.*
import kotlinx.serialization.internal.CommonEnumSerializer
/**
* An order for a pets from the pet store
* @param id
* @param petId
* @param quantity
* @param shipDate
* @param status Order Status
* @param complete
*/
@Serializable
data class Order (
@SerialName(value = "id") val id: kotlin.Long? = null,
@SerialName(value = "petId") val petId: kotlin.Long? = null,
@SerialName(value = "quantity") val quantity: kotlin.Int? = null,
@SerialName(value = "shipDate") val shipDate: kotlin.String? = null,
/* Order Status */
@SerialName(value = "status") val status: Order.Status? = null,
@SerialName(value = "complete") val complete: kotlin.Boolean? = null
)
{
/**
* Order Status
* Values: placed,approved,delivered
*/
@Serializable(with = Status.Serializer::class)
enum class Status(val value: kotlin.String){
placed("placed"),
approved("approved"),
delivered("delivered");
object Serializer : CommonEnumSerializer<Status>("Status", values(), values().map { it.value }.toTypedArray())
}
}

View File

@@ -0,0 +1,58 @@
/**
* OpenAPI Petstore
* This is a sample server Petstore server. For this sample, you can use the api key `special-key` to test the authorization filters.
*
* The version of the OpenAPI document: 1.0.0
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
* Do not edit the class manually.
*/
package org.openapitools.client.models
import org.openapitools.client.models.Category
import org.openapitools.client.models.Tag
import kotlinx.serialization.*
import kotlinx.serialization.internal.CommonEnumSerializer
/**
* A pet for sale in the pet store
* @param id
* @param category
* @param name
* @param photoUrls
* @param tags
* @param status pet status in the store
*/
@Serializable
data class Pet (
@SerialName(value = "name") @Required val name: kotlin.String,
@SerialName(value = "photoUrls") @Required val photoUrls: kotlin.Array<kotlin.String>,
@SerialName(value = "id") val id: kotlin.Long? = null,
@SerialName(value = "category") val category: Category? = null,
@SerialName(value = "tags") val tags: kotlin.Array<Tag>? = null,
/* pet status in the store */
@SerialName(value = "status") val status: Pet.Status? = null
)
{
/**
* pet status in the store
* Values: available,pending,sold
*/
@Serializable(with = Status.Serializer::class)
enum class Status(val value: kotlin.String){
available("available"),
pending("pending"),
sold("sold");
object Serializer : CommonEnumSerializer<Status>("Status", values(), values().map { it.value }.toTypedArray())
}
}

View File

@@ -0,0 +1,28 @@
/**
* OpenAPI Petstore
* This is a sample server Petstore server. For this sample, you can use the api key `special-key` to test the authorization filters.
*
* The version of the OpenAPI document: 1.0.0
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
* Do not edit the class manually.
*/
package org.openapitools.client.models
import kotlinx.serialization.*
import kotlinx.serialization.internal.CommonEnumSerializer
/**
* A tag for a pet
* @param id
* @param name
*/
@Serializable
data class Tag (
@SerialName(value = "id") val id: kotlin.Long? = null,
@SerialName(value = "name") val name: kotlin.String? = null
)

View File

@@ -0,0 +1,41 @@
/**
* OpenAPI Petstore
* This is a sample server Petstore server. For this sample, you can use the api key `special-key` to test the authorization filters.
*
* The version of the OpenAPI document: 1.0.0
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
* Do not edit the class manually.
*/
package org.openapitools.client.models
import kotlinx.serialization.*
import kotlinx.serialization.internal.CommonEnumSerializer
/**
* A User who is purchasing from the pet store
* @param id
* @param username
* @param firstName
* @param lastName
* @param email
* @param password
* @param phone
* @param userStatus User Status
*/
@Serializable
data class User (
@SerialName(value = "id") val id: kotlin.Long? = null,
@SerialName(value = "username") val username: kotlin.String? = null,
@SerialName(value = "firstName") val firstName: kotlin.String? = null,
@SerialName(value = "lastName") val lastName: kotlin.String? = null,
@SerialName(value = "email") val email: kotlin.String? = null,
@SerialName(value = "password") val password: kotlin.String? = null,
@SerialName(value = "phone") val phone: kotlin.String? = null,
/* User Status */
@SerialName(value = "userStatus") val userStatus: kotlin.Int? = null
)

View File

@@ -0,0 +1,23 @@
/**
* OpenAPI Petstore
* This is a sample server Petstore server. For this sample, you can use the api key `special-key` to test the authorization filters.
*
* The version of the OpenAPI document: 1.0.0
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
* Do not edit the class manually.
*/
package util
import kotlinx.coroutines.CoroutineScope
/**
* Block the current thread until execution of the given coroutine is complete.
*
* @param block The coroutine code.
* @return The result of the coroutine.
*/
internal expect fun <T> runTest(block: suspend CoroutineScope.() -> T): T

View File

@@ -0,0 +1,18 @@
/**
* OpenAPI Petstore
* This is a sample server Petstore server. For this sample, you can use the api key `special-key` to test the authorization filters.
*
* The version of the OpenAPI document: 1.0.0
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
* Do not edit the class manually.
*/
package util
import kotlinx.coroutines.CoroutineScope
import kotlin.coroutines.EmptyCoroutineContext
internal actual fun <T> runTest(block: suspend CoroutineScope.() -> T): T = kotlinx.coroutines.runBlocking(EmptyCoroutineContext, block)

View File

@@ -0,0 +1,18 @@
/**
* OpenAPI Petstore
* This is a sample server Petstore server. For this sample, you can use the api key `special-key` to test the authorization filters.
*
* The version of the OpenAPI document: 1.0.0
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
* Do not edit the class manually.
*/
package util
import kotlinx.coroutines.CoroutineScope
import kotlin.coroutines.EmptyCoroutineContext
internal actual fun <T> runTest(block: suspend CoroutineScope.() -> T): T = kotlinx.coroutines.runBlocking(EmptyCoroutineContext, block)