[Kotlin] client improvement / remove WildCards in client/server (#2862)

This commit is contained in:
Vincent Devos 2019-05-11 05:42:11 +02:00 committed by William Cheng
parent 9323cad06b
commit ef26ce68d4
58 changed files with 656 additions and 340 deletions

4
.gitignore vendored
View File

@ -175,12 +175,14 @@ samples/client/petstore/typescript-angular/tsd-debug.log
# aspnetcore # aspnetcore
samples/server/petstore/aspnetcore/.vs/ samples/server/petstore/aspnetcore/.vs/
effective.pom effective.pom
# kotlin # kotlin
samples/client/petstore/kotlin/src/main/kotlin/test/ samples/client/petstore/kotlin/src/main/kotlin/test/
samples/client/petstore/kotlin-threetenbp/build samples/client/petstore/kotlin-threetenbp/build
samples/client/petstore/kotlin-string/build samples/client/petstore/kotlin-string/build
samples/server/petstore/kotlin-server/ktor/build
samples/openapi3/client/petstore/kotlin/build samples/openapi3/client/petstore/kotlin/build
samples/server/petstore/kotlin-server/ktor/build
samples/server/petstore/kotlin-springboot/build
\? \?
# haskell # haskell

View File

@ -8,14 +8,14 @@ sidebar_label: kotlin-server
| Option | Description | Values | Default | | Option | Description | Values | Default |
| ------ | ----------- | ------ | ------- | | ------ | ----------- | ------ | ------- |
|sourceFolder|source folder for generated code| |src/main/kotlin| |sourceFolder|source folder for generated code| |src/main/kotlin|
|packageName|Generated artifact package name.| |org.openapitools| |packageName|Generated artifact package name.| |org.openapitools.server|
|apiSuffix|suffix for api classes| |Api| |apiSuffix|suffix for api classes| |Api|
|groupId|Generated artifact package's organization (i.e. maven groupId).| |org.openapitools| |groupId|Generated artifact package's organization (i.e. maven groupId).| |org.openapitools|
|artifactId|Generated artifact id (name of jar).| |null| |artifactId|Generated artifact id (name of jar).| |kotlin-server|
|artifactVersion|Generated artifact's package version.| |1.0.0| |artifactVersion|Generated artifact's package version.| |1.0.0|
|enumPropertyNaming|Naming convention for enum properties: 'camelCase', 'PascalCase', 'snake_case', 'UPPERCASE', and 'original'| |camelCase| |enumPropertyNaming|Naming convention for enum properties: 'camelCase', 'PascalCase', 'snake_case', 'UPPERCASE', and 'original'| |camelCase|
|parcelizeModels|toggle "@Parcelize" for generated models| |null| |parcelizeModels|toggle "@Parcelize" for generated models| |null|
|library|library template (sub-template) to use|<dl><dt>**ktor**</dt><dd>ktor framework</dd><dl>|ktor| |library|library template (sub-template)|<dl><dt>**ktor**</dt><dd>ktor framework</dd><dl>|ktor|
|featureAutoHead|Automatically provide responses to HEAD requests for existing routes that have the GET verb defined.| |true| |featureAutoHead|Automatically provide responses to HEAD requests for existing routes that have the GET verb defined.| |true|
|featureConditionalHeaders|Avoid sending content if client already has same content, by checking ETag or LastModified properties.| |false| |featureConditionalHeaders|Avoid sending content if client already has same content, by checking ETag or LastModified properties.| |false|
|featureHSTS|Avoid sending content if client already has same content, by checking ETag or LastModified properties.| |true| |featureHSTS|Avoid sending content if client already has same content, by checking ETag or LastModified properties.| |true|

View File

@ -11,7 +11,7 @@ sidebar_label: kotlin-spring
|packageName|Generated artifact package name.| |org.openapitools| |packageName|Generated artifact package name.| |org.openapitools|
|apiSuffix|suffix for api classes| |Api| |apiSuffix|suffix for api classes| |Api|
|groupId|Generated artifact package's organization (i.e. maven groupId).| |org.openapitools| |groupId|Generated artifact package's organization (i.e. maven groupId).| |org.openapitools|
|artifactId|Generated artifact id (name of jar).| |null| |artifactId|Generated artifact id (name of jar).| |openapi-spring|
|artifactVersion|Generated artifact's package version.| |1.0.0| |artifactVersion|Generated artifact's package version.| |1.0.0|
|enumPropertyNaming|Naming convention for enum properties: 'camelCase', 'PascalCase', 'snake_case', 'UPPERCASE', and 'original'| |camelCase| |enumPropertyNaming|Naming convention for enum properties: 'camelCase', 'PascalCase', 'snake_case', 'UPPERCASE', and 'original'| |camelCase|
|parcelizeModels|toggle &quot;@Parcelize&quot; for generated models| |null| |parcelizeModels|toggle &quot;@Parcelize&quot; for generated models| |null|
@ -26,4 +26,4 @@ sidebar_label: kotlin-spring
|serviceInterface|generate service interfaces to go alongside controllers. In most cases this option would be used to update an existing project, so not to override implementations. Useful to help facilitate the generation gap pattern| |false| |serviceInterface|generate service interfaces to go alongside controllers. In most cases this option would be used to update an existing project, so not to override implementations. Useful to help facilitate the generation gap pattern| |false|
|serviceImplementation|generate stub service implementations that extends service interfaces. If this is set to true service interfaces will also be generated| |false| |serviceImplementation|generate stub service implementations that extends service interfaces. If this is set to true service interfaces will also be generated| |false|
|useBeanValidation|Use BeanValidation API annotations to validate data types| |true| |useBeanValidation|Use BeanValidation API annotations to validate data types| |true|
|library|library template (sub-template) to use|<dl><dt>**spring-boot**</dt><dd>Spring-boot Server application.</dd><dl>|spring-boot| |library|library template (sub-template)|<dl><dt>**spring-boot**</dt><dd>Spring-boot Server application.</dd><dl>|spring-boot|

View File

@ -8,12 +8,12 @@ sidebar_label: kotlin
| Option | Description | Values | Default | | Option | Description | Values | Default |
| ------ | ----------- | ------ | ------- | | ------ | ----------- | ------ | ------- |
|sourceFolder|source folder for generated code| |src/main/kotlin| |sourceFolder|source folder for generated code| |src/main/kotlin|
|packageName|Generated artifact package name.| |org.openapitools| |packageName|Generated artifact package name.| |org.openapitools.client|
|apiSuffix|suffix for api classes| |Api| |apiSuffix|suffix for api classes| |Api|
|groupId|Generated artifact package's organization (i.e. maven groupId).| |org.openapitools| |groupId|Generated artifact package's organization (i.e. maven groupId).| |org.openapitools|
|artifactId|Generated artifact id (name of jar).| |null| |artifactId|Generated artifact id (name of jar).| |kotlin-client|
|artifactVersion|Generated artifact's package version.| |1.0.0| |artifactVersion|Generated artifact's package version.| |1.0.0|
|enumPropertyNaming|Naming convention for enum properties: 'camelCase', 'PascalCase', 'snake_case', 'UPPERCASE', and 'original'| |camelCase| |enumPropertyNaming|Naming convention for enum properties: 'camelCase', 'PascalCase', 'snake_case', 'UPPERCASE', and 'original'| |camelCase|
|parcelizeModels|toggle &quot;@Parcelize&quot; for generated models| |null| |parcelizeModels|toggle &quot;@Parcelize&quot; for generated models| |null|
|dateLibrary|Option. Date library to use|<dl><dt>**string**</dt><dd>String</dd><dt>**java8**</dt><dd>Java 8 native JSR310</dd><dt>**threetenbp**</dt><dd>Threetenbp</dd><dl>|null| |dateLibrary|Option. Date library to use|<dl><dt>**string**</dt><dd>String</dd><dt>**java8**</dt><dd>Java 8 native JSR310</dd><dt>**threetenbp**</dt><dd>Threetenbp</dd><dl>|java8|
|collectionType|Option. Collection type to use|<dl><dt>**array**</dt><dd>kotlin.Array</dd><dt>**list**</dt><dd>kotlin.collections.List</dd><dl>|null| |collectionType|Option. Collection type to use|<dl><dt>**array**</dt><dd>kotlin.Array</dd><dt>**list**</dt><dd>kotlin.collections.List</dd><dl>|array|

View File

@ -102,7 +102,7 @@ public class JavaClientCodegen extends AbstractJavaCodegen
apiPackage = "org.openapitools.client.api"; apiPackage = "org.openapitools.client.api";
modelPackage = "org.openapitools.client.model"; modelPackage = "org.openapitools.client.model";
// clioOptions default redifinition need to be updated // cliOptions default redefinition need to be updated
updateOption(CodegenConstants.INVOKER_PACKAGE, this.getInvokerPackage()); updateOption(CodegenConstants.INVOKER_PACKAGE, this.getInvokerPackage());
updateOption(CodegenConstants.ARTIFACT_ID, this.getArtifactId()); updateOption(CodegenConstants.ARTIFACT_ID, this.getArtifactId());
updateOption(CodegenConstants.API_PACKAGE, apiPackage); updateOption(CodegenConstants.API_PACKAGE, apiPackage);

View File

@ -21,8 +21,6 @@ import org.openapitools.codegen.CliOption;
import org.openapitools.codegen.CodegenConstants; import org.openapitools.codegen.CodegenConstants;
import org.openapitools.codegen.CodegenType; import org.openapitools.codegen.CodegenType;
import org.openapitools.codegen.SupportingFile; import org.openapitools.codegen.SupportingFile;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File; import java.io.File;
import java.util.HashMap; import java.util.HashMap;
@ -32,7 +30,6 @@ public class KotlinClientCodegen extends AbstractKotlinCodegen {
public static final String DATE_LIBRARY = "dateLibrary"; public static final String DATE_LIBRARY = "dateLibrary";
public static final String COLLECTION_TYPE = "collectionType"; public static final String COLLECTION_TYPE = "collectionType";
private static final Logger LOGGER = LoggerFactory.getLogger(KotlinClientCodegen.class);
protected String dateLibrary = DateLibrary.JAVA8.value; protected String dateLibrary = DateLibrary.JAVA8.value;
protected String collectionType = CollectionType.ARRAY.value; protected String collectionType = CollectionType.ARRAY.value;
@ -69,6 +66,10 @@ public class KotlinClientCodegen extends AbstractKotlinCodegen {
artifactId = "kotlin-client"; artifactId = "kotlin-client";
packageName = "org.openapitools.client"; packageName = "org.openapitools.client";
// cliOptions default redefinition need to be updated
updateOption(CodegenConstants.ARTIFACT_ID, this.artifactId);
updateOption(CodegenConstants.PACKAGE_NAME, this.packageName);
outputFolder = "generated-code" + File.separator + "kotlin-client"; outputFolder = "generated-code" + File.separator + "kotlin-client";
modelTemplateFiles.put("model.mustache", ".kt"); modelTemplateFiles.put("model.mustache", ".kt");
apiTemplateFiles.put("api.mustache", ".kt"); apiTemplateFiles.put("api.mustache", ".kt");
@ -78,14 +79,13 @@ public class KotlinClientCodegen extends AbstractKotlinCodegen {
apiPackage = packageName + ".apis"; apiPackage = packageName + ".apis";
modelPackage = packageName + ".models"; modelPackage = packageName + ".models";
enumPropertyNaming = CodegenConstants.ENUM_PROPERTY_NAMING_TYPE.camelCase;
CliOption dateLibrary = new CliOption(DATE_LIBRARY, "Option. Date library to use"); CliOption dateLibrary = new CliOption(DATE_LIBRARY, "Option. Date library to use");
Map<String, String> dateOptions = new HashMap<>(); Map<String, String> dateOptions = new HashMap<>();
dateOptions.put(DateLibrary.THREETENBP.value, "Threetenbp"); dateOptions.put(DateLibrary.THREETENBP.value, "Threetenbp");
dateOptions.put(DateLibrary.STRING.value, "String"); dateOptions.put(DateLibrary.STRING.value, "String");
dateOptions.put(DateLibrary.JAVA8.value, "Java 8 native JSR310"); dateOptions.put(DateLibrary.JAVA8.value, "Java 8 native JSR310");
dateLibrary.setEnum(dateOptions); dateLibrary.setEnum(dateOptions);
dateLibrary.setDefault(this.dateLibrary);
cliOptions.add(dateLibrary); cliOptions.add(dateLibrary);
CliOption collectionType = new CliOption(COLLECTION_TYPE, "Option. Collection type to use"); CliOption collectionType = new CliOption(COLLECTION_TYPE, "Option. Collection type to use");
@ -93,6 +93,7 @@ public class KotlinClientCodegen extends AbstractKotlinCodegen {
collectionOptions.put(CollectionType.ARRAY.value, "kotlin.Array"); collectionOptions.put(CollectionType.ARRAY.value, "kotlin.Array");
collectionOptions.put(CollectionType.LIST.value, "kotlin.collections.List"); collectionOptions.put(CollectionType.LIST.value, "kotlin.collections.List");
collectionType.setEnum(collectionOptions); collectionType.setEnum(collectionOptions);
collectionType.setDefault(this.collectionType);
cliOptions.add(collectionType); cliOptions.add(collectionType);
} }

View File

@ -62,6 +62,11 @@ public class KotlinServerCodegen extends AbstractKotlinCodegen {
artifactId = "kotlin-server"; artifactId = "kotlin-server";
packageName = "org.openapitools.server"; packageName = "org.openapitools.server";
// cliOptions default redefinition need to be updated
updateOption(CodegenConstants.ARTIFACT_ID, this.artifactId);
updateOption(CodegenConstants.PACKAGE_NAME, this.packageName);
outputFolder = "generated-code" + File.separator + "kotlin-server"; outputFolder = "generated-code" + File.separator + "kotlin-server";
modelTemplateFiles.put("model.mustache", ".kt"); modelTemplateFiles.put("model.mustache", ".kt");
apiTemplateFiles.put("api.mustache", ".kt"); apiTemplateFiles.put("api.mustache", ".kt");
@ -69,10 +74,10 @@ public class KotlinServerCodegen extends AbstractKotlinCodegen {
apiPackage = packageName + ".apis"; apiPackage = packageName + ".apis";
modelPackage = packageName + ".models"; modelPackage = packageName + ".models";
supportedLibraries.put("ktor", "ktor framework"); supportedLibraries.put(Constants.KTOR, "ktor framework");
// TODO: Configurable server engine. Defaults to netty in build.gradle. // TODO: Configurable server engine. Defaults to netty in build.gradle.
CliOption library = new CliOption(CodegenConstants.LIBRARY, "library template (sub-template) to use"); CliOption library = new CliOption(CodegenConstants.LIBRARY, CodegenConstants.LIBRARY_DESC);
library.setDefault(DEFAULT_LIBRARY); library.setDefault(DEFAULT_LIBRARY);
library.setEnum(supportedLibraries); library.setEnum(supportedLibraries);
@ -147,9 +152,9 @@ public class KotlinServerCodegen extends AbstractKotlinCodegen {
// set default library to "ktor" // set default library to "ktor"
if (StringUtils.isEmpty(library)) { if (StringUtils.isEmpty(library)) {
this.setLibrary("ktor"); this.setLibrary(DEFAULT_LIBRARY);
additionalProperties.put(CodegenConstants.LIBRARY, "ktor"); additionalProperties.put(CodegenConstants.LIBRARY, DEFAULT_LIBRARY);
LOGGER.info("`library` option is empty. Default to 'ktor'."); LOGGER.info("`library` option is empty. Default to " + DEFAULT_LIBRARY);
} }
if (additionalProperties.containsKey(Constants.AUTOMATIC_HEAD_REQUESTS)) { if (additionalProperties.containsKey(Constants.AUTOMATIC_HEAD_REQUESTS)) {
@ -182,7 +187,7 @@ public class KotlinServerCodegen extends AbstractKotlinCodegen {
additionalProperties.put(Constants.COMPRESSION, getCompressionFeatureEnabled()); additionalProperties.put(Constants.COMPRESSION, getCompressionFeatureEnabled());
} }
Boolean generateApis = additionalProperties.containsKey(CodegenConstants.GENERATE_APIS) && (Boolean)additionalProperties.get(CodegenConstants.GENERATE_APIS); boolean generateApis = additionalProperties.containsKey(CodegenConstants.GENERATE_APIS) && (Boolean)additionalProperties.get(CodegenConstants.GENERATE_APIS);
String packageFolder = (sourceFolder + File.separator + packageName).replace(".", File.separator); String packageFolder = (sourceFolder + File.separator + packageName).replace(".", File.separator);
String resourcesFolder = "src/main/resources"; // not sure this can be user configurable. String resourcesFolder = "src/main/resources"; // not sure this can be user configurable.
@ -226,7 +231,7 @@ public class KotlinServerCodegen extends AbstractKotlinCodegen {
if (objs.containsKey("lambda")) { if (objs.containsKey("lambda")) {
LOGGER.warn("A property named 'lambda' already exists. Mustache lambdas renamed from 'lambda' to '_lambda'. " + LOGGER.warn("A property named 'lambda' already exists. Mustache lambdas renamed from 'lambda' to '_lambda'. " +
"You'll likely need to use a custom template, " + "You'll likely need to use a custom template, " +
"see https://github.com/swagger-api/swagger-codegen#modifying-the-client-library-format. "); // TODO: update the URL "see https://github.com/OpenAPITools/openapi-generator/blob/master/docs/templating.md. ");
objs.put("_lambda", lambdas); objs.put("_lambda", lambdas);
} else { } else {
objs.put("lambda", lambdas); objs.put("lambda", lambdas);

View File

@ -87,6 +87,9 @@ public class KotlinSpringServerCodegen extends AbstractKotlinCodegen
apiPackage = "org.openapitools.api"; apiPackage = "org.openapitools.api";
modelPackage = "org.openapitools.model"; modelPackage = "org.openapitools.model";
// cliOptions default redefinition need to be updated
updateOption(CodegenConstants.ARTIFACT_ID, this.artifactId);
// Use lists instead of arrays // Use lists instead of arrays
typeMapping.put("array", "List"); typeMapping.put("array", "List");
typeMapping.put("string", "String"); typeMapping.put("string", "String");
@ -149,7 +152,7 @@ public class KotlinSpringServerCodegen extends AbstractKotlinCodegen
supportedLibraries.put(SPRING_BOOT, "Spring-boot Server application."); supportedLibraries.put(SPRING_BOOT, "Spring-boot Server application.");
setLibrary(SPRING_BOOT); setLibrary(SPRING_BOOT);
CliOption cliOpt = new CliOption(CodegenConstants.LIBRARY, "library template (sub-template) to use"); CliOption cliOpt = new CliOption(CodegenConstants.LIBRARY, CodegenConstants.LIBRARY_DESC);
cliOpt.setDefault(SPRING_BOOT); cliOpt.setDefault(SPRING_BOOT);
cliOpt.setEnum(supportedLibraries); cliOpt.setEnum(supportedLibraries);
cliOptions.add(cliOpt); cliOptions.add(cliOpt);

View File

@ -2,7 +2,7 @@
## Requires ## Requires
* Kotlin 1.3.20 * Kotlin 1.3.31
* Gradle 4.9 * Gradle 4.9
## Build ## Build

View File

@ -4,7 +4,17 @@ package {{apiPackage}}
{{#imports}}import {{import}} {{#imports}}import {{import}}
{{/imports}} {{/imports}}
import {{packageName}}.infrastructure.* import {{packageName}}.infrastructure.ApiClient
import {{packageName}}.infrastructure.ClientException
import {{packageName}}.infrastructure.ClientError
import {{packageName}}.infrastructure.ServerException
import {{packageName}}.infrastructure.ServerError
import {{packageName}}.infrastructure.MultiValueMap
import {{packageName}}.infrastructure.RequestConfig
import {{packageName}}.infrastructure.RequestMethod
import {{packageName}}.infrastructure.ResponseType
import {{packageName}}.infrastructure.Success
import {{packageName}}.infrastructure.toMultiValue
{{#threetenbp}} {{#threetenbp}}
import org.threeten.bp.LocalDateTime import org.threeten.bp.LocalDateTime
{{/threetenbp}} {{/threetenbp}}
@ -23,7 +33,7 @@ class {{classname}}(basePath: kotlin.String = "{{{basePath}}}") : ApiClient(base
fun {{operationId}}({{#allParams}}{{paramName}}: {{{dataType}}}{{^required}}?{{/required}}{{#hasMore}}, {{/hasMore}}{{/allParams}}) : {{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}Unit{{/returnType}} { fun {{operationId}}({{#allParams}}{{paramName}}: {{{dataType}}}{{^required}}?{{/required}}{{#hasMore}}, {{/hasMore}}{{/allParams}}) : {{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}Unit{{/returnType}} {
val localVariableBody: kotlin.Any? = {{#hasBodyParam}}{{#bodyParams}}{{paramName}}{{/bodyParams}}{{/hasBodyParam}}{{^hasBodyParam}}{{^hasFormParams}}null{{/hasFormParams}}{{#hasFormParams}}mapOf({{#formParams}}"{{{baseName}}}" to "${{paramName}}"{{#hasMore}}, {{/hasMore}}{{/formParams}}){{/hasFormParams}}{{/hasBodyParam}} val localVariableBody: kotlin.Any? = {{#hasBodyParam}}{{#bodyParams}}{{paramName}}{{/bodyParams}}{{/hasBodyParam}}{{^hasBodyParam}}{{^hasFormParams}}null{{/hasFormParams}}{{#hasFormParams}}mapOf({{#formParams}}"{{{baseName}}}" to "${{paramName}}"{{#hasMore}}, {{/hasMore}}{{/formParams}}){{/hasFormParams}}{{/hasBodyParam}}
val localVariableQuery: MultiValueMap = {{^hasQueryParams}}mapOf(){{/hasQueryParams}}{{#hasQueryParams}}mapOf({{#queryParams}}"{{paramName}}" to {{#isContainer}}toMultiValue({{paramName}}.toList(), "{{collectionFormat}}"){{/isContainer}}{{^isContainer}}listOf("${{paramName}}"){{/isContainer}}{{#hasMore}}, {{/hasMore}}{{/queryParams}}){{/hasQueryParams}} val localVariableQuery: MultiValueMap = {{^hasQueryParams}}mapOf(){{/hasQueryParams}}{{#hasQueryParams}}mapOf({{#queryParams}}"{{paramName}}" to {{#isContainer}}toMultiValue({{paramName}}.toList(), "{{collectionFormat}}"){{/isContainer}}{{^isContainer}}listOf("${{paramName}}"){{/isContainer}}{{#hasMore}}, {{/hasMore}}{{/queryParams}}){{/hasQueryParams}}
val localVariableHeaders: kotlin.collections.Map<kotlin.String,kotlin.String> = mapOf({{#hasFormParams}}"Content-Type" to "multipart/form-data"{{/hasFormParams}}{{^hasHeaderParams}}){{/hasHeaderParams}}{{#hasHeaderParams}}{{#hasFormParams}}, {{/hasFormParams}}{{#headerParams}}"{{baseName}}" to {{#isContainer}}{{paramName}}.joinToString(separator = collectionDelimiter("{{collectionFormat}}")){{/isContainer}}{{^isContainer}}{{paramName}}.toString(){{/isContainer}}{{#hasMore}}, {{/hasMore}}{{/headerParams}}){{/hasHeaderParams}} val localVariableHeaders: MutableMap<String, String> = mutableMapOf({{#hasFormParams}}"Content-Type" to {{^consumes}}"multipart/form-data"{{/consumes}}{{#consumes.0}}"{{MediaType}}"{{/consumes.0}}{{/hasFormParams}}{{^hasHeaderParams}}){{/hasHeaderParams}}{{#hasHeaderParams}}{{#hasFormParams}}, {{/hasFormParams}}{{#headerParams}}"{{baseName}}" to {{#isContainer}}{{paramName}}.joinToString(separator = collectionDelimiter("{{collectionFormat}}")){{/isContainer}}{{^isContainer}}{{paramName}}.toString(){{/isContainer}}{{#hasMore}}, {{/hasMore}}{{/headerParams}}){{/hasHeaderParams}}
val localVariableConfig = RequestConfig( val localVariableConfig = RequestConfig(
RequestMethod.{{httpMethod}}, RequestMethod.{{httpMethod}},
"{{path}}"{{#pathParams}}.replace("{"+"{{baseName}}"+"}", "${{paramName}}"){{/pathParams}}, "{{path}}"{{#pathParams}}.replace("{"+"{{baseName}}"+"}", "${{paramName}}"){{/pathParams}},

View File

@ -7,7 +7,7 @@ wrapper {
} }
buildscript { buildscript {
ext.kotlin_version = '1.3.20' ext.kotlin_version = '1.3.31'
repositories { repositories {
mavenCentral() mavenCentral()
@ -32,7 +32,7 @@ dependencies {
compile "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version" compile "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
compile "com.squareup.moshi:moshi-kotlin:1.5.0" compile "com.squareup.moshi:moshi-kotlin:1.5.0"
compile "com.squareup.moshi:moshi-adapters:1.5.0" compile "com.squareup.moshi:moshi-adapters:1.5.0"
compile "com.squareup.okhttp3:okhttp:3.8.0" compile "com.squareup.okhttp3:okhttp:3.14.0"
compile "org.threeten:threetenbp:1.3.6" compile "org.threeten:threetenbp:1.3.8"
testImplementation "io.kotlintest:kotlintest-runner-junit5:3.1.0" testImplementation "io.kotlintest:kotlintest-runner-junit5:3.1.0"
} }

View File

@ -3,9 +3,15 @@ package {{packageName}}.infrastructure
import com.squareup.moshi.FromJson import com.squareup.moshi.FromJson
import com.squareup.moshi.Moshi import com.squareup.moshi.Moshi
import com.squareup.moshi.ToJson import com.squareup.moshi.ToJson
import okhttp3.* import okhttp3.OkHttpClient
import okhttp3.RequestBody
import okhttp3.MediaType
import okhttp3.FormBody
import okhttp3.HttpUrl
import okhttp3.ResponseBody
import okhttp3.Request
import java.io.File import java.io.File
import java.util.* import java.util.UUID
open class ApiClient(val baseUrl: String) { open class ApiClient(val baseUrl: String) {
companion object { companion object {
@ -13,6 +19,7 @@ open class ApiClient(val baseUrl: String) {
protected const val Accept = "Accept" protected const val Accept = "Accept"
protected const val JsonMediaType = "application/json" protected const val JsonMediaType = "application/json"
protected const val FormDataMediaType = "multipart/form-data" protected const val FormDataMediaType = "multipart/form-data"
protected const val FormUrlEncMediaType = "application/x-www-form-urlencoded"
protected const val XmlMediaType = "application/xml" protected const val XmlMediaType = "application/xml"
@JvmStatic @JvmStatic
@ -22,38 +29,38 @@ open class ApiClient(val baseUrl: String) {
@JvmStatic @JvmStatic
val builder: OkHttpClient.Builder = OkHttpClient.Builder() val builder: OkHttpClient.Builder = OkHttpClient.Builder()
@JvmStatic
var defaultHeaders: Map<String, String> by ApplicationDelegates.setOnce(mapOf(ContentType to JsonMediaType, Accept to JsonMediaType))
@JvmStatic
val jsonHeaders: Map<String, String> = mapOf(ContentType to JsonMediaType, Accept to JsonMediaType)
} }
protected inline fun <reified T> requestBody(content: T, mediaType: String = JsonMediaType): RequestBody = protected inline fun <reified T> requestBody(content: T, mediaType: String = JsonMediaType): RequestBody =
when { when {
content is File -> RequestBody.create( content is File -> RequestBody.create(
MediaType.parse(mediaType), content MediaType.parse(mediaType), content
) )
mediaType == FormDataMediaType -> { mediaType == FormDataMediaType || mediaType == FormUrlEncMediaType -> {
var builder = FormBody.Builder() var builder = FormBody.Builder()
// content's type *must* be Map<String, Any> // content's type *must* be Map<String, Any>
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
(content as Map<String,String>).forEach { key, value -> (content as Map<String,String>).forEach { key, value ->
builder = builder.add(key, value) builder = builder.add(key, value)
} }
builder.build() builder.build()
} }
mediaType == JsonMediaType -> RequestBody.create( mediaType == JsonMediaType -> RequestBody.create(
MediaType.parse(mediaType), Serializer.moshi.adapter(T::class.java).toJson(content) MediaType.parse(mediaType), Serializer.moshi.adapter(T::class.java).toJson(content)
) )
mediaType == XmlMediaType -> TODO("xml not currently supported.") mediaType == XmlMediaType -> TODO("xml not currently supported.")
// TODO: this should be extended with other serializers // TODO: this should be extended with other serializers
else -> TODO("requestBody currently only supports JSON body and File body.") else -> TODO("requestBody currently only supports JSON body and File body.")
} }
protected inline fun <reified T: Any?> responseBody(body: ResponseBody?, mediaType: String = JsonMediaType): T? { protected inline fun <reified T: Any?> responseBody(body: ResponseBody?, mediaType: String? = JsonMediaType): T? {
if(body == null) return null if(body == null) {
return null
}
val bodyContent = body.string()
if (bodyContent.length == 0) {
return null
}
return when(mediaType) { return when(mediaType) {
JsonMediaType -> Moshi.Builder().add(object { JsonMediaType -> Moshi.Builder().add(object {
@ToJson @ToJson
@ -62,8 +69,8 @@ open class ApiClient(val baseUrl: String) {
fun fromJson(s: String) = UUID.fromString(s) fun fromJson(s: String) = UUID.fromString(s)
}) })
.add(ByteArrayAdapter()) .add(ByteArrayAdapter())
.build().adapter(T::class.java).fromJson(body.source()) .build().adapter(T::class.java).fromJson(bodyContent)
else -> TODO() else -> TODO("responseBody currently only supports JSON body.")
} }
} }
@ -80,7 +87,15 @@ open class ApiClient(val baseUrl: String) {
} }
val url = urlBuilder.build() val url = urlBuilder.build()
val headers = requestConfig.headers + defaultHeaders
// take content-type/accept from spec or set to default (application/json) if not defined
if (requestConfig.headers[ContentType].isNullOrEmpty()) {
requestConfig.headers.put(ContentType, JsonMediaType)
}
if (requestConfig.headers[Accept].isNullOrEmpty()) {
requestConfig.headers.put(Accept, JsonMediaType)
}
val headers = requestConfig.headers
if(headers[ContentType] ?: "" == "") { if(headers[ContentType] ?: "" == "") {
throw kotlin.IllegalStateException("Missing Content-Type header. This is required.") throw kotlin.IllegalStateException("Missing Content-Type header. This is required.")
@ -90,9 +105,8 @@ open class ApiClient(val baseUrl: String) {
throw kotlin.IllegalStateException("Missing Accept header. This is required.") throw kotlin.IllegalStateException("Missing Accept header. This is required.")
} }
// TODO: support multiple contentType,accept options here. // TODO: support multiple contentType options here.
val contentType = (headers[ContentType] as String).substringBefore(";").toLowerCase() val contentType = (headers[ContentType] as String).substringBefore(";").toLowerCase()
val accept = (headers[Accept] as String).substringBefore(";").toLowerCase()
var request : Request.Builder = when (requestConfig.method) { var request : Request.Builder = when (requestConfig.method) {
RequestMethod.DELETE -> Request.Builder().url(url).delete() RequestMethod.DELETE -> Request.Builder().url(url).delete()
@ -108,6 +122,7 @@ open class ApiClient(val baseUrl: String) {
val realRequest = request.build() val realRequest = request.build()
val response = client.newCall(realRequest).execute() val response = client.newCall(realRequest).execute()
val accept = response.header(ContentType)?.substringBefore(";")?.toLowerCase()
// TODO: handle specific mapping types. e.g. Map<int, Class<?>> // TODO: handle specific mapping types. e.g. Map<int, Class<?>>
when { when {

View File

@ -11,6 +11,6 @@ package {{packageName}}.infrastructure
data class RequestConfig( data class RequestConfig(
val method: RequestMethod, val method: RequestMethod,
val path: String, val path: String,
val headers: Map<String, String> = mapOf(), val headers: MutableMap<String, String> = mutableMapOf(),
val query: Map<String, List<String>> = mapOf() val query: Map<String, List<String>> = mapOf()
) )

View File

@ -2,8 +2,15 @@ package {{packageName}}.infrastructure
import io.ktor.application.ApplicationCall import io.ktor.application.ApplicationCall
import io.ktor.application.call import io.ktor.application.call
import io.ktor.auth.* import io.ktor.auth.Authentication
import io.ktor.http.auth.* import io.ktor.auth.AuthenticationFailedCause
import io.ktor.auth.AuthenticationPipeline
import io.ktor.auth.AuthenticationProvider
import io.ktor.auth.Credential
import io.ktor.auth.Principal
import io.ktor.auth.UnauthorizedResponse
import io.ktor.http.auth.HeaderValueEncoding
import io.ktor.http.auth.HttpAuthHeader
import io.ktor.request.ApplicationRequest import io.ktor.request.ApplicationRequest
import io.ktor.response.respond import io.ktor.response.respond

View File

@ -1,29 +1,36 @@
package {{packageName}} package {{packageName}}
import com.codahale.metrics.* import com.codahale.metrics.Slf4jReporter
import com.typesafe.config.ConfigFactory import com.typesafe.config.ConfigFactory
import io.ktor.application.* import io.ktor.application.Application
import io.ktor.application.ApplicationStopping
import io.ktor.application.install
import io.ktor.application.log
import io.ktor.client.HttpClient import io.ktor.client.HttpClient
import io.ktor.client.engine.apache.Apache import io.ktor.client.engine.apache.Apache
import io.ktor.config.HoconApplicationConfig import io.ktor.config.HoconApplicationConfig
import io.ktor.features.* import io.ktor.features.AutoHeadResponse
import io.ktor.features.Compression
import io.ktor.features.ContentNegotiation
import io.ktor.features.DefaultHeaders
import io.ktor.features.HSTS
import io.ktor.gson.GsonConverter import io.ktor.gson.GsonConverter
import io.ktor.http.ContentType import io.ktor.http.ContentType
import io.ktor.locations.* import io.ktor.locations.KtorExperimentalLocationsAPI
import io.ktor.metrics.* import io.ktor.locations.Locations
import io.ktor.routing.* import io.ktor.metrics.Metrics
import java.util.concurrent.* import io.ktor.routing.Routing
import java.util.concurrent.TimeUnit
{{#hasAuthMethods}} {{#hasAuthMethods}}
import io.ktor.auth.* import io.ktor.auth.Authentication
import io.ktor.auth.oauth
import io.ktor.util.KtorExperimentalAPI import io.ktor.util.KtorExperimentalAPI
import org.openapitools.server.infrastructure.* import org.openapitools.server.infrastructure.ApiKeyCredential
import org.openapitools.server.infrastructure.ApiPrincipal
import org.openapitools.server.infrastructure.apiKeyAuth
{{/hasAuthMethods}} {{/hasAuthMethods}}
{{#generateApis}} {{#generateApis}}{{#apiInfo}}{{#apis}}import {{apiPackage}}.{{classname}}
import {{apiPackage}}.* {{/apis}}{{/apiInfo}}{{/generateApis}}
{{/generateApis}}
{{#imports}}import {{import}}
{{/imports}}
@KtorExperimentalAPI @KtorExperimentalAPI
internal val settings = HoconApplicationConfig(ConfigFactory.defaultApplication(HTTP::class.java.classLoader)) internal val settings = HoconApplicationConfig(ConfigFactory.defaultApplication(HTTP::class.java.classLoader))

View File

@ -2,8 +2,12 @@ package {{packageName}}
// Use this file to hold package-level internal functions that return receiver object passed to the `install` method. // Use this file to hold package-level internal functions that return receiver object passed to the `install` method.
import io.ktor.auth.OAuthServerSettings import io.ktor.auth.OAuthServerSettings
import io.ktor.features.* import io.ktor.features.Compression
import io.ktor.http.* import io.ktor.features.HSTS
import io.ktor.features.deflate
import io.ktor.features.gzip
import io.ktor.features.minimumSize
import io.ktor.http.HttpMethod
import io.ktor.util.KtorExperimentalAPI import io.ktor.util.KtorExperimentalAPI
import java.time.Duration import java.time.Duration
import java.util.concurrent.Executors import java.util.concurrent.Executors

View File

@ -1,11 +1,9 @@
{{>licenseInfo}} {{>licenseInfo}}
package {{packageName}} package {{packageName}}
import io.ktor.locations.* import io.ktor.locations.KtorExperimentalLocationsAPI
import {{modelPackage}}.* import io.ktor.locations.Location
{{#imports}}import {{import}}
{{#imports}}
import {{import}}
{{/imports}} {{/imports}}
{{#apiInfo}} {{#apiInfo}}

View File

@ -10,10 +10,15 @@ import io.ktor.auth.OAuthAccessTokenResponse
import io.ktor.auth.OAuthServerSettings import io.ktor.auth.OAuthServerSettings
import io.ktor.http.ContentType import io.ktor.http.ContentType
import io.ktor.http.HttpStatusCode import io.ktor.http.HttpStatusCode
import io.ktor.locations.* import io.ktor.locations.KtorExperimentalLocationsAPI
import io.ktor.locations.delete
import io.ktor.locations.get
import io.ktor.response.respond import io.ktor.response.respond
import io.ktor.response.respondText import io.ktor.response.respondText
import io.ktor.routing.* import io.ktor.routing.Route
import io.ktor.routing.post
import io.ktor.routing.put
import io.ktor.routing.route
import {{packageName}}.Paths import {{packageName}}.Paths
import {{packageName}}.infrastructure.ApiPrincipal import {{packageName}}.infrastructure.ApiPrincipal

View File

@ -3,7 +3,13 @@ package {{package}}
{{#imports}}import {{import}} {{#imports}}import {{import}}
{{/imports}} {{/imports}}
{{#swaggerAnnotations}} {{#swaggerAnnotations}}
import io.swagger.annotations.* import io.swagger.annotations.Api
import io.swagger.annotations.ApiOperation
import io.swagger.annotations.ApiParam
import io.swagger.annotations.ApiResponse
import io.swagger.annotations.ApiResponses
import io.swagger.annotations.Authorization
import io.swagger.annotations.AuthorizationScope
{{/swaggerAnnotations}} {{/swaggerAnnotations}}
import org.springframework.http.HttpStatus import org.springframework.http.HttpStatus
import org.springframework.http.MediaType import org.springframework.http.MediaType
@ -24,7 +30,13 @@ import org.springframework.beans.factory.annotation.Autowired
{{#useBeanValidation}} {{#useBeanValidation}}
import javax.validation.Valid import javax.validation.Valid
import javax.validation.constraints.* import javax.validation.constraints.DecimalMax
import javax.validation.constraints.DecimalMin
import javax.validation.constraints.Max
import javax.validation.constraints.Min
import javax.validation.constraints.NotNull
import javax.validation.constraints.Pattern
import javax.validation.constraints.Size
{{/useBeanValidation}} {{/useBeanValidation}}
import kotlin.collections.List import kotlin.collections.List

View File

@ -4,8 +4,13 @@ import java.util.Objects
{{#imports}}import {{import}} {{#imports}}import {{import}}
{{/imports}} {{/imports}}
{{#useBeanValidation}} {{#useBeanValidation}}
import javax.validation.Valid import javax.validation.constraints.DecimalMax
import javax.validation.constraints.* import javax.validation.constraints.DecimalMin
import javax.validation.constraints.Max
import javax.validation.constraints.Min
import javax.validation.constraints.NotNull
import javax.validation.constraints.Pattern
import javax.validation.constraints.Size
{{/useBeanValidation}} {{/useBeanValidation}}
{{#swaggerAnnotations}} {{#swaggerAnnotations}}
import io.swagger.annotations.ApiModelProperty import io.swagger.annotations.ApiModelProperty

View File

@ -2,7 +2,7 @@
## Requires ## Requires
* Kotlin 1.3.20 * Kotlin 1.3.31
* Gradle 4.9 * Gradle 4.9
## Build ## Build

View File

@ -7,7 +7,7 @@ wrapper {
} }
buildscript { buildscript {
ext.kotlin_version = '1.3.20' ext.kotlin_version = '1.3.31'
repositories { repositories {
mavenCentral() mavenCentral()
@ -32,7 +32,7 @@ dependencies {
compile "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version" compile "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
compile "com.squareup.moshi:moshi-kotlin:1.5.0" compile "com.squareup.moshi:moshi-kotlin:1.5.0"
compile "com.squareup.moshi:moshi-adapters:1.5.0" compile "com.squareup.moshi:moshi-adapters:1.5.0"
compile "com.squareup.okhttp3:okhttp:3.8.0" compile "com.squareup.okhttp3:okhttp:3.14.0"
compile "org.threeten:threetenbp:1.3.6" compile "org.threeten:threetenbp:1.3.8"
testImplementation "io.kotlintest:kotlintest-runner-junit5:3.1.0" testImplementation "io.kotlintest:kotlintest-runner-junit5:3.1.0"
} }

View File

@ -14,7 +14,17 @@ package org.openapitools.client.apis
import org.openapitools.client.models.ApiResponse import org.openapitools.client.models.ApiResponse
import org.openapitools.client.models.Pet import org.openapitools.client.models.Pet
import org.openapitools.client.infrastructure.* import org.openapitools.client.infrastructure.ApiClient
import org.openapitools.client.infrastructure.ClientException
import org.openapitools.client.infrastructure.ClientError
import org.openapitools.client.infrastructure.ServerException
import org.openapitools.client.infrastructure.ServerError
import org.openapitools.client.infrastructure.MultiValueMap
import org.openapitools.client.infrastructure.RequestConfig
import org.openapitools.client.infrastructure.RequestMethod
import org.openapitools.client.infrastructure.ResponseType
import org.openapitools.client.infrastructure.Success
import org.openapitools.client.infrastructure.toMultiValue
class PetApi(basePath: kotlin.String = "http://petstore.swagger.io/v2") : ApiClient(basePath) { class PetApi(basePath: kotlin.String = "http://petstore.swagger.io/v2") : ApiClient(basePath) {
@ -27,7 +37,7 @@ class PetApi(basePath: kotlin.String = "http://petstore.swagger.io/v2") : ApiCli
fun addPet(body: Pet) : Unit { fun addPet(body: Pet) : Unit {
val localVariableBody: kotlin.Any? = body val localVariableBody: kotlin.Any? = body
val localVariableQuery: MultiValueMap = mapOf() val localVariableQuery: MultiValueMap = mapOf()
val localVariableHeaders: kotlin.collections.Map<kotlin.String,kotlin.String> = mapOf() val localVariableHeaders: MutableMap<String, String> = mutableMapOf()
val localVariableConfig = RequestConfig( val localVariableConfig = RequestConfig(
RequestMethod.POST, RequestMethod.POST,
"/pet", "/pet",
@ -58,7 +68,7 @@ class PetApi(basePath: kotlin.String = "http://petstore.swagger.io/v2") : ApiCli
fun deletePet(petId: kotlin.Long, apiKey: kotlin.String?) : Unit { fun deletePet(petId: kotlin.Long, apiKey: kotlin.String?) : Unit {
val localVariableBody: kotlin.Any? = null val localVariableBody: kotlin.Any? = null
val localVariableQuery: MultiValueMap = mapOf() val localVariableQuery: MultiValueMap = mapOf()
val localVariableHeaders: kotlin.collections.Map<kotlin.String,kotlin.String> = mapOf("api_key" to apiKey.toString()) val localVariableHeaders: MutableMap<String, String> = mutableMapOf("api_key" to apiKey.toString())
val localVariableConfig = RequestConfig( val localVariableConfig = RequestConfig(
RequestMethod.DELETE, RequestMethod.DELETE,
"/pet/{petId}".replace("{"+"petId"+"}", "$petId"), "/pet/{petId}".replace("{"+"petId"+"}", "$petId"),
@ -89,7 +99,7 @@ class PetApi(basePath: kotlin.String = "http://petstore.swagger.io/v2") : ApiCli
fun findPetsByStatus(status: kotlin.Array<kotlin.String>) : kotlin.Array<Pet> { fun findPetsByStatus(status: kotlin.Array<kotlin.String>) : kotlin.Array<Pet> {
val localVariableBody: kotlin.Any? = null val localVariableBody: kotlin.Any? = null
val localVariableQuery: MultiValueMap = mapOf("status" to toMultiValue(status.toList(), "csv")) val localVariableQuery: MultiValueMap = mapOf("status" to toMultiValue(status.toList(), "csv"))
val localVariableHeaders: kotlin.collections.Map<kotlin.String,kotlin.String> = mapOf() val localVariableHeaders: MutableMap<String, String> = mutableMapOf()
val localVariableConfig = RequestConfig( val localVariableConfig = RequestConfig(
RequestMethod.GET, RequestMethod.GET,
"/pet/findByStatus", "/pet/findByStatus",
@ -120,7 +130,7 @@ class PetApi(basePath: kotlin.String = "http://petstore.swagger.io/v2") : ApiCli
fun findPetsByTags(tags: kotlin.Array<kotlin.String>) : kotlin.Array<Pet> { fun findPetsByTags(tags: kotlin.Array<kotlin.String>) : kotlin.Array<Pet> {
val localVariableBody: kotlin.Any? = null val localVariableBody: kotlin.Any? = null
val localVariableQuery: MultiValueMap = mapOf("tags" to toMultiValue(tags.toList(), "csv")) val localVariableQuery: MultiValueMap = mapOf("tags" to toMultiValue(tags.toList(), "csv"))
val localVariableHeaders: kotlin.collections.Map<kotlin.String,kotlin.String> = mapOf() val localVariableHeaders: MutableMap<String, String> = mutableMapOf()
val localVariableConfig = RequestConfig( val localVariableConfig = RequestConfig(
RequestMethod.GET, RequestMethod.GET,
"/pet/findByTags", "/pet/findByTags",
@ -151,7 +161,7 @@ class PetApi(basePath: kotlin.String = "http://petstore.swagger.io/v2") : ApiCli
fun getPetById(petId: kotlin.Long) : Pet { fun getPetById(petId: kotlin.Long) : Pet {
val localVariableBody: kotlin.Any? = null val localVariableBody: kotlin.Any? = null
val localVariableQuery: MultiValueMap = mapOf() val localVariableQuery: MultiValueMap = mapOf()
val localVariableHeaders: kotlin.collections.Map<kotlin.String,kotlin.String> = mapOf() val localVariableHeaders: MutableMap<String, String> = mutableMapOf()
val localVariableConfig = RequestConfig( val localVariableConfig = RequestConfig(
RequestMethod.GET, RequestMethod.GET,
"/pet/{petId}".replace("{"+"petId"+"}", "$petId"), "/pet/{petId}".replace("{"+"petId"+"}", "$petId"),
@ -181,7 +191,7 @@ class PetApi(basePath: kotlin.String = "http://petstore.swagger.io/v2") : ApiCli
fun updatePet(body: Pet) : Unit { fun updatePet(body: Pet) : Unit {
val localVariableBody: kotlin.Any? = body val localVariableBody: kotlin.Any? = body
val localVariableQuery: MultiValueMap = mapOf() val localVariableQuery: MultiValueMap = mapOf()
val localVariableHeaders: kotlin.collections.Map<kotlin.String,kotlin.String> = mapOf() val localVariableHeaders: MutableMap<String, String> = mutableMapOf()
val localVariableConfig = RequestConfig( val localVariableConfig = RequestConfig(
RequestMethod.PUT, RequestMethod.PUT,
"/pet", "/pet",
@ -213,7 +223,7 @@ class PetApi(basePath: kotlin.String = "http://petstore.swagger.io/v2") : ApiCli
fun updatePetWithForm(petId: kotlin.Long, name: kotlin.String?, status: kotlin.String?) : Unit { fun updatePetWithForm(petId: kotlin.Long, name: kotlin.String?, status: kotlin.String?) : Unit {
val localVariableBody: kotlin.Any? = mapOf("name" to "$name", "status" to "$status") val localVariableBody: kotlin.Any? = mapOf("name" to "$name", "status" to "$status")
val localVariableQuery: MultiValueMap = mapOf() val localVariableQuery: MultiValueMap = mapOf()
val localVariableHeaders: kotlin.collections.Map<kotlin.String,kotlin.String> = mapOf("Content-Type" to "multipart/form-data") val localVariableHeaders: MutableMap<String, String> = mutableMapOf("Content-Type" to "")
val localVariableConfig = RequestConfig( val localVariableConfig = RequestConfig(
RequestMethod.POST, RequestMethod.POST,
"/pet/{petId}".replace("{"+"petId"+"}", "$petId"), "/pet/{petId}".replace("{"+"petId"+"}", "$petId"),
@ -246,7 +256,7 @@ class PetApi(basePath: kotlin.String = "http://petstore.swagger.io/v2") : ApiCli
fun uploadFile(petId: kotlin.Long, additionalMetadata: kotlin.String?, file: java.io.File?) : ApiResponse { fun uploadFile(petId: kotlin.Long, additionalMetadata: kotlin.String?, file: java.io.File?) : ApiResponse {
val localVariableBody: kotlin.Any? = mapOf("additionalMetadata" to "$additionalMetadata", "file" to "$file") val localVariableBody: kotlin.Any? = mapOf("additionalMetadata" to "$additionalMetadata", "file" to "$file")
val localVariableQuery: MultiValueMap = mapOf() val localVariableQuery: MultiValueMap = mapOf()
val localVariableHeaders: kotlin.collections.Map<kotlin.String,kotlin.String> = mapOf("Content-Type" to "multipart/form-data") val localVariableHeaders: MutableMap<String, String> = mutableMapOf("Content-Type" to "")
val localVariableConfig = RequestConfig( val localVariableConfig = RequestConfig(
RequestMethod.POST, RequestMethod.POST,
"/pet/{petId}/uploadImage".replace("{"+"petId"+"}", "$petId"), "/pet/{petId}/uploadImage".replace("{"+"petId"+"}", "$petId"),

View File

@ -13,7 +13,17 @@ package org.openapitools.client.apis
import org.openapitools.client.models.Order import org.openapitools.client.models.Order
import org.openapitools.client.infrastructure.* import org.openapitools.client.infrastructure.ApiClient
import org.openapitools.client.infrastructure.ClientException
import org.openapitools.client.infrastructure.ClientError
import org.openapitools.client.infrastructure.ServerException
import org.openapitools.client.infrastructure.ServerError
import org.openapitools.client.infrastructure.MultiValueMap
import org.openapitools.client.infrastructure.RequestConfig
import org.openapitools.client.infrastructure.RequestMethod
import org.openapitools.client.infrastructure.ResponseType
import org.openapitools.client.infrastructure.Success
import org.openapitools.client.infrastructure.toMultiValue
class StoreApi(basePath: kotlin.String = "http://petstore.swagger.io/v2") : ApiClient(basePath) { class StoreApi(basePath: kotlin.String = "http://petstore.swagger.io/v2") : ApiClient(basePath) {
@ -26,7 +36,7 @@ class StoreApi(basePath: kotlin.String = "http://petstore.swagger.io/v2") : ApiC
fun deleteOrder(orderId: kotlin.String) : Unit { fun deleteOrder(orderId: kotlin.String) : Unit {
val localVariableBody: kotlin.Any? = null val localVariableBody: kotlin.Any? = null
val localVariableQuery: MultiValueMap = mapOf() val localVariableQuery: MultiValueMap = mapOf()
val localVariableHeaders: kotlin.collections.Map<kotlin.String,kotlin.String> = mapOf() val localVariableHeaders: MutableMap<String, String> = mutableMapOf()
val localVariableConfig = RequestConfig( val localVariableConfig = RequestConfig(
RequestMethod.DELETE, RequestMethod.DELETE,
"/store/order/{orderId}".replace("{"+"orderId"+"}", "$orderId"), "/store/order/{orderId}".replace("{"+"orderId"+"}", "$orderId"),
@ -56,7 +66,7 @@ class StoreApi(basePath: kotlin.String = "http://petstore.swagger.io/v2") : ApiC
fun getInventory() : kotlin.collections.Map<kotlin.String, kotlin.Int> { fun getInventory() : kotlin.collections.Map<kotlin.String, kotlin.Int> {
val localVariableBody: kotlin.Any? = null val localVariableBody: kotlin.Any? = null
val localVariableQuery: MultiValueMap = mapOf() val localVariableQuery: MultiValueMap = mapOf()
val localVariableHeaders: kotlin.collections.Map<kotlin.String,kotlin.String> = mapOf() val localVariableHeaders: MutableMap<String, String> = mutableMapOf()
val localVariableConfig = RequestConfig( val localVariableConfig = RequestConfig(
RequestMethod.GET, RequestMethod.GET,
"/store/inventory", "/store/inventory",
@ -87,7 +97,7 @@ class StoreApi(basePath: kotlin.String = "http://petstore.swagger.io/v2") : ApiC
fun getOrderById(orderId: kotlin.Long) : Order { fun getOrderById(orderId: kotlin.Long) : Order {
val localVariableBody: kotlin.Any? = null val localVariableBody: kotlin.Any? = null
val localVariableQuery: MultiValueMap = mapOf() val localVariableQuery: MultiValueMap = mapOf()
val localVariableHeaders: kotlin.collections.Map<kotlin.String,kotlin.String> = mapOf() val localVariableHeaders: MutableMap<String, String> = mutableMapOf()
val localVariableConfig = RequestConfig( val localVariableConfig = RequestConfig(
RequestMethod.GET, RequestMethod.GET,
"/store/order/{orderId}".replace("{"+"orderId"+"}", "$orderId"), "/store/order/{orderId}".replace("{"+"orderId"+"}", "$orderId"),
@ -118,7 +128,7 @@ class StoreApi(basePath: kotlin.String = "http://petstore.swagger.io/v2") : ApiC
fun placeOrder(body: Order) : Order { fun placeOrder(body: Order) : Order {
val localVariableBody: kotlin.Any? = body val localVariableBody: kotlin.Any? = body
val localVariableQuery: MultiValueMap = mapOf() val localVariableQuery: MultiValueMap = mapOf()
val localVariableHeaders: kotlin.collections.Map<kotlin.String,kotlin.String> = mapOf() val localVariableHeaders: MutableMap<String, String> = mutableMapOf()
val localVariableConfig = RequestConfig( val localVariableConfig = RequestConfig(
RequestMethod.POST, RequestMethod.POST,
"/store/order", "/store/order",

View File

@ -13,7 +13,17 @@ package org.openapitools.client.apis
import org.openapitools.client.models.User import org.openapitools.client.models.User
import org.openapitools.client.infrastructure.* import org.openapitools.client.infrastructure.ApiClient
import org.openapitools.client.infrastructure.ClientException
import org.openapitools.client.infrastructure.ClientError
import org.openapitools.client.infrastructure.ServerException
import org.openapitools.client.infrastructure.ServerError
import org.openapitools.client.infrastructure.MultiValueMap
import org.openapitools.client.infrastructure.RequestConfig
import org.openapitools.client.infrastructure.RequestMethod
import org.openapitools.client.infrastructure.ResponseType
import org.openapitools.client.infrastructure.Success
import org.openapitools.client.infrastructure.toMultiValue
class UserApi(basePath: kotlin.String = "http://petstore.swagger.io/v2") : ApiClient(basePath) { class UserApi(basePath: kotlin.String = "http://petstore.swagger.io/v2") : ApiClient(basePath) {
@ -26,7 +36,7 @@ class UserApi(basePath: kotlin.String = "http://petstore.swagger.io/v2") : ApiCl
fun createUser(body: User) : Unit { fun createUser(body: User) : Unit {
val localVariableBody: kotlin.Any? = body val localVariableBody: kotlin.Any? = body
val localVariableQuery: MultiValueMap = mapOf() val localVariableQuery: MultiValueMap = mapOf()
val localVariableHeaders: kotlin.collections.Map<kotlin.String,kotlin.String> = mapOf() val localVariableHeaders: MutableMap<String, String> = mutableMapOf()
val localVariableConfig = RequestConfig( val localVariableConfig = RequestConfig(
RequestMethod.POST, RequestMethod.POST,
"/user", "/user",
@ -56,7 +66,7 @@ class UserApi(basePath: kotlin.String = "http://petstore.swagger.io/v2") : ApiCl
fun createUsersWithArrayInput(body: kotlin.Array<User>) : Unit { fun createUsersWithArrayInput(body: kotlin.Array<User>) : Unit {
val localVariableBody: kotlin.Any? = body val localVariableBody: kotlin.Any? = body
val localVariableQuery: MultiValueMap = mapOf() val localVariableQuery: MultiValueMap = mapOf()
val localVariableHeaders: kotlin.collections.Map<kotlin.String,kotlin.String> = mapOf() val localVariableHeaders: MutableMap<String, String> = mutableMapOf()
val localVariableConfig = RequestConfig( val localVariableConfig = RequestConfig(
RequestMethod.POST, RequestMethod.POST,
"/user/createWithArray", "/user/createWithArray",
@ -86,7 +96,7 @@ class UserApi(basePath: kotlin.String = "http://petstore.swagger.io/v2") : ApiCl
fun createUsersWithListInput(body: kotlin.Array<User>) : Unit { fun createUsersWithListInput(body: kotlin.Array<User>) : Unit {
val localVariableBody: kotlin.Any? = body val localVariableBody: kotlin.Any? = body
val localVariableQuery: MultiValueMap = mapOf() val localVariableQuery: MultiValueMap = mapOf()
val localVariableHeaders: kotlin.collections.Map<kotlin.String,kotlin.String> = mapOf() val localVariableHeaders: MutableMap<String, String> = mutableMapOf()
val localVariableConfig = RequestConfig( val localVariableConfig = RequestConfig(
RequestMethod.POST, RequestMethod.POST,
"/user/createWithList", "/user/createWithList",
@ -116,7 +126,7 @@ class UserApi(basePath: kotlin.String = "http://petstore.swagger.io/v2") : ApiCl
fun deleteUser(username: kotlin.String) : Unit { fun deleteUser(username: kotlin.String) : Unit {
val localVariableBody: kotlin.Any? = null val localVariableBody: kotlin.Any? = null
val localVariableQuery: MultiValueMap = mapOf() val localVariableQuery: MultiValueMap = mapOf()
val localVariableHeaders: kotlin.collections.Map<kotlin.String,kotlin.String> = mapOf() val localVariableHeaders: MutableMap<String, String> = mutableMapOf()
val localVariableConfig = RequestConfig( val localVariableConfig = RequestConfig(
RequestMethod.DELETE, RequestMethod.DELETE,
"/user/{username}".replace("{"+"username"+"}", "$username"), "/user/{username}".replace("{"+"username"+"}", "$username"),
@ -147,7 +157,7 @@ class UserApi(basePath: kotlin.String = "http://petstore.swagger.io/v2") : ApiCl
fun getUserByName(username: kotlin.String) : User { fun getUserByName(username: kotlin.String) : User {
val localVariableBody: kotlin.Any? = null val localVariableBody: kotlin.Any? = null
val localVariableQuery: MultiValueMap = mapOf() val localVariableQuery: MultiValueMap = mapOf()
val localVariableHeaders: kotlin.collections.Map<kotlin.String,kotlin.String> = mapOf() val localVariableHeaders: MutableMap<String, String> = mutableMapOf()
val localVariableConfig = RequestConfig( val localVariableConfig = RequestConfig(
RequestMethod.GET, RequestMethod.GET,
"/user/{username}".replace("{"+"username"+"}", "$username"), "/user/{username}".replace("{"+"username"+"}", "$username"),
@ -179,7 +189,7 @@ class UserApi(basePath: kotlin.String = "http://petstore.swagger.io/v2") : ApiCl
fun loginUser(username: kotlin.String, password: kotlin.String) : kotlin.String { fun loginUser(username: kotlin.String, password: kotlin.String) : kotlin.String {
val localVariableBody: kotlin.Any? = null val localVariableBody: kotlin.Any? = null
val localVariableQuery: MultiValueMap = mapOf("username" to listOf("$username"), "password" to listOf("$password")) val localVariableQuery: MultiValueMap = mapOf("username" to listOf("$username"), "password" to listOf("$password"))
val localVariableHeaders: kotlin.collections.Map<kotlin.String,kotlin.String> = mapOf() val localVariableHeaders: MutableMap<String, String> = mutableMapOf()
val localVariableConfig = RequestConfig( val localVariableConfig = RequestConfig(
RequestMethod.GET, RequestMethod.GET,
"/user/login", "/user/login",
@ -208,7 +218,7 @@ class UserApi(basePath: kotlin.String = "http://petstore.swagger.io/v2") : ApiCl
fun logoutUser() : Unit { fun logoutUser() : Unit {
val localVariableBody: kotlin.Any? = null val localVariableBody: kotlin.Any? = null
val localVariableQuery: MultiValueMap = mapOf() val localVariableQuery: MultiValueMap = mapOf()
val localVariableHeaders: kotlin.collections.Map<kotlin.String,kotlin.String> = mapOf() val localVariableHeaders: MutableMap<String, String> = mutableMapOf()
val localVariableConfig = RequestConfig( val localVariableConfig = RequestConfig(
RequestMethod.GET, RequestMethod.GET,
"/user/logout", "/user/logout",
@ -239,7 +249,7 @@ class UserApi(basePath: kotlin.String = "http://petstore.swagger.io/v2") : ApiCl
fun updateUser(username: kotlin.String, body: User) : Unit { fun updateUser(username: kotlin.String, body: User) : Unit {
val localVariableBody: kotlin.Any? = body val localVariableBody: kotlin.Any? = body
val localVariableQuery: MultiValueMap = mapOf() val localVariableQuery: MultiValueMap = mapOf()
val localVariableHeaders: kotlin.collections.Map<kotlin.String,kotlin.String> = mapOf() val localVariableHeaders: MutableMap<String, String> = mutableMapOf()
val localVariableConfig = RequestConfig( val localVariableConfig = RequestConfig(
RequestMethod.PUT, RequestMethod.PUT,
"/user/{username}".replace("{"+"username"+"}", "$username"), "/user/{username}".replace("{"+"username"+"}", "$username"),

View File

@ -3,9 +3,15 @@ package org.openapitools.client.infrastructure
import com.squareup.moshi.FromJson import com.squareup.moshi.FromJson
import com.squareup.moshi.Moshi import com.squareup.moshi.Moshi
import com.squareup.moshi.ToJson import com.squareup.moshi.ToJson
import okhttp3.* import okhttp3.OkHttpClient
import okhttp3.RequestBody
import okhttp3.MediaType
import okhttp3.FormBody
import okhttp3.HttpUrl
import okhttp3.ResponseBody
import okhttp3.Request
import java.io.File import java.io.File
import java.util.* import java.util.UUID
open class ApiClient(val baseUrl: String) { open class ApiClient(val baseUrl: String) {
companion object { companion object {
@ -13,6 +19,7 @@ open class ApiClient(val baseUrl: String) {
protected const val Accept = "Accept" protected const val Accept = "Accept"
protected const val JsonMediaType = "application/json" protected const val JsonMediaType = "application/json"
protected const val FormDataMediaType = "multipart/form-data" protected const val FormDataMediaType = "multipart/form-data"
protected const val FormUrlEncMediaType = "application/x-www-form-urlencoded"
protected const val XmlMediaType = "application/xml" protected const val XmlMediaType = "application/xml"
@JvmStatic @JvmStatic
@ -22,38 +29,38 @@ open class ApiClient(val baseUrl: String) {
@JvmStatic @JvmStatic
val builder: OkHttpClient.Builder = OkHttpClient.Builder() val builder: OkHttpClient.Builder = OkHttpClient.Builder()
@JvmStatic
var defaultHeaders: Map<String, String> by ApplicationDelegates.setOnce(mapOf(ContentType to JsonMediaType, Accept to JsonMediaType))
@JvmStatic
val jsonHeaders: Map<String, String> = mapOf(ContentType to JsonMediaType, Accept to JsonMediaType)
} }
protected inline fun <reified T> requestBody(content: T, mediaType: String = JsonMediaType): RequestBody = protected inline fun <reified T> requestBody(content: T, mediaType: String = JsonMediaType): RequestBody =
when { when {
content is File -> RequestBody.create( content is File -> RequestBody.create(
MediaType.parse(mediaType), content MediaType.parse(mediaType), content
) )
mediaType == FormDataMediaType -> { mediaType == FormDataMediaType || mediaType == FormUrlEncMediaType -> {
var builder = FormBody.Builder() var builder = FormBody.Builder()
// content's type *must* be Map<String, Any> // content's type *must* be Map<String, Any>
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
(content as Map<String,String>).forEach { key, value -> (content as Map<String,String>).forEach { key, value ->
builder = builder.add(key, value) builder = builder.add(key, value)
} }
builder.build() builder.build()
} }
mediaType == JsonMediaType -> RequestBody.create( mediaType == JsonMediaType -> RequestBody.create(
MediaType.parse(mediaType), Serializer.moshi.adapter(T::class.java).toJson(content) MediaType.parse(mediaType), Serializer.moshi.adapter(T::class.java).toJson(content)
) )
mediaType == XmlMediaType -> TODO("xml not currently supported.") mediaType == XmlMediaType -> TODO("xml not currently supported.")
// TODO: this should be extended with other serializers // TODO: this should be extended with other serializers
else -> TODO("requestBody currently only supports JSON body and File body.") else -> TODO("requestBody currently only supports JSON body and File body.")
} }
protected inline fun <reified T: Any?> responseBody(body: ResponseBody?, mediaType: String = JsonMediaType): T? { protected inline fun <reified T: Any?> responseBody(body: ResponseBody?, mediaType: String? = JsonMediaType): T? {
if(body == null) return null if(body == null) {
return null
}
val bodyContent = body.string()
if (bodyContent.length == 0) {
return null
}
return when(mediaType) { return when(mediaType) {
JsonMediaType -> Moshi.Builder().add(object { JsonMediaType -> Moshi.Builder().add(object {
@ToJson @ToJson
@ -62,8 +69,8 @@ open class ApiClient(val baseUrl: String) {
fun fromJson(s: String) = UUID.fromString(s) fun fromJson(s: String) = UUID.fromString(s)
}) })
.add(ByteArrayAdapter()) .add(ByteArrayAdapter())
.build().adapter(T::class.java).fromJson(body.source()) .build().adapter(T::class.java).fromJson(bodyContent)
else -> TODO() else -> TODO("responseBody currently only supports JSON body.")
} }
} }
@ -80,7 +87,15 @@ open class ApiClient(val baseUrl: String) {
} }
val url = urlBuilder.build() val url = urlBuilder.build()
val headers = requestConfig.headers + defaultHeaders
// take content-type/accept from spec or set to default (application/json) if not defined
if (requestConfig.headers[ContentType].isNullOrEmpty()) {
requestConfig.headers.put(ContentType, JsonMediaType)
}
if (requestConfig.headers[Accept].isNullOrEmpty()) {
requestConfig.headers.put(Accept, JsonMediaType)
}
val headers = requestConfig.headers
if(headers[ContentType] ?: "" == "") { if(headers[ContentType] ?: "" == "") {
throw kotlin.IllegalStateException("Missing Content-Type header. This is required.") throw kotlin.IllegalStateException("Missing Content-Type header. This is required.")
@ -90,9 +105,8 @@ open class ApiClient(val baseUrl: String) {
throw kotlin.IllegalStateException("Missing Accept header. This is required.") throw kotlin.IllegalStateException("Missing Accept header. This is required.")
} }
// TODO: support multiple contentType,accept options here. // TODO: support multiple contentType options here.
val contentType = (headers[ContentType] as String).substringBefore(";").toLowerCase() val contentType = (headers[ContentType] as String).substringBefore(";").toLowerCase()
val accept = (headers[Accept] as String).substringBefore(";").toLowerCase()
var request : Request.Builder = when (requestConfig.method) { var request : Request.Builder = when (requestConfig.method) {
RequestMethod.DELETE -> Request.Builder().url(url).delete() RequestMethod.DELETE -> Request.Builder().url(url).delete()
@ -108,6 +122,7 @@ open class ApiClient(val baseUrl: String) {
val realRequest = request.build() val realRequest = request.build()
val response = client.newCall(realRequest).execute() val response = client.newCall(realRequest).execute()
val accept = response.header(ContentType)?.substringBefore(";")?.toLowerCase()
// TODO: handle specific mapping types. e.g. Map<int, Class<?>> // TODO: handle specific mapping types. e.g. Map<int, Class<?>>
when { when {

View File

@ -11,6 +11,6 @@ package org.openapitools.client.infrastructure
data class RequestConfig( data class RequestConfig(
val method: RequestMethod, val method: RequestMethod,
val path: String, val path: String,
val headers: Map<String, String> = mapOf(), val headers: MutableMap<String, String> = mutableMapOf(),
val query: Map<String, List<String>> = mapOf() val query: Map<String, List<String>> = mapOf()
) )

View File

@ -2,7 +2,7 @@
## Requires ## Requires
* Kotlin 1.3.20 * Kotlin 1.3.31
* Gradle 4.9 * Gradle 4.9
## Build ## Build

View File

@ -7,7 +7,7 @@ wrapper {
} }
buildscript { buildscript {
ext.kotlin_version = '1.3.20' ext.kotlin_version = '1.3.31'
repositories { repositories {
mavenCentral() mavenCentral()
@ -32,7 +32,7 @@ dependencies {
compile "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version" compile "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
compile "com.squareup.moshi:moshi-kotlin:1.5.0" compile "com.squareup.moshi:moshi-kotlin:1.5.0"
compile "com.squareup.moshi:moshi-adapters:1.5.0" compile "com.squareup.moshi:moshi-adapters:1.5.0"
compile "com.squareup.okhttp3:okhttp:3.8.0" compile "com.squareup.okhttp3:okhttp:3.14.0"
compile "org.threeten:threetenbp:1.3.6" compile "org.threeten:threetenbp:1.3.8"
testImplementation "io.kotlintest:kotlintest-runner-junit5:3.1.0" testImplementation "io.kotlintest:kotlintest-runner-junit5:3.1.0"
} }

View File

@ -14,7 +14,17 @@ package org.openapitools.client.apis
import org.openapitools.client.models.ApiResponse import org.openapitools.client.models.ApiResponse
import org.openapitools.client.models.Pet import org.openapitools.client.models.Pet
import org.openapitools.client.infrastructure.* import org.openapitools.client.infrastructure.ApiClient
import org.openapitools.client.infrastructure.ClientException
import org.openapitools.client.infrastructure.ClientError
import org.openapitools.client.infrastructure.ServerException
import org.openapitools.client.infrastructure.ServerError
import org.openapitools.client.infrastructure.MultiValueMap
import org.openapitools.client.infrastructure.RequestConfig
import org.openapitools.client.infrastructure.RequestMethod
import org.openapitools.client.infrastructure.ResponseType
import org.openapitools.client.infrastructure.Success
import org.openapitools.client.infrastructure.toMultiValue
import org.threeten.bp.LocalDateTime import org.threeten.bp.LocalDateTime
class PetApi(basePath: kotlin.String = "http://petstore.swagger.io/v2") : ApiClient(basePath) { class PetApi(basePath: kotlin.String = "http://petstore.swagger.io/v2") : ApiClient(basePath) {
@ -28,7 +38,7 @@ class PetApi(basePath: kotlin.String = "http://petstore.swagger.io/v2") : ApiCli
fun addPet(body: Pet) : Unit { fun addPet(body: Pet) : Unit {
val localVariableBody: kotlin.Any? = body val localVariableBody: kotlin.Any? = body
val localVariableQuery: MultiValueMap = mapOf() val localVariableQuery: MultiValueMap = mapOf()
val localVariableHeaders: kotlin.collections.Map<kotlin.String,kotlin.String> = mapOf() val localVariableHeaders: MutableMap<String, String> = mutableMapOf()
val localVariableConfig = RequestConfig( val localVariableConfig = RequestConfig(
RequestMethod.POST, RequestMethod.POST,
"/pet", "/pet",
@ -59,7 +69,7 @@ class PetApi(basePath: kotlin.String = "http://petstore.swagger.io/v2") : ApiCli
fun deletePet(petId: kotlin.Long, apiKey: kotlin.String?) : Unit { fun deletePet(petId: kotlin.Long, apiKey: kotlin.String?) : Unit {
val localVariableBody: kotlin.Any? = null val localVariableBody: kotlin.Any? = null
val localVariableQuery: MultiValueMap = mapOf() val localVariableQuery: MultiValueMap = mapOf()
val localVariableHeaders: kotlin.collections.Map<kotlin.String,kotlin.String> = mapOf("api_key" to apiKey.toString()) val localVariableHeaders: MutableMap<String, String> = mutableMapOf("api_key" to apiKey.toString())
val localVariableConfig = RequestConfig( val localVariableConfig = RequestConfig(
RequestMethod.DELETE, RequestMethod.DELETE,
"/pet/{petId}".replace("{"+"petId"+"}", "$petId"), "/pet/{petId}".replace("{"+"petId"+"}", "$petId"),
@ -90,7 +100,7 @@ class PetApi(basePath: kotlin.String = "http://petstore.swagger.io/v2") : ApiCli
fun findPetsByStatus(status: kotlin.Array<kotlin.String>) : kotlin.Array<Pet> { fun findPetsByStatus(status: kotlin.Array<kotlin.String>) : kotlin.Array<Pet> {
val localVariableBody: kotlin.Any? = null val localVariableBody: kotlin.Any? = null
val localVariableQuery: MultiValueMap = mapOf("status" to toMultiValue(status.toList(), "csv")) val localVariableQuery: MultiValueMap = mapOf("status" to toMultiValue(status.toList(), "csv"))
val localVariableHeaders: kotlin.collections.Map<kotlin.String,kotlin.String> = mapOf() val localVariableHeaders: MutableMap<String, String> = mutableMapOf()
val localVariableConfig = RequestConfig( val localVariableConfig = RequestConfig(
RequestMethod.GET, RequestMethod.GET,
"/pet/findByStatus", "/pet/findByStatus",
@ -121,7 +131,7 @@ class PetApi(basePath: kotlin.String = "http://petstore.swagger.io/v2") : ApiCli
fun findPetsByTags(tags: kotlin.Array<kotlin.String>) : kotlin.Array<Pet> { fun findPetsByTags(tags: kotlin.Array<kotlin.String>) : kotlin.Array<Pet> {
val localVariableBody: kotlin.Any? = null val localVariableBody: kotlin.Any? = null
val localVariableQuery: MultiValueMap = mapOf("tags" to toMultiValue(tags.toList(), "csv")) val localVariableQuery: MultiValueMap = mapOf("tags" to toMultiValue(tags.toList(), "csv"))
val localVariableHeaders: kotlin.collections.Map<kotlin.String,kotlin.String> = mapOf() val localVariableHeaders: MutableMap<String, String> = mutableMapOf()
val localVariableConfig = RequestConfig( val localVariableConfig = RequestConfig(
RequestMethod.GET, RequestMethod.GET,
"/pet/findByTags", "/pet/findByTags",
@ -152,7 +162,7 @@ class PetApi(basePath: kotlin.String = "http://petstore.swagger.io/v2") : ApiCli
fun getPetById(petId: kotlin.Long) : Pet { fun getPetById(petId: kotlin.Long) : Pet {
val localVariableBody: kotlin.Any? = null val localVariableBody: kotlin.Any? = null
val localVariableQuery: MultiValueMap = mapOf() val localVariableQuery: MultiValueMap = mapOf()
val localVariableHeaders: kotlin.collections.Map<kotlin.String,kotlin.String> = mapOf() val localVariableHeaders: MutableMap<String, String> = mutableMapOf()
val localVariableConfig = RequestConfig( val localVariableConfig = RequestConfig(
RequestMethod.GET, RequestMethod.GET,
"/pet/{petId}".replace("{"+"petId"+"}", "$petId"), "/pet/{petId}".replace("{"+"petId"+"}", "$petId"),
@ -182,7 +192,7 @@ class PetApi(basePath: kotlin.String = "http://petstore.swagger.io/v2") : ApiCli
fun updatePet(body: Pet) : Unit { fun updatePet(body: Pet) : Unit {
val localVariableBody: kotlin.Any? = body val localVariableBody: kotlin.Any? = body
val localVariableQuery: MultiValueMap = mapOf() val localVariableQuery: MultiValueMap = mapOf()
val localVariableHeaders: kotlin.collections.Map<kotlin.String,kotlin.String> = mapOf() val localVariableHeaders: MutableMap<String, String> = mutableMapOf()
val localVariableConfig = RequestConfig( val localVariableConfig = RequestConfig(
RequestMethod.PUT, RequestMethod.PUT,
"/pet", "/pet",
@ -214,7 +224,7 @@ class PetApi(basePath: kotlin.String = "http://petstore.swagger.io/v2") : ApiCli
fun updatePetWithForm(petId: kotlin.Long, name: kotlin.String?, status: kotlin.String?) : Unit { fun updatePetWithForm(petId: kotlin.Long, name: kotlin.String?, status: kotlin.String?) : Unit {
val localVariableBody: kotlin.Any? = mapOf("name" to "$name", "status" to "$status") val localVariableBody: kotlin.Any? = mapOf("name" to "$name", "status" to "$status")
val localVariableQuery: MultiValueMap = mapOf() val localVariableQuery: MultiValueMap = mapOf()
val localVariableHeaders: kotlin.collections.Map<kotlin.String,kotlin.String> = mapOf("Content-Type" to "multipart/form-data") val localVariableHeaders: MutableMap<String, String> = mutableMapOf("Content-Type" to "")
val localVariableConfig = RequestConfig( val localVariableConfig = RequestConfig(
RequestMethod.POST, RequestMethod.POST,
"/pet/{petId}".replace("{"+"petId"+"}", "$petId"), "/pet/{petId}".replace("{"+"petId"+"}", "$petId"),
@ -247,7 +257,7 @@ class PetApi(basePath: kotlin.String = "http://petstore.swagger.io/v2") : ApiCli
fun uploadFile(petId: kotlin.Long, additionalMetadata: kotlin.String?, file: java.io.File?) : ApiResponse { fun uploadFile(petId: kotlin.Long, additionalMetadata: kotlin.String?, file: java.io.File?) : ApiResponse {
val localVariableBody: kotlin.Any? = mapOf("additionalMetadata" to "$additionalMetadata", "file" to "$file") val localVariableBody: kotlin.Any? = mapOf("additionalMetadata" to "$additionalMetadata", "file" to "$file")
val localVariableQuery: MultiValueMap = mapOf() val localVariableQuery: MultiValueMap = mapOf()
val localVariableHeaders: kotlin.collections.Map<kotlin.String,kotlin.String> = mapOf("Content-Type" to "multipart/form-data") val localVariableHeaders: MutableMap<String, String> = mutableMapOf("Content-Type" to "")
val localVariableConfig = RequestConfig( val localVariableConfig = RequestConfig(
RequestMethod.POST, RequestMethod.POST,
"/pet/{petId}/uploadImage".replace("{"+"petId"+"}", "$petId"), "/pet/{petId}/uploadImage".replace("{"+"petId"+"}", "$petId"),

View File

@ -13,7 +13,17 @@ package org.openapitools.client.apis
import org.openapitools.client.models.Order import org.openapitools.client.models.Order
import org.openapitools.client.infrastructure.* import org.openapitools.client.infrastructure.ApiClient
import org.openapitools.client.infrastructure.ClientException
import org.openapitools.client.infrastructure.ClientError
import org.openapitools.client.infrastructure.ServerException
import org.openapitools.client.infrastructure.ServerError
import org.openapitools.client.infrastructure.MultiValueMap
import org.openapitools.client.infrastructure.RequestConfig
import org.openapitools.client.infrastructure.RequestMethod
import org.openapitools.client.infrastructure.ResponseType
import org.openapitools.client.infrastructure.Success
import org.openapitools.client.infrastructure.toMultiValue
import org.threeten.bp.LocalDateTime import org.threeten.bp.LocalDateTime
class StoreApi(basePath: kotlin.String = "http://petstore.swagger.io/v2") : ApiClient(basePath) { class StoreApi(basePath: kotlin.String = "http://petstore.swagger.io/v2") : ApiClient(basePath) {
@ -27,7 +37,7 @@ class StoreApi(basePath: kotlin.String = "http://petstore.swagger.io/v2") : ApiC
fun deleteOrder(orderId: kotlin.String) : Unit { fun deleteOrder(orderId: kotlin.String) : Unit {
val localVariableBody: kotlin.Any? = null val localVariableBody: kotlin.Any? = null
val localVariableQuery: MultiValueMap = mapOf() val localVariableQuery: MultiValueMap = mapOf()
val localVariableHeaders: kotlin.collections.Map<kotlin.String,kotlin.String> = mapOf() val localVariableHeaders: MutableMap<String, String> = mutableMapOf()
val localVariableConfig = RequestConfig( val localVariableConfig = RequestConfig(
RequestMethod.DELETE, RequestMethod.DELETE,
"/store/order/{orderId}".replace("{"+"orderId"+"}", "$orderId"), "/store/order/{orderId}".replace("{"+"orderId"+"}", "$orderId"),
@ -57,7 +67,7 @@ class StoreApi(basePath: kotlin.String = "http://petstore.swagger.io/v2") : ApiC
fun getInventory() : kotlin.collections.Map<kotlin.String, kotlin.Int> { fun getInventory() : kotlin.collections.Map<kotlin.String, kotlin.Int> {
val localVariableBody: kotlin.Any? = null val localVariableBody: kotlin.Any? = null
val localVariableQuery: MultiValueMap = mapOf() val localVariableQuery: MultiValueMap = mapOf()
val localVariableHeaders: kotlin.collections.Map<kotlin.String,kotlin.String> = mapOf() val localVariableHeaders: MutableMap<String, String> = mutableMapOf()
val localVariableConfig = RequestConfig( val localVariableConfig = RequestConfig(
RequestMethod.GET, RequestMethod.GET,
"/store/inventory", "/store/inventory",
@ -88,7 +98,7 @@ class StoreApi(basePath: kotlin.String = "http://petstore.swagger.io/v2") : ApiC
fun getOrderById(orderId: kotlin.Long) : Order { fun getOrderById(orderId: kotlin.Long) : Order {
val localVariableBody: kotlin.Any? = null val localVariableBody: kotlin.Any? = null
val localVariableQuery: MultiValueMap = mapOf() val localVariableQuery: MultiValueMap = mapOf()
val localVariableHeaders: kotlin.collections.Map<kotlin.String,kotlin.String> = mapOf() val localVariableHeaders: MutableMap<String, String> = mutableMapOf()
val localVariableConfig = RequestConfig( val localVariableConfig = RequestConfig(
RequestMethod.GET, RequestMethod.GET,
"/store/order/{orderId}".replace("{"+"orderId"+"}", "$orderId"), "/store/order/{orderId}".replace("{"+"orderId"+"}", "$orderId"),
@ -119,7 +129,7 @@ class StoreApi(basePath: kotlin.String = "http://petstore.swagger.io/v2") : ApiC
fun placeOrder(body: Order) : Order { fun placeOrder(body: Order) : Order {
val localVariableBody: kotlin.Any? = body val localVariableBody: kotlin.Any? = body
val localVariableQuery: MultiValueMap = mapOf() val localVariableQuery: MultiValueMap = mapOf()
val localVariableHeaders: kotlin.collections.Map<kotlin.String,kotlin.String> = mapOf() val localVariableHeaders: MutableMap<String, String> = mutableMapOf()
val localVariableConfig = RequestConfig( val localVariableConfig = RequestConfig(
RequestMethod.POST, RequestMethod.POST,
"/store/order", "/store/order",

View File

@ -13,7 +13,17 @@ package org.openapitools.client.apis
import org.openapitools.client.models.User import org.openapitools.client.models.User
import org.openapitools.client.infrastructure.* import org.openapitools.client.infrastructure.ApiClient
import org.openapitools.client.infrastructure.ClientException
import org.openapitools.client.infrastructure.ClientError
import org.openapitools.client.infrastructure.ServerException
import org.openapitools.client.infrastructure.ServerError
import org.openapitools.client.infrastructure.MultiValueMap
import org.openapitools.client.infrastructure.RequestConfig
import org.openapitools.client.infrastructure.RequestMethod
import org.openapitools.client.infrastructure.ResponseType
import org.openapitools.client.infrastructure.Success
import org.openapitools.client.infrastructure.toMultiValue
import org.threeten.bp.LocalDateTime import org.threeten.bp.LocalDateTime
class UserApi(basePath: kotlin.String = "http://petstore.swagger.io/v2") : ApiClient(basePath) { class UserApi(basePath: kotlin.String = "http://petstore.swagger.io/v2") : ApiClient(basePath) {
@ -27,7 +37,7 @@ class UserApi(basePath: kotlin.String = "http://petstore.swagger.io/v2") : ApiCl
fun createUser(body: User) : Unit { fun createUser(body: User) : Unit {
val localVariableBody: kotlin.Any? = body val localVariableBody: kotlin.Any? = body
val localVariableQuery: MultiValueMap = mapOf() val localVariableQuery: MultiValueMap = mapOf()
val localVariableHeaders: kotlin.collections.Map<kotlin.String,kotlin.String> = mapOf() val localVariableHeaders: MutableMap<String, String> = mutableMapOf()
val localVariableConfig = RequestConfig( val localVariableConfig = RequestConfig(
RequestMethod.POST, RequestMethod.POST,
"/user", "/user",
@ -57,7 +67,7 @@ class UserApi(basePath: kotlin.String = "http://petstore.swagger.io/v2") : ApiCl
fun createUsersWithArrayInput(body: kotlin.Array<User>) : Unit { fun createUsersWithArrayInput(body: kotlin.Array<User>) : Unit {
val localVariableBody: kotlin.Any? = body val localVariableBody: kotlin.Any? = body
val localVariableQuery: MultiValueMap = mapOf() val localVariableQuery: MultiValueMap = mapOf()
val localVariableHeaders: kotlin.collections.Map<kotlin.String,kotlin.String> = mapOf() val localVariableHeaders: MutableMap<String, String> = mutableMapOf()
val localVariableConfig = RequestConfig( val localVariableConfig = RequestConfig(
RequestMethod.POST, RequestMethod.POST,
"/user/createWithArray", "/user/createWithArray",
@ -87,7 +97,7 @@ class UserApi(basePath: kotlin.String = "http://petstore.swagger.io/v2") : ApiCl
fun createUsersWithListInput(body: kotlin.Array<User>) : Unit { fun createUsersWithListInput(body: kotlin.Array<User>) : Unit {
val localVariableBody: kotlin.Any? = body val localVariableBody: kotlin.Any? = body
val localVariableQuery: MultiValueMap = mapOf() val localVariableQuery: MultiValueMap = mapOf()
val localVariableHeaders: kotlin.collections.Map<kotlin.String,kotlin.String> = mapOf() val localVariableHeaders: MutableMap<String, String> = mutableMapOf()
val localVariableConfig = RequestConfig( val localVariableConfig = RequestConfig(
RequestMethod.POST, RequestMethod.POST,
"/user/createWithList", "/user/createWithList",
@ -117,7 +127,7 @@ class UserApi(basePath: kotlin.String = "http://petstore.swagger.io/v2") : ApiCl
fun deleteUser(username: kotlin.String) : Unit { fun deleteUser(username: kotlin.String) : Unit {
val localVariableBody: kotlin.Any? = null val localVariableBody: kotlin.Any? = null
val localVariableQuery: MultiValueMap = mapOf() val localVariableQuery: MultiValueMap = mapOf()
val localVariableHeaders: kotlin.collections.Map<kotlin.String,kotlin.String> = mapOf() val localVariableHeaders: MutableMap<String, String> = mutableMapOf()
val localVariableConfig = RequestConfig( val localVariableConfig = RequestConfig(
RequestMethod.DELETE, RequestMethod.DELETE,
"/user/{username}".replace("{"+"username"+"}", "$username"), "/user/{username}".replace("{"+"username"+"}", "$username"),
@ -148,7 +158,7 @@ class UserApi(basePath: kotlin.String = "http://petstore.swagger.io/v2") : ApiCl
fun getUserByName(username: kotlin.String) : User { fun getUserByName(username: kotlin.String) : User {
val localVariableBody: kotlin.Any? = null val localVariableBody: kotlin.Any? = null
val localVariableQuery: MultiValueMap = mapOf() val localVariableQuery: MultiValueMap = mapOf()
val localVariableHeaders: kotlin.collections.Map<kotlin.String,kotlin.String> = mapOf() val localVariableHeaders: MutableMap<String, String> = mutableMapOf()
val localVariableConfig = RequestConfig( val localVariableConfig = RequestConfig(
RequestMethod.GET, RequestMethod.GET,
"/user/{username}".replace("{"+"username"+"}", "$username"), "/user/{username}".replace("{"+"username"+"}", "$username"),
@ -180,7 +190,7 @@ class UserApi(basePath: kotlin.String = "http://petstore.swagger.io/v2") : ApiCl
fun loginUser(username: kotlin.String, password: kotlin.String) : kotlin.String { fun loginUser(username: kotlin.String, password: kotlin.String) : kotlin.String {
val localVariableBody: kotlin.Any? = null val localVariableBody: kotlin.Any? = null
val localVariableQuery: MultiValueMap = mapOf("username" to listOf("$username"), "password" to listOf("$password")) val localVariableQuery: MultiValueMap = mapOf("username" to listOf("$username"), "password" to listOf("$password"))
val localVariableHeaders: kotlin.collections.Map<kotlin.String,kotlin.String> = mapOf() val localVariableHeaders: MutableMap<String, String> = mutableMapOf()
val localVariableConfig = RequestConfig( val localVariableConfig = RequestConfig(
RequestMethod.GET, RequestMethod.GET,
"/user/login", "/user/login",
@ -209,7 +219,7 @@ class UserApi(basePath: kotlin.String = "http://petstore.swagger.io/v2") : ApiCl
fun logoutUser() : Unit { fun logoutUser() : Unit {
val localVariableBody: kotlin.Any? = null val localVariableBody: kotlin.Any? = null
val localVariableQuery: MultiValueMap = mapOf() val localVariableQuery: MultiValueMap = mapOf()
val localVariableHeaders: kotlin.collections.Map<kotlin.String,kotlin.String> = mapOf() val localVariableHeaders: MutableMap<String, String> = mutableMapOf()
val localVariableConfig = RequestConfig( val localVariableConfig = RequestConfig(
RequestMethod.GET, RequestMethod.GET,
"/user/logout", "/user/logout",
@ -240,7 +250,7 @@ class UserApi(basePath: kotlin.String = "http://petstore.swagger.io/v2") : ApiCl
fun updateUser(username: kotlin.String, body: User) : Unit { fun updateUser(username: kotlin.String, body: User) : Unit {
val localVariableBody: kotlin.Any? = body val localVariableBody: kotlin.Any? = body
val localVariableQuery: MultiValueMap = mapOf() val localVariableQuery: MultiValueMap = mapOf()
val localVariableHeaders: kotlin.collections.Map<kotlin.String,kotlin.String> = mapOf() val localVariableHeaders: MutableMap<String, String> = mutableMapOf()
val localVariableConfig = RequestConfig( val localVariableConfig = RequestConfig(
RequestMethod.PUT, RequestMethod.PUT,
"/user/{username}".replace("{"+"username"+"}", "$username"), "/user/{username}".replace("{"+"username"+"}", "$username"),

View File

@ -3,9 +3,15 @@ package org.openapitools.client.infrastructure
import com.squareup.moshi.FromJson import com.squareup.moshi.FromJson
import com.squareup.moshi.Moshi import com.squareup.moshi.Moshi
import com.squareup.moshi.ToJson import com.squareup.moshi.ToJson
import okhttp3.* import okhttp3.OkHttpClient
import okhttp3.RequestBody
import okhttp3.MediaType
import okhttp3.FormBody
import okhttp3.HttpUrl
import okhttp3.ResponseBody
import okhttp3.Request
import java.io.File import java.io.File
import java.util.* import java.util.UUID
open class ApiClient(val baseUrl: String) { open class ApiClient(val baseUrl: String) {
companion object { companion object {
@ -13,6 +19,7 @@ open class ApiClient(val baseUrl: String) {
protected const val Accept = "Accept" protected const val Accept = "Accept"
protected const val JsonMediaType = "application/json" protected const val JsonMediaType = "application/json"
protected const val FormDataMediaType = "multipart/form-data" protected const val FormDataMediaType = "multipart/form-data"
protected const val FormUrlEncMediaType = "application/x-www-form-urlencoded"
protected const val XmlMediaType = "application/xml" protected const val XmlMediaType = "application/xml"
@JvmStatic @JvmStatic
@ -22,38 +29,38 @@ open class ApiClient(val baseUrl: String) {
@JvmStatic @JvmStatic
val builder: OkHttpClient.Builder = OkHttpClient.Builder() val builder: OkHttpClient.Builder = OkHttpClient.Builder()
@JvmStatic
var defaultHeaders: Map<String, String> by ApplicationDelegates.setOnce(mapOf(ContentType to JsonMediaType, Accept to JsonMediaType))
@JvmStatic
val jsonHeaders: Map<String, String> = mapOf(ContentType to JsonMediaType, Accept to JsonMediaType)
} }
protected inline fun <reified T> requestBody(content: T, mediaType: String = JsonMediaType): RequestBody = protected inline fun <reified T> requestBody(content: T, mediaType: String = JsonMediaType): RequestBody =
when { when {
content is File -> RequestBody.create( content is File -> RequestBody.create(
MediaType.parse(mediaType), content MediaType.parse(mediaType), content
) )
mediaType == FormDataMediaType -> { mediaType == FormDataMediaType || mediaType == FormUrlEncMediaType -> {
var builder = FormBody.Builder() var builder = FormBody.Builder()
// content's type *must* be Map<String, Any> // content's type *must* be Map<String, Any>
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
(content as Map<String,String>).forEach { key, value -> (content as Map<String,String>).forEach { key, value ->
builder = builder.add(key, value) builder = builder.add(key, value)
} }
builder.build() builder.build()
} }
mediaType == JsonMediaType -> RequestBody.create( mediaType == JsonMediaType -> RequestBody.create(
MediaType.parse(mediaType), Serializer.moshi.adapter(T::class.java).toJson(content) MediaType.parse(mediaType), Serializer.moshi.adapter(T::class.java).toJson(content)
) )
mediaType == XmlMediaType -> TODO("xml not currently supported.") mediaType == XmlMediaType -> TODO("xml not currently supported.")
// TODO: this should be extended with other serializers // TODO: this should be extended with other serializers
else -> TODO("requestBody currently only supports JSON body and File body.") else -> TODO("requestBody currently only supports JSON body and File body.")
} }
protected inline fun <reified T: Any?> responseBody(body: ResponseBody?, mediaType: String = JsonMediaType): T? { protected inline fun <reified T: Any?> responseBody(body: ResponseBody?, mediaType: String? = JsonMediaType): T? {
if(body == null) return null if(body == null) {
return null
}
val bodyContent = body.string()
if (bodyContent.length == 0) {
return null
}
return when(mediaType) { return when(mediaType) {
JsonMediaType -> Moshi.Builder().add(object { JsonMediaType -> Moshi.Builder().add(object {
@ToJson @ToJson
@ -62,8 +69,8 @@ open class ApiClient(val baseUrl: String) {
fun fromJson(s: String) = UUID.fromString(s) fun fromJson(s: String) = UUID.fromString(s)
}) })
.add(ByteArrayAdapter()) .add(ByteArrayAdapter())
.build().adapter(T::class.java).fromJson(body.source()) .build().adapter(T::class.java).fromJson(bodyContent)
else -> TODO() else -> TODO("responseBody currently only supports JSON body.")
} }
} }
@ -80,7 +87,15 @@ open class ApiClient(val baseUrl: String) {
} }
val url = urlBuilder.build() val url = urlBuilder.build()
val headers = requestConfig.headers + defaultHeaders
// take content-type/accept from spec or set to default (application/json) if not defined
if (requestConfig.headers[ContentType].isNullOrEmpty()) {
requestConfig.headers.put(ContentType, JsonMediaType)
}
if (requestConfig.headers[Accept].isNullOrEmpty()) {
requestConfig.headers.put(Accept, JsonMediaType)
}
val headers = requestConfig.headers
if(headers[ContentType] ?: "" == "") { if(headers[ContentType] ?: "" == "") {
throw kotlin.IllegalStateException("Missing Content-Type header. This is required.") throw kotlin.IllegalStateException("Missing Content-Type header. This is required.")
@ -90,9 +105,8 @@ open class ApiClient(val baseUrl: String) {
throw kotlin.IllegalStateException("Missing Accept header. This is required.") throw kotlin.IllegalStateException("Missing Accept header. This is required.")
} }
// TODO: support multiple contentType,accept options here. // TODO: support multiple contentType options here.
val contentType = (headers[ContentType] as String).substringBefore(";").toLowerCase() val contentType = (headers[ContentType] as String).substringBefore(";").toLowerCase()
val accept = (headers[Accept] as String).substringBefore(";").toLowerCase()
var request : Request.Builder = when (requestConfig.method) { var request : Request.Builder = when (requestConfig.method) {
RequestMethod.DELETE -> Request.Builder().url(url).delete() RequestMethod.DELETE -> Request.Builder().url(url).delete()
@ -108,6 +122,7 @@ open class ApiClient(val baseUrl: String) {
val realRequest = request.build() val realRequest = request.build()
val response = client.newCall(realRequest).execute() val response = client.newCall(realRequest).execute()
val accept = response.header(ContentType)?.substringBefore(";")?.toLowerCase()
// TODO: handle specific mapping types. e.g. Map<int, Class<?>> // TODO: handle specific mapping types. e.g. Map<int, Class<?>>
when { when {

View File

@ -11,6 +11,6 @@ package org.openapitools.client.infrastructure
data class RequestConfig( data class RequestConfig(
val method: RequestMethod, val method: RequestMethod,
val path: String, val path: String,
val headers: Map<String, String> = mapOf(), val headers: MutableMap<String, String> = mutableMapOf(),
val query: Map<String, List<String>> = mapOf() val query: Map<String, List<String>> = mapOf()
) )

View File

@ -2,7 +2,7 @@
## Requires ## Requires
* Kotlin 1.3.20 * Kotlin 1.3.31
* Gradle 4.9 * Gradle 4.9
## Build ## Build

View File

@ -7,7 +7,7 @@ wrapper {
} }
buildscript { buildscript {
ext.kotlin_version = '1.3.20' ext.kotlin_version = '1.3.31'
repositories { repositories {
mavenCentral() mavenCentral()
@ -32,7 +32,7 @@ dependencies {
compile "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version" compile "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
compile "com.squareup.moshi:moshi-kotlin:1.5.0" compile "com.squareup.moshi:moshi-kotlin:1.5.0"
compile "com.squareup.moshi:moshi-adapters:1.5.0" compile "com.squareup.moshi:moshi-adapters:1.5.0"
compile "com.squareup.okhttp3:okhttp:3.8.0" compile "com.squareup.okhttp3:okhttp:3.14.0"
compile "org.threeten:threetenbp:1.3.6" compile "org.threeten:threetenbp:1.3.8"
testImplementation "io.kotlintest:kotlintest-runner-junit5:3.1.0" testImplementation "io.kotlintest:kotlintest-runner-junit5:3.1.0"
} }

View File

@ -14,7 +14,17 @@ package org.openapitools.client.apis
import org.openapitools.client.models.ApiResponse import org.openapitools.client.models.ApiResponse
import org.openapitools.client.models.Pet import org.openapitools.client.models.Pet
import org.openapitools.client.infrastructure.* import org.openapitools.client.infrastructure.ApiClient
import org.openapitools.client.infrastructure.ClientException
import org.openapitools.client.infrastructure.ClientError
import org.openapitools.client.infrastructure.ServerException
import org.openapitools.client.infrastructure.ServerError
import org.openapitools.client.infrastructure.MultiValueMap
import org.openapitools.client.infrastructure.RequestConfig
import org.openapitools.client.infrastructure.RequestMethod
import org.openapitools.client.infrastructure.ResponseType
import org.openapitools.client.infrastructure.Success
import org.openapitools.client.infrastructure.toMultiValue
class PetApi(basePath: kotlin.String = "http://petstore.swagger.io/v2") : ApiClient(basePath) { class PetApi(basePath: kotlin.String = "http://petstore.swagger.io/v2") : ApiClient(basePath) {
@ -27,7 +37,7 @@ class PetApi(basePath: kotlin.String = "http://petstore.swagger.io/v2") : ApiCli
fun addPet(body: Pet) : Unit { fun addPet(body: Pet) : Unit {
val localVariableBody: kotlin.Any? = body val localVariableBody: kotlin.Any? = body
val localVariableQuery: MultiValueMap = mapOf() val localVariableQuery: MultiValueMap = mapOf()
val localVariableHeaders: kotlin.collections.Map<kotlin.String,kotlin.String> = mapOf() val localVariableHeaders: MutableMap<String, String> = mutableMapOf()
val localVariableConfig = RequestConfig( val localVariableConfig = RequestConfig(
RequestMethod.POST, RequestMethod.POST,
"/pet", "/pet",
@ -58,7 +68,7 @@ class PetApi(basePath: kotlin.String = "http://petstore.swagger.io/v2") : ApiCli
fun deletePet(petId: kotlin.Long, apiKey: kotlin.String?) : Unit { fun deletePet(petId: kotlin.Long, apiKey: kotlin.String?) : Unit {
val localVariableBody: kotlin.Any? = null val localVariableBody: kotlin.Any? = null
val localVariableQuery: MultiValueMap = mapOf() val localVariableQuery: MultiValueMap = mapOf()
val localVariableHeaders: kotlin.collections.Map<kotlin.String,kotlin.String> = mapOf("api_key" to apiKey.toString()) val localVariableHeaders: MutableMap<String, String> = mutableMapOf("api_key" to apiKey.toString())
val localVariableConfig = RequestConfig( val localVariableConfig = RequestConfig(
RequestMethod.DELETE, RequestMethod.DELETE,
"/pet/{petId}".replace("{"+"petId"+"}", "$petId"), "/pet/{petId}".replace("{"+"petId"+"}", "$petId"),
@ -89,7 +99,7 @@ class PetApi(basePath: kotlin.String = "http://petstore.swagger.io/v2") : ApiCli
fun findPetsByStatus(status: kotlin.Array<kotlin.String>) : kotlin.Array<Pet> { fun findPetsByStatus(status: kotlin.Array<kotlin.String>) : kotlin.Array<Pet> {
val localVariableBody: kotlin.Any? = null val localVariableBody: kotlin.Any? = null
val localVariableQuery: MultiValueMap = mapOf("status" to toMultiValue(status.toList(), "csv")) val localVariableQuery: MultiValueMap = mapOf("status" to toMultiValue(status.toList(), "csv"))
val localVariableHeaders: kotlin.collections.Map<kotlin.String,kotlin.String> = mapOf() val localVariableHeaders: MutableMap<String, String> = mutableMapOf()
val localVariableConfig = RequestConfig( val localVariableConfig = RequestConfig(
RequestMethod.GET, RequestMethod.GET,
"/pet/findByStatus", "/pet/findByStatus",
@ -120,7 +130,7 @@ class PetApi(basePath: kotlin.String = "http://petstore.swagger.io/v2") : ApiCli
fun findPetsByTags(tags: kotlin.Array<kotlin.String>) : kotlin.Array<Pet> { fun findPetsByTags(tags: kotlin.Array<kotlin.String>) : kotlin.Array<Pet> {
val localVariableBody: kotlin.Any? = null val localVariableBody: kotlin.Any? = null
val localVariableQuery: MultiValueMap = mapOf("tags" to toMultiValue(tags.toList(), "csv")) val localVariableQuery: MultiValueMap = mapOf("tags" to toMultiValue(tags.toList(), "csv"))
val localVariableHeaders: kotlin.collections.Map<kotlin.String,kotlin.String> = mapOf() val localVariableHeaders: MutableMap<String, String> = mutableMapOf()
val localVariableConfig = RequestConfig( val localVariableConfig = RequestConfig(
RequestMethod.GET, RequestMethod.GET,
"/pet/findByTags", "/pet/findByTags",
@ -151,7 +161,7 @@ class PetApi(basePath: kotlin.String = "http://petstore.swagger.io/v2") : ApiCli
fun getPetById(petId: kotlin.Long) : Pet { fun getPetById(petId: kotlin.Long) : Pet {
val localVariableBody: kotlin.Any? = null val localVariableBody: kotlin.Any? = null
val localVariableQuery: MultiValueMap = mapOf() val localVariableQuery: MultiValueMap = mapOf()
val localVariableHeaders: kotlin.collections.Map<kotlin.String,kotlin.String> = mapOf() val localVariableHeaders: MutableMap<String, String> = mutableMapOf()
val localVariableConfig = RequestConfig( val localVariableConfig = RequestConfig(
RequestMethod.GET, RequestMethod.GET,
"/pet/{petId}".replace("{"+"petId"+"}", "$petId"), "/pet/{petId}".replace("{"+"petId"+"}", "$petId"),
@ -181,7 +191,7 @@ class PetApi(basePath: kotlin.String = "http://petstore.swagger.io/v2") : ApiCli
fun updatePet(body: Pet) : Unit { fun updatePet(body: Pet) : Unit {
val localVariableBody: kotlin.Any? = body val localVariableBody: kotlin.Any? = body
val localVariableQuery: MultiValueMap = mapOf() val localVariableQuery: MultiValueMap = mapOf()
val localVariableHeaders: kotlin.collections.Map<kotlin.String,kotlin.String> = mapOf() val localVariableHeaders: MutableMap<String, String> = mutableMapOf()
val localVariableConfig = RequestConfig( val localVariableConfig = RequestConfig(
RequestMethod.PUT, RequestMethod.PUT,
"/pet", "/pet",
@ -213,7 +223,7 @@ class PetApi(basePath: kotlin.String = "http://petstore.swagger.io/v2") : ApiCli
fun updatePetWithForm(petId: kotlin.Long, name: kotlin.String?, status: kotlin.String?) : Unit { fun updatePetWithForm(petId: kotlin.Long, name: kotlin.String?, status: kotlin.String?) : Unit {
val localVariableBody: kotlin.Any? = mapOf("name" to "$name", "status" to "$status") val localVariableBody: kotlin.Any? = mapOf("name" to "$name", "status" to "$status")
val localVariableQuery: MultiValueMap = mapOf() val localVariableQuery: MultiValueMap = mapOf()
val localVariableHeaders: kotlin.collections.Map<kotlin.String,kotlin.String> = mapOf("Content-Type" to "multipart/form-data") val localVariableHeaders: MutableMap<String, String> = mutableMapOf("Content-Type" to "")
val localVariableConfig = RequestConfig( val localVariableConfig = RequestConfig(
RequestMethod.POST, RequestMethod.POST,
"/pet/{petId}".replace("{"+"petId"+"}", "$petId"), "/pet/{petId}".replace("{"+"petId"+"}", "$petId"),
@ -246,7 +256,7 @@ class PetApi(basePath: kotlin.String = "http://petstore.swagger.io/v2") : ApiCli
fun uploadFile(petId: kotlin.Long, additionalMetadata: kotlin.String?, file: java.io.File?) : ApiResponse { fun uploadFile(petId: kotlin.Long, additionalMetadata: kotlin.String?, file: java.io.File?) : ApiResponse {
val localVariableBody: kotlin.Any? = mapOf("additionalMetadata" to "$additionalMetadata", "file" to "$file") val localVariableBody: kotlin.Any? = mapOf("additionalMetadata" to "$additionalMetadata", "file" to "$file")
val localVariableQuery: MultiValueMap = mapOf() val localVariableQuery: MultiValueMap = mapOf()
val localVariableHeaders: kotlin.collections.Map<kotlin.String,kotlin.String> = mapOf("Content-Type" to "multipart/form-data") val localVariableHeaders: MutableMap<String, String> = mutableMapOf("Content-Type" to "")
val localVariableConfig = RequestConfig( val localVariableConfig = RequestConfig(
RequestMethod.POST, RequestMethod.POST,
"/pet/{petId}/uploadImage".replace("{"+"petId"+"}", "$petId"), "/pet/{petId}/uploadImage".replace("{"+"petId"+"}", "$petId"),

View File

@ -13,7 +13,17 @@ package org.openapitools.client.apis
import org.openapitools.client.models.Order import org.openapitools.client.models.Order
import org.openapitools.client.infrastructure.* import org.openapitools.client.infrastructure.ApiClient
import org.openapitools.client.infrastructure.ClientException
import org.openapitools.client.infrastructure.ClientError
import org.openapitools.client.infrastructure.ServerException
import org.openapitools.client.infrastructure.ServerError
import org.openapitools.client.infrastructure.MultiValueMap
import org.openapitools.client.infrastructure.RequestConfig
import org.openapitools.client.infrastructure.RequestMethod
import org.openapitools.client.infrastructure.ResponseType
import org.openapitools.client.infrastructure.Success
import org.openapitools.client.infrastructure.toMultiValue
class StoreApi(basePath: kotlin.String = "http://petstore.swagger.io/v2") : ApiClient(basePath) { class StoreApi(basePath: kotlin.String = "http://petstore.swagger.io/v2") : ApiClient(basePath) {
@ -26,7 +36,7 @@ class StoreApi(basePath: kotlin.String = "http://petstore.swagger.io/v2") : ApiC
fun deleteOrder(orderId: kotlin.String) : Unit { fun deleteOrder(orderId: kotlin.String) : Unit {
val localVariableBody: kotlin.Any? = null val localVariableBody: kotlin.Any? = null
val localVariableQuery: MultiValueMap = mapOf() val localVariableQuery: MultiValueMap = mapOf()
val localVariableHeaders: kotlin.collections.Map<kotlin.String,kotlin.String> = mapOf() val localVariableHeaders: MutableMap<String, String> = mutableMapOf()
val localVariableConfig = RequestConfig( val localVariableConfig = RequestConfig(
RequestMethod.DELETE, RequestMethod.DELETE,
"/store/order/{orderId}".replace("{"+"orderId"+"}", "$orderId"), "/store/order/{orderId}".replace("{"+"orderId"+"}", "$orderId"),
@ -56,7 +66,7 @@ class StoreApi(basePath: kotlin.String = "http://petstore.swagger.io/v2") : ApiC
fun getInventory() : kotlin.collections.Map<kotlin.String, kotlin.Int> { fun getInventory() : kotlin.collections.Map<kotlin.String, kotlin.Int> {
val localVariableBody: kotlin.Any? = null val localVariableBody: kotlin.Any? = null
val localVariableQuery: MultiValueMap = mapOf() val localVariableQuery: MultiValueMap = mapOf()
val localVariableHeaders: kotlin.collections.Map<kotlin.String,kotlin.String> = mapOf() val localVariableHeaders: MutableMap<String, String> = mutableMapOf()
val localVariableConfig = RequestConfig( val localVariableConfig = RequestConfig(
RequestMethod.GET, RequestMethod.GET,
"/store/inventory", "/store/inventory",
@ -87,7 +97,7 @@ class StoreApi(basePath: kotlin.String = "http://petstore.swagger.io/v2") : ApiC
fun getOrderById(orderId: kotlin.Long) : Order { fun getOrderById(orderId: kotlin.Long) : Order {
val localVariableBody: kotlin.Any? = null val localVariableBody: kotlin.Any? = null
val localVariableQuery: MultiValueMap = mapOf() val localVariableQuery: MultiValueMap = mapOf()
val localVariableHeaders: kotlin.collections.Map<kotlin.String,kotlin.String> = mapOf() val localVariableHeaders: MutableMap<String, String> = mutableMapOf()
val localVariableConfig = RequestConfig( val localVariableConfig = RequestConfig(
RequestMethod.GET, RequestMethod.GET,
"/store/order/{orderId}".replace("{"+"orderId"+"}", "$orderId"), "/store/order/{orderId}".replace("{"+"orderId"+"}", "$orderId"),
@ -118,7 +128,7 @@ class StoreApi(basePath: kotlin.String = "http://petstore.swagger.io/v2") : ApiC
fun placeOrder(body: Order) : Order { fun placeOrder(body: Order) : Order {
val localVariableBody: kotlin.Any? = body val localVariableBody: kotlin.Any? = body
val localVariableQuery: MultiValueMap = mapOf() val localVariableQuery: MultiValueMap = mapOf()
val localVariableHeaders: kotlin.collections.Map<kotlin.String,kotlin.String> = mapOf() val localVariableHeaders: MutableMap<String, String> = mutableMapOf()
val localVariableConfig = RequestConfig( val localVariableConfig = RequestConfig(
RequestMethod.POST, RequestMethod.POST,
"/store/order", "/store/order",

View File

@ -13,7 +13,17 @@ package org.openapitools.client.apis
import org.openapitools.client.models.User import org.openapitools.client.models.User
import org.openapitools.client.infrastructure.* import org.openapitools.client.infrastructure.ApiClient
import org.openapitools.client.infrastructure.ClientException
import org.openapitools.client.infrastructure.ClientError
import org.openapitools.client.infrastructure.ServerException
import org.openapitools.client.infrastructure.ServerError
import org.openapitools.client.infrastructure.MultiValueMap
import org.openapitools.client.infrastructure.RequestConfig
import org.openapitools.client.infrastructure.RequestMethod
import org.openapitools.client.infrastructure.ResponseType
import org.openapitools.client.infrastructure.Success
import org.openapitools.client.infrastructure.toMultiValue
class UserApi(basePath: kotlin.String = "http://petstore.swagger.io/v2") : ApiClient(basePath) { class UserApi(basePath: kotlin.String = "http://petstore.swagger.io/v2") : ApiClient(basePath) {
@ -26,7 +36,7 @@ class UserApi(basePath: kotlin.String = "http://petstore.swagger.io/v2") : ApiCl
fun createUser(body: User) : Unit { fun createUser(body: User) : Unit {
val localVariableBody: kotlin.Any? = body val localVariableBody: kotlin.Any? = body
val localVariableQuery: MultiValueMap = mapOf() val localVariableQuery: MultiValueMap = mapOf()
val localVariableHeaders: kotlin.collections.Map<kotlin.String,kotlin.String> = mapOf() val localVariableHeaders: MutableMap<String, String> = mutableMapOf()
val localVariableConfig = RequestConfig( val localVariableConfig = RequestConfig(
RequestMethod.POST, RequestMethod.POST,
"/user", "/user",
@ -56,7 +66,7 @@ class UserApi(basePath: kotlin.String = "http://petstore.swagger.io/v2") : ApiCl
fun createUsersWithArrayInput(body: kotlin.Array<User>) : Unit { fun createUsersWithArrayInput(body: kotlin.Array<User>) : Unit {
val localVariableBody: kotlin.Any? = body val localVariableBody: kotlin.Any? = body
val localVariableQuery: MultiValueMap = mapOf() val localVariableQuery: MultiValueMap = mapOf()
val localVariableHeaders: kotlin.collections.Map<kotlin.String,kotlin.String> = mapOf() val localVariableHeaders: MutableMap<String, String> = mutableMapOf()
val localVariableConfig = RequestConfig( val localVariableConfig = RequestConfig(
RequestMethod.POST, RequestMethod.POST,
"/user/createWithArray", "/user/createWithArray",
@ -86,7 +96,7 @@ class UserApi(basePath: kotlin.String = "http://petstore.swagger.io/v2") : ApiCl
fun createUsersWithListInput(body: kotlin.Array<User>) : Unit { fun createUsersWithListInput(body: kotlin.Array<User>) : Unit {
val localVariableBody: kotlin.Any? = body val localVariableBody: kotlin.Any? = body
val localVariableQuery: MultiValueMap = mapOf() val localVariableQuery: MultiValueMap = mapOf()
val localVariableHeaders: kotlin.collections.Map<kotlin.String,kotlin.String> = mapOf() val localVariableHeaders: MutableMap<String, String> = mutableMapOf()
val localVariableConfig = RequestConfig( val localVariableConfig = RequestConfig(
RequestMethod.POST, RequestMethod.POST,
"/user/createWithList", "/user/createWithList",
@ -116,7 +126,7 @@ class UserApi(basePath: kotlin.String = "http://petstore.swagger.io/v2") : ApiCl
fun deleteUser(username: kotlin.String) : Unit { fun deleteUser(username: kotlin.String) : Unit {
val localVariableBody: kotlin.Any? = null val localVariableBody: kotlin.Any? = null
val localVariableQuery: MultiValueMap = mapOf() val localVariableQuery: MultiValueMap = mapOf()
val localVariableHeaders: kotlin.collections.Map<kotlin.String,kotlin.String> = mapOf() val localVariableHeaders: MutableMap<String, String> = mutableMapOf()
val localVariableConfig = RequestConfig( val localVariableConfig = RequestConfig(
RequestMethod.DELETE, RequestMethod.DELETE,
"/user/{username}".replace("{"+"username"+"}", "$username"), "/user/{username}".replace("{"+"username"+"}", "$username"),
@ -147,7 +157,7 @@ class UserApi(basePath: kotlin.String = "http://petstore.swagger.io/v2") : ApiCl
fun getUserByName(username: kotlin.String) : User { fun getUserByName(username: kotlin.String) : User {
val localVariableBody: kotlin.Any? = null val localVariableBody: kotlin.Any? = null
val localVariableQuery: MultiValueMap = mapOf() val localVariableQuery: MultiValueMap = mapOf()
val localVariableHeaders: kotlin.collections.Map<kotlin.String,kotlin.String> = mapOf() val localVariableHeaders: MutableMap<String, String> = mutableMapOf()
val localVariableConfig = RequestConfig( val localVariableConfig = RequestConfig(
RequestMethod.GET, RequestMethod.GET,
"/user/{username}".replace("{"+"username"+"}", "$username"), "/user/{username}".replace("{"+"username"+"}", "$username"),
@ -179,7 +189,7 @@ class UserApi(basePath: kotlin.String = "http://petstore.swagger.io/v2") : ApiCl
fun loginUser(username: kotlin.String, password: kotlin.String) : kotlin.String { fun loginUser(username: kotlin.String, password: kotlin.String) : kotlin.String {
val localVariableBody: kotlin.Any? = null val localVariableBody: kotlin.Any? = null
val localVariableQuery: MultiValueMap = mapOf("username" to listOf("$username"), "password" to listOf("$password")) val localVariableQuery: MultiValueMap = mapOf("username" to listOf("$username"), "password" to listOf("$password"))
val localVariableHeaders: kotlin.collections.Map<kotlin.String,kotlin.String> = mapOf() val localVariableHeaders: MutableMap<String, String> = mutableMapOf()
val localVariableConfig = RequestConfig( val localVariableConfig = RequestConfig(
RequestMethod.GET, RequestMethod.GET,
"/user/login", "/user/login",
@ -208,7 +218,7 @@ class UserApi(basePath: kotlin.String = "http://petstore.swagger.io/v2") : ApiCl
fun logoutUser() : Unit { fun logoutUser() : Unit {
val localVariableBody: kotlin.Any? = null val localVariableBody: kotlin.Any? = null
val localVariableQuery: MultiValueMap = mapOf() val localVariableQuery: MultiValueMap = mapOf()
val localVariableHeaders: kotlin.collections.Map<kotlin.String,kotlin.String> = mapOf() val localVariableHeaders: MutableMap<String, String> = mutableMapOf()
val localVariableConfig = RequestConfig( val localVariableConfig = RequestConfig(
RequestMethod.GET, RequestMethod.GET,
"/user/logout", "/user/logout",
@ -239,7 +249,7 @@ class UserApi(basePath: kotlin.String = "http://petstore.swagger.io/v2") : ApiCl
fun updateUser(username: kotlin.String, body: User) : Unit { fun updateUser(username: kotlin.String, body: User) : Unit {
val localVariableBody: kotlin.Any? = body val localVariableBody: kotlin.Any? = body
val localVariableQuery: MultiValueMap = mapOf() val localVariableQuery: MultiValueMap = mapOf()
val localVariableHeaders: kotlin.collections.Map<kotlin.String,kotlin.String> = mapOf() val localVariableHeaders: MutableMap<String, String> = mutableMapOf()
val localVariableConfig = RequestConfig( val localVariableConfig = RequestConfig(
RequestMethod.PUT, RequestMethod.PUT,
"/user/{username}".replace("{"+"username"+"}", "$username"), "/user/{username}".replace("{"+"username"+"}", "$username"),

View File

@ -3,9 +3,15 @@ package org.openapitools.client.infrastructure
import com.squareup.moshi.FromJson import com.squareup.moshi.FromJson
import com.squareup.moshi.Moshi import com.squareup.moshi.Moshi
import com.squareup.moshi.ToJson import com.squareup.moshi.ToJson
import okhttp3.* import okhttp3.OkHttpClient
import okhttp3.RequestBody
import okhttp3.MediaType
import okhttp3.FormBody
import okhttp3.HttpUrl
import okhttp3.ResponseBody
import okhttp3.Request
import java.io.File import java.io.File
import java.util.* import java.util.UUID
open class ApiClient(val baseUrl: String) { open class ApiClient(val baseUrl: String) {
companion object { companion object {
@ -13,6 +19,7 @@ open class ApiClient(val baseUrl: String) {
protected const val Accept = "Accept" protected const val Accept = "Accept"
protected const val JsonMediaType = "application/json" protected const val JsonMediaType = "application/json"
protected const val FormDataMediaType = "multipart/form-data" protected const val FormDataMediaType = "multipart/form-data"
protected const val FormUrlEncMediaType = "application/x-www-form-urlencoded"
protected const val XmlMediaType = "application/xml" protected const val XmlMediaType = "application/xml"
@JvmStatic @JvmStatic
@ -22,38 +29,38 @@ open class ApiClient(val baseUrl: String) {
@JvmStatic @JvmStatic
val builder: OkHttpClient.Builder = OkHttpClient.Builder() val builder: OkHttpClient.Builder = OkHttpClient.Builder()
@JvmStatic
var defaultHeaders: Map<String, String> by ApplicationDelegates.setOnce(mapOf(ContentType to JsonMediaType, Accept to JsonMediaType))
@JvmStatic
val jsonHeaders: Map<String, String> = mapOf(ContentType to JsonMediaType, Accept to JsonMediaType)
} }
protected inline fun <reified T> requestBody(content: T, mediaType: String = JsonMediaType): RequestBody = protected inline fun <reified T> requestBody(content: T, mediaType: String = JsonMediaType): RequestBody =
when { when {
content is File -> RequestBody.create( content is File -> RequestBody.create(
MediaType.parse(mediaType), content MediaType.parse(mediaType), content
) )
mediaType == FormDataMediaType -> { mediaType == FormDataMediaType || mediaType == FormUrlEncMediaType -> {
var builder = FormBody.Builder() var builder = FormBody.Builder()
// content's type *must* be Map<String, Any> // content's type *must* be Map<String, Any>
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
(content as Map<String,String>).forEach { key, value -> (content as Map<String,String>).forEach { key, value ->
builder = builder.add(key, value) builder = builder.add(key, value)
} }
builder.build() builder.build()
} }
mediaType == JsonMediaType -> RequestBody.create( mediaType == JsonMediaType -> RequestBody.create(
MediaType.parse(mediaType), Serializer.moshi.adapter(T::class.java).toJson(content) MediaType.parse(mediaType), Serializer.moshi.adapter(T::class.java).toJson(content)
) )
mediaType == XmlMediaType -> TODO("xml not currently supported.") mediaType == XmlMediaType -> TODO("xml not currently supported.")
// TODO: this should be extended with other serializers // TODO: this should be extended with other serializers
else -> TODO("requestBody currently only supports JSON body and File body.") else -> TODO("requestBody currently only supports JSON body and File body.")
} }
protected inline fun <reified T: Any?> responseBody(body: ResponseBody?, mediaType: String = JsonMediaType): T? { protected inline fun <reified T: Any?> responseBody(body: ResponseBody?, mediaType: String? = JsonMediaType): T? {
if(body == null) return null if(body == null) {
return null
}
val bodyContent = body.string()
if (bodyContent.length == 0) {
return null
}
return when(mediaType) { return when(mediaType) {
JsonMediaType -> Moshi.Builder().add(object { JsonMediaType -> Moshi.Builder().add(object {
@ToJson @ToJson
@ -62,8 +69,8 @@ open class ApiClient(val baseUrl: String) {
fun fromJson(s: String) = UUID.fromString(s) fun fromJson(s: String) = UUID.fromString(s)
}) })
.add(ByteArrayAdapter()) .add(ByteArrayAdapter())
.build().adapter(T::class.java).fromJson(body.source()) .build().adapter(T::class.java).fromJson(bodyContent)
else -> TODO() else -> TODO("responseBody currently only supports JSON body.")
} }
} }
@ -80,7 +87,15 @@ open class ApiClient(val baseUrl: String) {
} }
val url = urlBuilder.build() val url = urlBuilder.build()
val headers = requestConfig.headers + defaultHeaders
// take content-type/accept from spec or set to default (application/json) if not defined
if (requestConfig.headers[ContentType].isNullOrEmpty()) {
requestConfig.headers.put(ContentType, JsonMediaType)
}
if (requestConfig.headers[Accept].isNullOrEmpty()) {
requestConfig.headers.put(Accept, JsonMediaType)
}
val headers = requestConfig.headers
if(headers[ContentType] ?: "" == "") { if(headers[ContentType] ?: "" == "") {
throw kotlin.IllegalStateException("Missing Content-Type header. This is required.") throw kotlin.IllegalStateException("Missing Content-Type header. This is required.")
@ -90,9 +105,8 @@ open class ApiClient(val baseUrl: String) {
throw kotlin.IllegalStateException("Missing Accept header. This is required.") throw kotlin.IllegalStateException("Missing Accept header. This is required.")
} }
// TODO: support multiple contentType,accept options here. // TODO: support multiple contentType options here.
val contentType = (headers[ContentType] as String).substringBefore(";").toLowerCase() val contentType = (headers[ContentType] as String).substringBefore(";").toLowerCase()
val accept = (headers[Accept] as String).substringBefore(";").toLowerCase()
var request : Request.Builder = when (requestConfig.method) { var request : Request.Builder = when (requestConfig.method) {
RequestMethod.DELETE -> Request.Builder().url(url).delete() RequestMethod.DELETE -> Request.Builder().url(url).delete()
@ -108,6 +122,7 @@ open class ApiClient(val baseUrl: String) {
val realRequest = request.build() val realRequest = request.build()
val response = client.newCall(realRequest).execute() val response = client.newCall(realRequest).execute()
val accept = response.header(ContentType)?.substringBefore(";")?.toLowerCase()
// TODO: handle specific mapping types. e.g. Map<int, Class<?>> // TODO: handle specific mapping types. e.g. Map<int, Class<?>>
when { when {

View File

@ -11,6 +11,6 @@ package org.openapitools.client.infrastructure
data class RequestConfig( data class RequestConfig(
val method: RequestMethod, val method: RequestMethod,
val path: String, val path: String,
val headers: Map<String, String> = mapOf(), val headers: MutableMap<String, String> = mutableMapOf(),
val query: Map<String, List<String>> = mapOf() val query: Map<String, List<String>> = mapOf()
) )

View File

@ -2,8 +2,11 @@ package org.openapitools.client
import io.kotlintest.shouldBe import io.kotlintest.shouldBe
import io.kotlintest.matchers.numerics.shouldBeGreaterThan import io.kotlintest.matchers.numerics.shouldBeGreaterThan
import io.kotlintest.matchers.string.shouldContain
import io.kotlintest.shouldThrow
import io.kotlintest.specs.ShouldSpec import io.kotlintest.specs.ShouldSpec
import org.openapitools.client.apis.PetApi import org.openapitools.client.apis.PetApi
import org.openapitools.client.infrastructure.ClientException
import org.openapitools.client.models.Category import org.openapitools.client.models.Category
import org.openapitools.client.models.Pet import org.openapitools.client.models.Pet
import org.openapitools.client.models.Tag import org.openapitools.client.models.Tag
@ -11,8 +14,11 @@ import org.openapitools.client.models.Tag
class PetApiTest : ShouldSpec() { class PetApiTest : ShouldSpec() {
init { init {
val petId:Long = 10006
val api = PetApi()
should("add a pet") { should("add a pet") {
val petId:Long = 10006
val pet = Pet( val pet = Pet(
id = petId, id = petId,
name = "kotlin client test", name = "kotlin client test",
@ -20,15 +26,11 @@ class PetApiTest : ShouldSpec() {
category = Category(petId, "test kotlin category"), category = Category(petId, "test kotlin category"),
tags = arrayOf(Tag(petId, "test kotlin tag")) tags = arrayOf(Tag(petId, "test kotlin tag"))
) )
val api = PetApi()
api.addPet(pet) api.addPet(pet)
} }
should("get pet by id") { should("get pet by id") {
val petId: Long = 10006
val api = PetApi()
val result = api.getPetById(petId) val result = api.getPetById(petId)
result.id shouldBe (petId) result.id shouldBe (petId)
@ -42,7 +44,6 @@ class PetApiTest : ShouldSpec() {
} }
should("find pet by status") { should("find pet by status") {
val api = PetApi()
val result = api.findPetsByStatus(arrayOf("available")) val result = api.findPetsByStatus(arrayOf("available"))
result.size.shouldBeGreaterThan(0) result.size.shouldBeGreaterThan(0)
@ -58,15 +59,12 @@ class PetApiTest : ShouldSpec() {
} }
should("update a pet") { should("update a pet") {
val petId:Long = 10007
val pet = Pet( val pet = Pet(
id = petId, id = petId,
name = "kotlin client updatePet", name = "kotlin client updatePet",
status = Pet.Status.pending, status = Pet.Status.pending,
photoUrls = arrayOf("http://test_kotlin_unit_test.com") photoUrls = arrayOf("http://test_kotlin_unit_test.com")
) )
val api = PetApi()
api.updatePet(pet) api.updatePet(pet)
// verify updated Pet // verify updated Pet
@ -77,14 +75,10 @@ class PetApiTest : ShouldSpec() {
} }
//TODO the test fail cause client doesn't support other JSON contentType/Accept
/*
should("update a pet with form") { should("update a pet with form") {
val petId:Long = 10007
val name = "kotlin client updatePet with Form" val name = "kotlin client updatePet with Form"
val status = "pending" val status = "pending"
val api = PetApi()
api.updatePetWithForm(petId, name, status) api.updatePetWithForm(petId, name, status)
// verify updated Pet // verify updated Pet
@ -94,7 +88,16 @@ class PetApiTest : ShouldSpec() {
result.status shouldBe (Pet.Status.pending) result.status shouldBe (Pet.Status.pending)
} }
*/
should("delete a pet") {
api.deletePet(petId, "apiKey")
// verify updated Pet
val exception = shouldThrow<ClientException> {
api.getPetById(petId)
}
exception.message?.shouldContain("Pet not found")
}
} }

View File

@ -1,22 +1,35 @@
package org.openapitools.server package org.openapitools.server
import com.codahale.metrics.* import com.codahale.metrics.Slf4jReporter
import com.typesafe.config.ConfigFactory import com.typesafe.config.ConfigFactory
import io.ktor.application.* import io.ktor.application.Application
import io.ktor.application.ApplicationStopping
import io.ktor.application.install
import io.ktor.application.log
import io.ktor.client.HttpClient import io.ktor.client.HttpClient
import io.ktor.client.engine.apache.Apache import io.ktor.client.engine.apache.Apache
import io.ktor.config.HoconApplicationConfig import io.ktor.config.HoconApplicationConfig
import io.ktor.features.* import io.ktor.features.AutoHeadResponse
import io.ktor.features.Compression
import io.ktor.features.ContentNegotiation
import io.ktor.features.DefaultHeaders
import io.ktor.features.HSTS
import io.ktor.gson.GsonConverter import io.ktor.gson.GsonConverter
import io.ktor.http.ContentType import io.ktor.http.ContentType
import io.ktor.locations.* import io.ktor.locations.KtorExperimentalLocationsAPI
import io.ktor.metrics.* import io.ktor.locations.Locations
import io.ktor.routing.* import io.ktor.metrics.Metrics
import java.util.concurrent.* import io.ktor.routing.Routing
import io.ktor.auth.* import java.util.concurrent.TimeUnit
import io.ktor.auth.Authentication
import io.ktor.auth.oauth
import io.ktor.util.KtorExperimentalAPI import io.ktor.util.KtorExperimentalAPI
import org.openapitools.server.infrastructure.* import org.openapitools.server.infrastructure.ApiKeyCredential
import org.openapitools.server.apis.* import org.openapitools.server.infrastructure.ApiPrincipal
import org.openapitools.server.infrastructure.apiKeyAuth
import org.openapitools.server.apis.PetApi
import org.openapitools.server.apis.StoreApi
import org.openapitools.server.apis.UserApi
@KtorExperimentalAPI @KtorExperimentalAPI

View File

@ -2,8 +2,12 @@ package org.openapitools.server
// Use this file to hold package-level internal functions that return receiver object passed to the `install` method. // Use this file to hold package-level internal functions that return receiver object passed to the `install` method.
import io.ktor.auth.OAuthServerSettings import io.ktor.auth.OAuthServerSettings
import io.ktor.features.* import io.ktor.features.Compression
import io.ktor.http.* import io.ktor.features.HSTS
import io.ktor.features.deflate
import io.ktor.features.gzip
import io.ktor.features.minimumSize
import io.ktor.http.HttpMethod
import io.ktor.util.KtorExperimentalAPI import io.ktor.util.KtorExperimentalAPI
import java.time.Duration import java.time.Duration
import java.util.concurrent.Executors import java.util.concurrent.Executors

View File

@ -11,9 +11,8 @@
*/ */
package org.openapitools.server package org.openapitools.server
import io.ktor.locations.* import io.ktor.locations.KtorExperimentalLocationsAPI
import org.openapitools.server.models.* import io.ktor.locations.Location
object Paths { object Paths {
/** /**

View File

@ -20,10 +20,15 @@ import io.ktor.auth.OAuthAccessTokenResponse
import io.ktor.auth.OAuthServerSettings import io.ktor.auth.OAuthServerSettings
import io.ktor.http.ContentType import io.ktor.http.ContentType
import io.ktor.http.HttpStatusCode import io.ktor.http.HttpStatusCode
import io.ktor.locations.* import io.ktor.locations.KtorExperimentalLocationsAPI
import io.ktor.locations.delete
import io.ktor.locations.get
import io.ktor.response.respond import io.ktor.response.respond
import io.ktor.response.respondText import io.ktor.response.respondText
import io.ktor.routing.* import io.ktor.routing.Route
import io.ktor.routing.post
import io.ktor.routing.put
import io.ktor.routing.route
import org.openapitools.server.Paths import org.openapitools.server.Paths
import org.openapitools.server.infrastructure.ApiPrincipal import org.openapitools.server.infrastructure.ApiPrincipal

View File

@ -20,10 +20,15 @@ import io.ktor.auth.OAuthAccessTokenResponse
import io.ktor.auth.OAuthServerSettings import io.ktor.auth.OAuthServerSettings
import io.ktor.http.ContentType import io.ktor.http.ContentType
import io.ktor.http.HttpStatusCode import io.ktor.http.HttpStatusCode
import io.ktor.locations.* import io.ktor.locations.KtorExperimentalLocationsAPI
import io.ktor.locations.delete
import io.ktor.locations.get
import io.ktor.response.respond import io.ktor.response.respond
import io.ktor.response.respondText import io.ktor.response.respondText
import io.ktor.routing.* import io.ktor.routing.Route
import io.ktor.routing.post
import io.ktor.routing.put
import io.ktor.routing.route
import org.openapitools.server.Paths import org.openapitools.server.Paths
import org.openapitools.server.infrastructure.ApiPrincipal import org.openapitools.server.infrastructure.ApiPrincipal

View File

@ -20,10 +20,15 @@ import io.ktor.auth.OAuthAccessTokenResponse
import io.ktor.auth.OAuthServerSettings import io.ktor.auth.OAuthServerSettings
import io.ktor.http.ContentType import io.ktor.http.ContentType
import io.ktor.http.HttpStatusCode import io.ktor.http.HttpStatusCode
import io.ktor.locations.* import io.ktor.locations.KtorExperimentalLocationsAPI
import io.ktor.locations.delete
import io.ktor.locations.get
import io.ktor.response.respond import io.ktor.response.respond
import io.ktor.response.respondText import io.ktor.response.respondText
import io.ktor.routing.* import io.ktor.routing.Route
import io.ktor.routing.post
import io.ktor.routing.put
import io.ktor.routing.route
import org.openapitools.server.Paths import org.openapitools.server.Paths
import org.openapitools.server.infrastructure.ApiPrincipal import org.openapitools.server.infrastructure.ApiPrincipal

View File

@ -2,8 +2,15 @@ package org.openapitools.server.infrastructure
import io.ktor.application.ApplicationCall import io.ktor.application.ApplicationCall
import io.ktor.application.call import io.ktor.application.call
import io.ktor.auth.* import io.ktor.auth.Authentication
import io.ktor.http.auth.* import io.ktor.auth.AuthenticationFailedCause
import io.ktor.auth.AuthenticationPipeline
import io.ktor.auth.AuthenticationProvider
import io.ktor.auth.Credential
import io.ktor.auth.Principal
import io.ktor.auth.UnauthorizedResponse
import io.ktor.http.auth.HeaderValueEncoding
import io.ktor.http.auth.HttpAuthHeader
import io.ktor.request.ApplicationRequest import io.ktor.request.ApplicationRequest
import io.ktor.response.respond import io.ktor.response.respond

View File

@ -2,7 +2,13 @@ package org.openapitools.api
import org.openapitools.model.ModelApiResponse import org.openapitools.model.ModelApiResponse
import org.openapitools.model.Pet import org.openapitools.model.Pet
import io.swagger.annotations.* import io.swagger.annotations.Api
import io.swagger.annotations.ApiOperation
import io.swagger.annotations.ApiParam
import io.swagger.annotations.ApiResponse
import io.swagger.annotations.ApiResponses
import io.swagger.annotations.Authorization
import io.swagger.annotations.AuthorizationScope
import org.springframework.http.HttpStatus import org.springframework.http.HttpStatus
import org.springframework.http.MediaType import org.springframework.http.MediaType
import org.springframework.http.ResponseEntity import org.springframework.http.ResponseEntity
@ -19,7 +25,13 @@ import org.springframework.web.context.request.NativeWebRequest
import org.springframework.beans.factory.annotation.Autowired import org.springframework.beans.factory.annotation.Autowired
import javax.validation.Valid import javax.validation.Valid
import javax.validation.constraints.* import javax.validation.constraints.DecimalMax
import javax.validation.constraints.DecimalMin
import javax.validation.constraints.Max
import javax.validation.constraints.Min
import javax.validation.constraints.NotNull
import javax.validation.constraints.Pattern
import javax.validation.constraints.Size
import kotlin.collections.List import kotlin.collections.List
import kotlin.collections.Map import kotlin.collections.Map

View File

@ -1,7 +1,13 @@
package org.openapitools.api package org.openapitools.api
import org.openapitools.model.Order import org.openapitools.model.Order
import io.swagger.annotations.* import io.swagger.annotations.Api
import io.swagger.annotations.ApiOperation
import io.swagger.annotations.ApiParam
import io.swagger.annotations.ApiResponse
import io.swagger.annotations.ApiResponses
import io.swagger.annotations.Authorization
import io.swagger.annotations.AuthorizationScope
import org.springframework.http.HttpStatus import org.springframework.http.HttpStatus
import org.springframework.http.MediaType import org.springframework.http.MediaType
import org.springframework.http.ResponseEntity import org.springframework.http.ResponseEntity
@ -18,7 +24,13 @@ import org.springframework.web.context.request.NativeWebRequest
import org.springframework.beans.factory.annotation.Autowired import org.springframework.beans.factory.annotation.Autowired
import javax.validation.Valid import javax.validation.Valid
import javax.validation.constraints.* import javax.validation.constraints.DecimalMax
import javax.validation.constraints.DecimalMin
import javax.validation.constraints.Max
import javax.validation.constraints.Min
import javax.validation.constraints.NotNull
import javax.validation.constraints.Pattern
import javax.validation.constraints.Size
import kotlin.collections.List import kotlin.collections.List
import kotlin.collections.Map import kotlin.collections.Map

View File

@ -1,7 +1,13 @@
package org.openapitools.api package org.openapitools.api
import org.openapitools.model.User import org.openapitools.model.User
import io.swagger.annotations.* import io.swagger.annotations.Api
import io.swagger.annotations.ApiOperation
import io.swagger.annotations.ApiParam
import io.swagger.annotations.ApiResponse
import io.swagger.annotations.ApiResponses
import io.swagger.annotations.Authorization
import io.swagger.annotations.AuthorizationScope
import org.springframework.http.HttpStatus import org.springframework.http.HttpStatus
import org.springframework.http.MediaType import org.springframework.http.MediaType
import org.springframework.http.ResponseEntity import org.springframework.http.ResponseEntity
@ -18,7 +24,13 @@ import org.springframework.web.context.request.NativeWebRequest
import org.springframework.beans.factory.annotation.Autowired import org.springframework.beans.factory.annotation.Autowired
import javax.validation.Valid import javax.validation.Valid
import javax.validation.constraints.* import javax.validation.constraints.DecimalMax
import javax.validation.constraints.DecimalMin
import javax.validation.constraints.Max
import javax.validation.constraints.Min
import javax.validation.constraints.NotNull
import javax.validation.constraints.Pattern
import javax.validation.constraints.Size
import kotlin.collections.List import kotlin.collections.List
import kotlin.collections.Map import kotlin.collections.Map

View File

@ -2,8 +2,13 @@ package org.openapitools.model
import java.util.Objects import java.util.Objects
import com.fasterxml.jackson.annotation.JsonProperty import com.fasterxml.jackson.annotation.JsonProperty
import javax.validation.Valid import javax.validation.constraints.DecimalMax
import javax.validation.constraints.* import javax.validation.constraints.DecimalMin
import javax.validation.constraints.Max
import javax.validation.constraints.Min
import javax.validation.constraints.NotNull
import javax.validation.constraints.Pattern
import javax.validation.constraints.Size
import io.swagger.annotations.ApiModelProperty import io.swagger.annotations.ApiModelProperty
/** /**

View File

@ -2,8 +2,13 @@ package org.openapitools.model
import java.util.Objects import java.util.Objects
import com.fasterxml.jackson.annotation.JsonProperty import com.fasterxml.jackson.annotation.JsonProperty
import javax.validation.Valid import javax.validation.constraints.DecimalMax
import javax.validation.constraints.* import javax.validation.constraints.DecimalMin
import javax.validation.constraints.Max
import javax.validation.constraints.Min
import javax.validation.constraints.NotNull
import javax.validation.constraints.Pattern
import javax.validation.constraints.Size
import io.swagger.annotations.ApiModelProperty import io.swagger.annotations.ApiModelProperty
/** /**

View File

@ -3,8 +3,13 @@ package org.openapitools.model
import java.util.Objects import java.util.Objects
import com.fasterxml.jackson.annotation.JsonProperty import com.fasterxml.jackson.annotation.JsonProperty
import com.fasterxml.jackson.annotation.JsonValue import com.fasterxml.jackson.annotation.JsonValue
import javax.validation.Valid import javax.validation.constraints.DecimalMax
import javax.validation.constraints.* import javax.validation.constraints.DecimalMin
import javax.validation.constraints.Max
import javax.validation.constraints.Min
import javax.validation.constraints.NotNull
import javax.validation.constraints.Pattern
import javax.validation.constraints.Size
import io.swagger.annotations.ApiModelProperty import io.swagger.annotations.ApiModelProperty
/** /**

View File

@ -5,8 +5,13 @@ import com.fasterxml.jackson.annotation.JsonProperty
import com.fasterxml.jackson.annotation.JsonValue import com.fasterxml.jackson.annotation.JsonValue
import org.openapitools.model.Category import org.openapitools.model.Category
import org.openapitools.model.Tag import org.openapitools.model.Tag
import javax.validation.Valid import javax.validation.constraints.DecimalMax
import javax.validation.constraints.* import javax.validation.constraints.DecimalMin
import javax.validation.constraints.Max
import javax.validation.constraints.Min
import javax.validation.constraints.NotNull
import javax.validation.constraints.Pattern
import javax.validation.constraints.Size
import io.swagger.annotations.ApiModelProperty import io.swagger.annotations.ApiModelProperty
/** /**

View File

@ -2,8 +2,13 @@ package org.openapitools.model
import java.util.Objects import java.util.Objects
import com.fasterxml.jackson.annotation.JsonProperty import com.fasterxml.jackson.annotation.JsonProperty
import javax.validation.Valid import javax.validation.constraints.DecimalMax
import javax.validation.constraints.* import javax.validation.constraints.DecimalMin
import javax.validation.constraints.Max
import javax.validation.constraints.Min
import javax.validation.constraints.NotNull
import javax.validation.constraints.Pattern
import javax.validation.constraints.Size
import io.swagger.annotations.ApiModelProperty import io.swagger.annotations.ApiModelProperty
/** /**

View File

@ -2,8 +2,13 @@ package org.openapitools.model
import java.util.Objects import java.util.Objects
import com.fasterxml.jackson.annotation.JsonProperty import com.fasterxml.jackson.annotation.JsonProperty
import javax.validation.Valid import javax.validation.constraints.DecimalMax
import javax.validation.constraints.* import javax.validation.constraints.DecimalMin
import javax.validation.constraints.Max
import javax.validation.constraints.Min
import javax.validation.constraints.NotNull
import javax.validation.constraints.Pattern
import javax.validation.constraints.Size
import io.swagger.annotations.ApiModelProperty import io.swagger.annotations.ApiModelProperty
/** /**