From 463d905664498ac0c4006a4b888c39c9359dbcba Mon Sep 17 00:00:00 2001 From: Sascha Peilicke Date: Sun, 20 Jun 2021 16:03:44 +0200 Subject: [PATCH] Kotlin-Server: Optional metrics and upgrade to Ktor 1.5.4 (#9358) Use Gradle 6.9 and Kotlin 1.4.32. Generate Paths for other HTTP verbs (#828) and fix imports (#5640). Use 'object' when no parameters are used. Introduce 'featureMetrics' to control metrics plugin usage. Remove HOCON configuration parsing. This is provided by `Application.environment.config already` and removes a dependency. Resolves #9087, resolves #828, resolves #5640 Relates-To #5346 --- docs/generators/kotlin-server.md | 1 + .../languages/KotlinServerCodegen.java | 26 +++++- .../libraries/ktor/AppMain.kt.mustache | 83 ++++++++----------- .../libraries/ktor/Configuration.kt.mustache | 22 +++-- .../libraries/ktor/Paths.kt.mustache | 14 ++-- .../libraries/ktor/README.mustache | 4 +- .../kotlin-server/libraries/ktor/api.mustache | 41 ++------- .../libraries/ktor/build.gradle.mustache | 66 ++++++++------- .../petstore/kotlin-server/ktor/README.md | 4 +- .../petstore/kotlin-server/ktor/build.gradle | 60 +++++++------- .../kotlin/org/openapitools/server/AppMain.kt | 45 ++++------ .../org/openapitools/server/Configuration.kt | 17 ++-- .../kotlin/org/openapitools/server/Paths.kt | 28 +------ .../org/openapitools/server/apis/PetApi.kt | 28 ++----- .../org/openapitools/server/apis/StoreApi.kt | 28 ++----- .../org/openapitools/server/apis/UserApi.kt | 28 ++----- 16 files changed, 202 insertions(+), 293 deletions(-) diff --git a/docs/generators/kotlin-server.md b/docs/generators/kotlin-server.md index b45dc3ffb4d2..7d9beb5ae101 100644 --- a/docs/generators/kotlin-server.md +++ b/docs/generators/kotlin-server.md @@ -17,6 +17,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl |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| |featureLocations|Generates routes in a typed way, for both: constructing URLs and reading the parameters.| |true| +|featureMetrics|Enables metrics feature.| |true| |groupId|Generated artifact package's organization (i.e. maven groupId).| |org.openapitools| |library|library template (sub-template)|
**ktor**
ktor framework
|ktor| |modelMutable|Create mutable models| |false| diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinServerCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinServerCodegen.java index c5063d991858..3ad47e68fee3 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinServerCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinServerCodegen.java @@ -34,7 +34,6 @@ import java.util.Map; public class KotlinServerCodegen extends AbstractKotlinCodegen { - public static final String DEFAULT_LIBRARY = Constants.KTOR; private final Logger LOGGER = LoggerFactory.getLogger(KotlinServerCodegen.class); private Boolean autoHeadFeatureEnabled = true; @@ -43,6 +42,7 @@ public class KotlinServerCodegen extends AbstractKotlinCodegen { private Boolean corsFeatureEnabled = false; private Boolean compressionFeatureEnabled = true; private Boolean locationsFeatureEnabled = true; + private Boolean metricsFeatureEnabled = true; // This is here to potentially warn the user when an option is not supported by the target framework. private Map> optionsSupportedPerFramework = new ImmutableMap.Builder>() @@ -52,7 +52,8 @@ public class KotlinServerCodegen extends AbstractKotlinCodegen { Constants.HSTS, Constants.CORS, Constants.COMPRESSION, - Constants.LOCATIONS + Constants.LOCATIONS, + Constants.METRICS )) .build(); @@ -115,6 +116,7 @@ public KotlinServerCodegen() { addSwitch(Constants.CORS, Constants.CORS_DESC, getCorsFeatureEnabled()); addSwitch(Constants.COMPRESSION, Constants.COMPRESSION_DESC, getCompressionFeatureEnabled()); addSwitch(Constants.LOCATIONS, Constants.LOCATIONS_DESC, getLocationsFeatureEnabled()); + addSwitch(Constants.METRICS, Constants.METRICS_DESC, getMetricsFeatureEnabled()); } public Boolean getAutoHeadFeatureEnabled() { @@ -169,6 +171,14 @@ public void setLocationsFeatureEnabled(Boolean locationsFeatureEnabled) { this.locationsFeatureEnabled = locationsFeatureEnabled; } + public Boolean getMetricsFeatureEnabled() { + return metricsFeatureEnabled; + } + + public void setMetricsFeatureEnabled(Boolean metricsEnabled) { + this.metricsFeatureEnabled = metricsEnabled; + } + public String getName() { return "kotlin-server"; } @@ -228,6 +238,12 @@ public void processOpts() { additionalProperties.put(Constants.LOCATIONS, getLocationsFeatureEnabled()); } + if (additionalProperties.containsKey(Constants.METRICS)) { + setMetricsFeatureEnabled(convertPropertyToBooleanAndWriteBack(Constants.METRICS)); + } else { + additionalProperties.put(Constants.METRICS, getMetricsFeatureEnabled()); + } + boolean generateApis = additionalProperties.containsKey(CodegenConstants.GENERATE_APIS) && (Boolean) additionalProperties.get(CodegenConstants.GENERATE_APIS); String packageFolder = (sourceFolder + File.separator + packageName).replace(".", File.separator); String resourcesFolder = "src/main/resources"; // not sure this can be user configurable. @@ -268,17 +284,19 @@ public static class Constants { public final static String COMPRESSION_DESC = "Adds ability to compress outgoing content using gzip, deflate or custom encoder and thus reduce size of the response."; public final static String LOCATIONS = "featureLocations"; public final static String LOCATIONS_DESC = "Generates routes in a typed way, for both: constructing URLs and reading the parameters."; + public final static String METRICS = "featureMetrics"; + public final static String METRICS_DESC = "Enables metrics feature."; } @Override public void postProcess() { System.out.println("################################################################################"); System.out.println("# Thanks for using OpenAPI Generator. #"); - System.out.println("# Please consider donation to help us maintain this project \uD83D\uDE4F #"); + System.out.println("# Please consider donation to help us maintain this project \uD83D\uDE4F #"); System.out.println("# https://opencollective.com/openapi_generator/donate #"); System.out.println("# #"); System.out.println("# This generator's contributed by Jim Schubert (https://github.com/jimschubert)#"); - System.out.println("# Please support his work directly via https://patreon.com/jimschubert \uD83D\uDE4F #"); + System.out.println("# Please support his work directly via https://patreon.com/jimschubert \uD83D\uDE4F #"); System.out.println("################################################################################"); } } diff --git a/modules/openapi-generator/src/main/resources/kotlin-server/libraries/ktor/AppMain.kt.mustache b/modules/openapi-generator/src/main/resources/kotlin-server/libraries/ktor/AppMain.kt.mustache index 1556c44ae58f..1dc57ad3b381 100644 --- a/modules/openapi-generator/src/main/resources/kotlin-server/libraries/ktor/AppMain.kt.mustache +++ b/modules/openapi-generator/src/main/resources/kotlin-server/libraries/ktor/AppMain.kt.mustache @@ -1,61 +1,47 @@ package {{packageName}} +{{#featureMetrics}} import com.codahale.metrics.Slf4jReporter -import com.typesafe.config.ConfigFactory -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.engine.apache.Apache -import io.ktor.config.HoconApplicationConfig -{{#featureAutoHead}} -import io.ktor.features.AutoHeadResponse -{{/featureAutoHead}} -{{#featureCompression}} -import io.ktor.features.Compression -{{/featureCompression}} -{{#featureCORS}} -import io.ktor.features.CORS -{{/featureCORS}} -{{#featureConditionalHeaders}} -import io.ktor.features.ConditionalHeaders -{{/featureConditionalHeaders}} -import io.ktor.features.ContentNegotiation -import io.ktor.features.DefaultHeaders -{{#featureHSTS}} -import io.ktor.features.HSTS -{{/featureHSTS}} -import io.ktor.gson.GsonConverter -import io.ktor.http.ContentType +{{/featureMetrics}} +import io.ktor.application.* +import io.ktor.features.* +import io.ktor.gson.* +import io.ktor.http.* {{#featureLocations}} -import io.ktor.locations.KtorExperimentalLocationsAPI -import io.ktor.locations.Locations +import io.ktor.locations.* {{/featureLocations}} -import io.ktor.routing.Routing +{{#featureMetrics}} +import io.ktor.metrics.dropwizard.* import java.util.concurrent.TimeUnit +{{/featureMetrics}} +import io.ktor.routing.* +import io.ktor.util.* {{#hasAuthMethods}} -import io.ktor.auth.Authentication -import io.ktor.auth.oauth -import io.ktor.metrics.dropwizard.DropwizardMetrics -import org.openapitools.server.infrastructure.ApiKeyCredential -import org.openapitools.server.infrastructure.ApiPrincipal -import org.openapitools.server.infrastructure.apiKeyAuth +import com.typesafe.config.ConfigFactory +import io.ktor.auth.* +import io.ktor.client.HttpClient +import io.ktor.client.engine.apache.Apache +import io.ktor.config.HoconApplicationConfig +import org.openapitools.server.infrastructure.* {{/hasAuthMethods}} {{#generateApis}}{{#apiInfo}}{{#apis}}import {{apiPackage}}.{{classname}} {{/apis}}{{/apiInfo}}{{/generateApis}} +{{#hasAuthMethods}} internal val settings = HoconApplicationConfig(ConfigFactory.defaultApplication(HTTP::class.java.classLoader)) object HTTP { val client = HttpClient(Apache) } +{{/hasAuthMethods}} +@KtorExperimentalAPI {{#featureLocations}} @KtorExperimentalLocationsAPI {{/featureLocations}} fun Application.main() { install(DefaultHeaders) + {{#featureMetrics}} install(DropwizardMetrics) { val reporter = Slf4jReporter.forRegistry(registry) .outputTo(log) @@ -64,27 +50,28 @@ fun Application.main() { .build() reporter.start(10, TimeUnit.SECONDS) } + {{/featureMetrics}} {{#generateApis}} install(ContentNegotiation) { register(ContentType.Application.Json, GsonConverter()) } {{#featureAutoHead}} - install(AutoHeadResponse) // see http://ktor.io/features/autoheadresponse.html + install(AutoHeadResponse) // see https://ktor.io/docs/autoheadresponse.html {{/featureAutoHead}} {{#featureConditionalHeaders}} - install(ConditionalHeaders) // see http://ktor.io/features/conditional-headers.html + install(ConditionalHeaders) // see https://ktor.io/docs/conditional-headers.html {{/featureConditionalHeaders}} - {{#featureHSTS}} - install(HSTS, ApplicationHstsConfiguration()) // see http://ktor.io/features/hsts.html - {{/featureHSTS}} - {{#featureCORS}} - install(CORS, ApplicationCORSConfiguration()) // see http://ktor.io/features/cors.html - {{/featureCORS}} {{#featureCompression}} - install(Compression, ApplicationCompressionConfiguration()) // see http://ktor.io/features/compression.html + install(Compression, ApplicationCompressionConfiguration()) // see https://ktor.io/docs/compression.html {{/featureCompression}} + {{#featureCORS}} + install(CORS, ApplicationCORSConfiguration()) // see https://ktor.io/docs/cors.html + {{/featureCORS}} + {{#featureHSTS}} + install(HSTS, ApplicationHstsConfiguration()) // see https://ktor.io/docs/hsts.html + {{/featureHSTS}} {{#featureLocations}} - install(Locations) // see http://ktor.io/features/locations.html + install(Locations) // see https://ktor.io/docs/features-locations.html {{/featureLocations}} {{#hasAuthMethods}} install(Authentication) { @@ -140,8 +127,4 @@ fun Application.main() { } {{/generateApis}} - - environment.monitor.subscribe(ApplicationStopping) { - HTTP.client.close() - } } diff --git a/modules/openapi-generator/src/main/resources/kotlin-server/libraries/ktor/Configuration.kt.mustache b/modules/openapi-generator/src/main/resources/kotlin-server/libraries/ktor/Configuration.kt.mustache index a8956ec59052..76a07ce208fa 100644 --- a/modules/openapi-generator/src/main/resources/kotlin-server/libraries/ktor/Configuration.kt.mustache +++ b/modules/openapi-generator/src/main/resources/kotlin-server/libraries/ktor/Configuration.kt.mustache @@ -1,16 +1,14 @@ package {{packageName}} // 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.features.Compression -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.auth.* +import io.ktor.features.* +import io.ktor.http.* +import io.ktor.util.* +import java.time.Duration import java.util.concurrent.TimeUnit - {{#featureCORS}} + /** * Application block for [CORS] configuration. * @@ -33,8 +31,8 @@ internal fun ApplicationCORSConfiguration(): CORS.Configuration.() -> Unit { } } {{/featureCORS}} - {{#featureHSTS}} + /** * Application block for [HSTS] configuration. * @@ -54,8 +52,8 @@ internal fun ApplicationHstsConfiguration(): HSTS.Configuration.() -> Unit { } } {{/featureHSTS}} - {{#featureCompression}} + /** * Application block for [Compression] configuration. * @@ -99,8 +97,8 @@ val ApplicationAuthProviders: Map = listOflicenseInfo}} package {{packageName}} -import io.ktor.locations.KtorExperimentalLocationsAPI -import io.ktor.locations.Location +import io.ktor.locations.* import {{packageName}}.models.* {{#imports}}import {{import}} {{/imports}} {{#apiInfo}} +@KtorExperimentalLocationsAPI object Paths { {{#apis}} {{#operations}} {{#operation}} - /** - * {{summary}} + /**{{#summary}} + * {{summary}}{{/summary}} * {{#unescapedNotes}}{{.}}{{/unescapedNotes}} {{#allParams}}* @param {{paramName}} {{description}} {{^required}}(optional{{#defaultValue}}, default to {{{.}}}{{/defaultValue}}){{/required}} {{/allParams}}*/ - @KtorExperimentalLocationsAPI + {{#hasParams}} @Location("{{path}}") class {{operationId}}({{#allParams}}val {{paramName}}: {{{dataType}}}{{^required}}? = null{{/required}}{{#required}}{{#isNullable}}?{{/isNullable}}{{/required}}{{^-last}}, {{/-last}}{{/allParams}}) + {{/hasParams}} + {{^hasParams}} + @Location("{{path}}") object {{operationId}} + {{/hasParams}} {{/operation}} {{/operations}} diff --git a/modules/openapi-generator/src/main/resources/kotlin-server/libraries/ktor/README.mustache b/modules/openapi-generator/src/main/resources/kotlin-server/libraries/ktor/README.mustache index f12148e1d394..2763aa259aa8 100644 --- a/modules/openapi-generator/src/main/resources/kotlin-server/libraries/ktor/README.mustache +++ b/modules/openapi-generator/src/main/resources/kotlin-server/libraries/ktor/README.mustache @@ -8,8 +8,8 @@ Generated by OpenAPI Generator {{generatorVersion}}{{^hideGenerationTimestamp}} ## Requires -* Kotlin 1.4.31 -* Gradle 6.8.2 +* Kotlin 1.4.32 +* Gradle 6.9 ## Build diff --git a/modules/openapi-generator/src/main/resources/kotlin-server/libraries/ktor/api.mustache b/modules/openapi-generator/src/main/resources/kotlin-server/libraries/ktor/api.mustache index a3d8c124e817..ba7eccdee567 100644 --- a/modules/openapi-generator/src/main/resources/kotlin-server/libraries/ktor/api.mustache +++ b/modules/openapi-generator/src/main/resources/kotlin-server/libraries/ktor/api.mustache @@ -2,50 +2,27 @@ package {{apiPackage}} import com.google.gson.Gson -import io.ktor.application.call -import io.ktor.auth.UserIdPrincipal -import io.ktor.auth.authentication -import io.ktor.auth.authenticate -import io.ktor.auth.OAuthAccessTokenResponse -import io.ktor.auth.OAuthServerSettings -import io.ktor.http.ContentType -import io.ktor.http.HttpStatusCode -import io.ktor.response.respond -import io.ktor.response.respondText -import io.ktor.routing.Route +import io.ktor.application.* +import io.ktor.auth.* +import io.ktor.http.* +import io.ktor.response.* {{#featureLocations}} import {{packageName}}.Paths -import io.ktor.locations.KtorExperimentalLocationsAPI -import io.ktor.locations.delete -import io.ktor.locations.get -import io.ktor.locations.post -import io.ktor.locations.put -import io.ktor.locations.options -import io.ktor.locations.head +import io.ktor.locations.* {{/featureLocations}} -{{^featureLocations}} -import io.ktor.routing.delete -import io.ktor.routing.get -import io.ktor.routing.post -import io.ktor.routing.put -import io.ktor.routing.options -import io.ktor.routing.head -import io.ktor.routing.route -{{/featureLocations}} - +import io.ktor.routing.* import {{packageName}}.infrastructure.ApiPrincipal - - {{#imports}}import {{import}} {{/imports}} {{#operations}} - {{#featureLocations}} +{{#featureLocations}} @KtorExperimentalLocationsAPI - {{/featureLocations}} +{{/featureLocations}} fun Route.{{classname}}() { val gson = Gson() val empty = mutableMapOf() + {{#operation}} {{#hasAuthMethods}} {{#authMethods}} diff --git a/modules/openapi-generator/src/main/resources/kotlin-server/libraries/ktor/build.gradle.mustache b/modules/openapi-generator/src/main/resources/kotlin-server/libraries/ktor/build.gradle.mustache index 173686fdf88d..8d8948d689c5 100644 --- a/modules/openapi-generator/src/main/resources/kotlin-server/libraries/ktor/build.gradle.mustache +++ b/modules/openapi-generator/src/main/resources/kotlin-server/libraries/ktor/build.gradle.mustache @@ -1,37 +1,35 @@ -group '{{groupId}}' -version '{{artifactVersion}}' +group "{{groupId}}" +version "{{artifactVersion}}" wrapper { - gradleVersion = '6.8.2' + gradleVersion = "6.9" distributionUrl = "https://services.gradle.org/distributions/gradle-$gradleVersion-all.zip" } buildscript { - ext.kotlin_version = '1.4.31' - ext.ktor_version = '1.5.2' - ext.shadow_version = '2.0.3' + ext.kotlin_version = "1.4.32" + ext.ktor_version = "1.5.4" + ext.shadow_version = "6.1.0" repositories { maven { url "https://repo1.maven.org/maven2" } - maven { - url = "https://plugins.gradle.org/m2/" - } + maven { url "https://plugins.gradle.org/m2/" } } dependencies { - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" - classpath "com.github.jengelman.gradle.plugins:shadow:$shadow_version" + classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version") + classpath("com.github.jengelman.gradle.plugins:shadow:$shadow_version") } } -apply plugin: 'java' -apply plugin: 'kotlin' -apply plugin: 'application' +apply plugin: "java" +apply plugin: "kotlin" +apply plugin: "application" mainClassName = "io.ktor.server.netty.DevelopmentEngine" -// Initialization order with shadow 2.0.1 and Gradle 6.8.2 is weird. +// Initialization order with shadow 2.0.1 and Gradle 6.9 is weird. // See https://github.com/johnrengelman/shadow/issues/336#issuecomment-355402508 -apply plugin: 'com.github.johnrengelman.shadow' +apply plugin: "com.github.johnrengelman.shadow" sourceCompatibility = 1.8 @@ -44,28 +42,36 @@ compileTestKotlin { } shadowJar { - baseName = '{{artifactId}}' + baseName = "{{artifactId}}" classifier = null version = null } repositories { - maven { url "https://repo1.maven.org/maven2" } - maven { url "https://dl.bintray.com/kotlin/ktor" } - maven { url "https://dl.bintray.com/kotlin/kotlinx" } + maven { setUrl("https://repo1.maven.org/maven2") } + maven { setUrl("https://dl.bintray.com/kotlin/ktor") } + maven { setUrl("https://dl.bintray.com/kotlin/kotlinx") } } dependencies { - compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" - compile "io.ktor:ktor-server-netty:$ktor_version" - compile "io.ktor:ktor-metrics:$ktor_version" - compile "io.ktor:ktor-auth:$ktor_version" + implementation("org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version") + implementation("ch.qos.logback:logback-classic:1.2.1") +{{#hasAuthMethods}} + implementation("com.typesafe:config:1.4.1") +{{/hasAuthMethods}} + implementation("io.ktor:ktor-auth:$ktor_version") +{{#hasAuthMethods}} + implementation("io.ktor:ktor-client-apache:$ktor_version") +{{/hasAuthMethods}} + implementation("io.ktor:ktor-gson:$ktor_version") {{#featureLocations}} - compile "io.ktor:ktor-locations:$ktor_version" + implementation("io.ktor:ktor-locations:$ktor_version") {{/featureLocations}} - compile "io.ktor:ktor-gson:$ktor_version" - compile "io.ktor:ktor-client-core:$ktor_version" - compile "io.ktor:ktor-client-apache:$ktor_version" - compile "ch.qos.logback:logback-classic:1.2.1" - testCompile group: 'junit', name: 'junit', version: '4.13' +{{#featureMetrics}} + implementation("io.dropwizard.metrics:metrics-core:4.1.18") + implementation("io.ktor:ktor-metrics:$ktor_version") +{{/featureMetrics}} + implementation("io.ktor:ktor-server-netty:$ktor_version") + + testImplementation("junit:junit:4.13.2") } diff --git a/samples/server/petstore/kotlin-server/ktor/README.md b/samples/server/petstore/kotlin-server/ktor/README.md index 0312e13cdf7c..c18e00d6d352 100644 --- a/samples/server/petstore/kotlin-server/ktor/README.md +++ b/samples/server/petstore/kotlin-server/ktor/README.md @@ -6,8 +6,8 @@ Generated by OpenAPI Generator 5.2.0-SNAPSHOT. ## Requires -* Kotlin 1.4.31 -* Gradle 6.8.2 +* Kotlin 1.4.32 +* Gradle 6.9 ## Build diff --git a/samples/server/petstore/kotlin-server/ktor/build.gradle b/samples/server/petstore/kotlin-server/ktor/build.gradle index c69f129160f5..ebf0c9880680 100644 --- a/samples/server/petstore/kotlin-server/ktor/build.gradle +++ b/samples/server/petstore/kotlin-server/ktor/build.gradle @@ -1,37 +1,35 @@ -group 'org.openapitools' -version '1.0.0' +group "org.openapitools" +version "1.0.0" wrapper { - gradleVersion = '6.8.2' + gradleVersion = "6.9" distributionUrl = "https://services.gradle.org/distributions/gradle-$gradleVersion-all.zip" } buildscript { - ext.kotlin_version = '1.4.31' - ext.ktor_version = '1.5.2' - ext.shadow_version = '2.0.3' + ext.kotlin_version = "1.4.32" + ext.ktor_version = "1.5.4" + ext.shadow_version = "6.1.0" repositories { maven { url "https://repo1.maven.org/maven2" } - maven { - url = "https://plugins.gradle.org/m2/" - } + maven { url "https://plugins.gradle.org/m2/" } } dependencies { - classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" - classpath "com.github.jengelman.gradle.plugins:shadow:$shadow_version" + classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version") + classpath("com.github.jengelman.gradle.plugins:shadow:$shadow_version") } } -apply plugin: 'java' -apply plugin: 'kotlin' -apply plugin: 'application' +apply plugin: "java" +apply plugin: "kotlin" +apply plugin: "application" mainClassName = "io.ktor.server.netty.DevelopmentEngine" -// Initialization order with shadow 2.0.1 and Gradle 6.8.2 is weird. +// Initialization order with shadow 2.0.1 and Gradle 6.9 is weird. // See https://github.com/johnrengelman/shadow/issues/336#issuecomment-355402508 -apply plugin: 'com.github.johnrengelman.shadow' +apply plugin: "com.github.johnrengelman.shadow" sourceCompatibility = 1.8 @@ -44,26 +42,28 @@ compileTestKotlin { } shadowJar { - baseName = 'kotlin-server' + baseName = "kotlin-server" classifier = null version = null } repositories { - maven { url "https://repo1.maven.org/maven2" } - maven { url "https://dl.bintray.com/kotlin/ktor" } - maven { url "https://dl.bintray.com/kotlin/kotlinx" } + maven { setUrl("https://repo1.maven.org/maven2") } + maven { setUrl("https://dl.bintray.com/kotlin/ktor") } + maven { setUrl("https://dl.bintray.com/kotlin/kotlinx") } } dependencies { - compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version" - compile "io.ktor:ktor-server-netty:$ktor_version" - compile "io.ktor:ktor-metrics:$ktor_version" - compile "io.ktor:ktor-auth:$ktor_version" - compile "io.ktor:ktor-locations:$ktor_version" - compile "io.ktor:ktor-gson:$ktor_version" - compile "io.ktor:ktor-client-core:$ktor_version" - compile "io.ktor:ktor-client-apache:$ktor_version" - compile "ch.qos.logback:logback-classic:1.2.1" - testCompile group: 'junit', name: 'junit', version: '4.13' + implementation("org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version") + implementation("ch.qos.logback:logback-classic:1.2.1") + implementation("com.typesafe:config:1.4.1") + implementation("io.ktor:ktor-auth:$ktor_version") + implementation("io.ktor:ktor-client-apache:$ktor_version") + implementation("io.ktor:ktor-gson:$ktor_version") + implementation("io.ktor:ktor-locations:$ktor_version") + implementation("io.dropwizard.metrics:metrics-core:4.1.18") + implementation("io.ktor:ktor-metrics:$ktor_version") + implementation("io.ktor:ktor-server-netty:$ktor_version") + + testImplementation("junit:junit:4.13.2") } diff --git a/samples/server/petstore/kotlin-server/ktor/src/main/kotlin/org/openapitools/server/AppMain.kt b/samples/server/petstore/kotlin-server/ktor/src/main/kotlin/org/openapitools/server/AppMain.kt index 54658d6ba5df..9b0468fb5684 100644 --- a/samples/server/petstore/kotlin-server/ktor/src/main/kotlin/org/openapitools/server/AppMain.kt +++ b/samples/server/petstore/kotlin-server/ktor/src/main/kotlin/org/openapitools/server/AppMain.kt @@ -1,31 +1,21 @@ package org.openapitools.server import com.codahale.metrics.Slf4jReporter +import io.ktor.application.* +import io.ktor.features.* +import io.ktor.gson.* +import io.ktor.http.* +import io.ktor.locations.* +import io.ktor.metrics.dropwizard.* +import java.util.concurrent.TimeUnit +import io.ktor.routing.* +import io.ktor.util.* import com.typesafe.config.ConfigFactory -import io.ktor.application.Application -import io.ktor.application.ApplicationStopping -import io.ktor.application.install -import io.ktor.application.log +import io.ktor.auth.* import io.ktor.client.HttpClient import io.ktor.client.engine.apache.Apache import io.ktor.config.HoconApplicationConfig -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.http.ContentType -import io.ktor.locations.KtorExperimentalLocationsAPI -import io.ktor.locations.Locations -import io.ktor.routing.Routing -import java.util.concurrent.TimeUnit -import io.ktor.auth.Authentication -import io.ktor.auth.oauth -import io.ktor.metrics.dropwizard.DropwizardMetrics -import org.openapitools.server.infrastructure.ApiKeyCredential -import org.openapitools.server.infrastructure.ApiPrincipal -import org.openapitools.server.infrastructure.apiKeyAuth +import org.openapitools.server.infrastructure.* import org.openapitools.server.apis.PetApi import org.openapitools.server.apis.StoreApi import org.openapitools.server.apis.UserApi @@ -37,6 +27,7 @@ object HTTP { val client = HttpClient(Apache) } +@KtorExperimentalAPI @KtorExperimentalLocationsAPI fun Application.main() { install(DefaultHeaders) @@ -51,10 +42,10 @@ fun Application.main() { install(ContentNegotiation) { register(ContentType.Application.Json, GsonConverter()) } - install(AutoHeadResponse) // see http://ktor.io/features/autoheadresponse.html - install(HSTS, ApplicationHstsConfiguration()) // see http://ktor.io/features/hsts.html - install(Compression, ApplicationCompressionConfiguration()) // see http://ktor.io/features/compression.html - install(Locations) // see http://ktor.io/features/locations.html + install(AutoHeadResponse) // see https://ktor.io/docs/autoheadresponse.html + install(Compression, ApplicationCompressionConfiguration()) // see https://ktor.io/docs/compression.html + install(HSTS, ApplicationHstsConfiguration()) // see https://ktor.io/docs/hsts.html + install(Locations) // see https://ktor.io/docs/features-locations.html install(Authentication) { // "Implement API key auth (api_key) for parameter name 'api_key'." apiKeyAuth("api_key") { @@ -80,8 +71,4 @@ fun Application.main() { UserApi() } - - environment.monitor.subscribe(ApplicationStopping) { - HTTP.client.close() - } } diff --git a/samples/server/petstore/kotlin-server/ktor/src/main/kotlin/org/openapitools/server/Configuration.kt b/samples/server/petstore/kotlin-server/ktor/src/main/kotlin/org/openapitools/server/Configuration.kt index 8483e64319d0..93aa1c728227 100644 --- a/samples/server/petstore/kotlin-server/ktor/src/main/kotlin/org/openapitools/server/Configuration.kt +++ b/samples/server/petstore/kotlin-server/ktor/src/main/kotlin/org/openapitools/server/Configuration.kt @@ -1,16 +1,13 @@ package org.openapitools.server // 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.features.Compression -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.auth.* +import io.ktor.features.* +import io.ktor.http.* +import io.ktor.util.* +import java.time.Duration import java.util.concurrent.TimeUnit - /** * Application block for [HSTS] configuration. * @@ -67,8 +64,8 @@ val ApplicationAuthProviders: Map = listOf) /** @@ -46,7 +43,6 @@ object Paths { * Multiple tags can be provided with comma separated strings. Use tag1, tag2, tag3 for testing. * @param tags Tags to filter by */ - @KtorExperimentalLocationsAPI @Location("/pet/findByTags") class findPetsByTags(val tags: kotlin.collections.List) /** @@ -54,7 +50,6 @@ object Paths { * Returns a single pet * @param petId ID of pet to return */ - @KtorExperimentalLocationsAPI @Location("/pet/{petId}") class getPetById(val petId: kotlin.Long) /** @@ -62,7 +57,6 @@ object Paths { * * @param body Pet object that needs to be added to the store */ - @KtorExperimentalLocationsAPI @Location("/pet") class updatePet(val body: Pet) /** @@ -72,7 +66,6 @@ object Paths { * @param name Updated name of the pet (optional) * @param status Updated status of the pet (optional) */ - @KtorExperimentalLocationsAPI @Location("/pet/{petId}") class updatePetWithForm(val petId: kotlin.Long, val name: kotlin.String? = null, val status: kotlin.String? = null) /** @@ -82,7 +75,6 @@ object Paths { * @param additionalMetadata Additional data to pass to server (optional) * @param file file to upload (optional) */ - @KtorExperimentalLocationsAPI @Location("/pet/{petId}/uploadImage") class uploadFile(val petId: kotlin.Long, val additionalMetadata: kotlin.String? = null, val file: java.io.File? = null) /** @@ -90,22 +82,19 @@ object Paths { * For valid response try integer IDs with value < 1000. Anything above 1000 or nonintegers will generate API errors * @param orderId ID of the order that needs to be deleted */ - @KtorExperimentalLocationsAPI @Location("/store/order/{orderId}") class deleteOrder(val orderId: kotlin.String) /** * Returns pet inventories by status * Returns a map of status codes to quantities */ - @KtorExperimentalLocationsAPI - @Location("/store/inventory") class getInventory() + @Location("/store/inventory") object getInventory /** * Find purchase order by ID * For valid response try integer IDs with value <= 5 or > 10. Other values will generated exceptions * @param orderId ID of pet that needs to be fetched */ - @KtorExperimentalLocationsAPI @Location("/store/order/{orderId}") class getOrderById(val orderId: kotlin.Long) /** @@ -113,7 +102,6 @@ object Paths { * * @param body order placed for purchasing the pet */ - @KtorExperimentalLocationsAPI @Location("/store/order") class placeOrder(val body: Order) /** @@ -121,7 +109,6 @@ object Paths { * This can only be done by the logged in user. * @param body Created user object */ - @KtorExperimentalLocationsAPI @Location("/user") class createUser(val body: User) /** @@ -129,7 +116,6 @@ object Paths { * * @param body List of user object */ - @KtorExperimentalLocationsAPI @Location("/user/createWithArray") class createUsersWithArrayInput(val body: kotlin.collections.List) /** @@ -137,7 +123,6 @@ object Paths { * * @param body List of user object */ - @KtorExperimentalLocationsAPI @Location("/user/createWithList") class createUsersWithListInput(val body: kotlin.collections.List) /** @@ -145,7 +130,6 @@ object Paths { * This can only be done by the logged in user. * @param username The name that needs to be deleted */ - @KtorExperimentalLocationsAPI @Location("/user/{username}") class deleteUser(val username: kotlin.String) /** @@ -153,7 +137,6 @@ object Paths { * * @param username The name that needs to be fetched. Use user1 for testing. */ - @KtorExperimentalLocationsAPI @Location("/user/{username}") class getUserByName(val username: kotlin.String) /** @@ -162,15 +145,13 @@ object Paths { * @param username The user name for login * @param password The password for login in clear text */ - @KtorExperimentalLocationsAPI @Location("/user/login") class loginUser(val username: kotlin.String, val password: kotlin.String) /** * Logs out current logged in user session * */ - @KtorExperimentalLocationsAPI - @Location("/user/logout") class logoutUser() + @Location("/user/logout") object logoutUser /** * Updated user @@ -178,7 +159,6 @@ object Paths { * @param username name that need to be deleted * @param body Updated user object */ - @KtorExperimentalLocationsAPI @Location("/user/{username}") class updateUser(val username: kotlin.String, val body: User) } diff --git a/samples/server/petstore/kotlin-server/ktor/src/main/kotlin/org/openapitools/server/apis/PetApi.kt b/samples/server/petstore/kotlin-server/ktor/src/main/kotlin/org/openapitools/server/apis/PetApi.kt index 9226541eb34e..95f5d7fb8808 100644 --- a/samples/server/petstore/kotlin-server/ktor/src/main/kotlin/org/openapitools/server/apis/PetApi.kt +++ b/samples/server/petstore/kotlin-server/ktor/src/main/kotlin/org/openapitools/server/apis/PetApi.kt @@ -12,29 +12,14 @@ package org.openapitools.server.apis import com.google.gson.Gson -import io.ktor.application.call -import io.ktor.auth.UserIdPrincipal -import io.ktor.auth.authentication -import io.ktor.auth.authenticate -import io.ktor.auth.OAuthAccessTokenResponse -import io.ktor.auth.OAuthServerSettings -import io.ktor.http.ContentType -import io.ktor.http.HttpStatusCode -import io.ktor.response.respond -import io.ktor.response.respondText -import io.ktor.routing.Route +import io.ktor.application.* +import io.ktor.auth.* +import io.ktor.http.* +import io.ktor.response.* import org.openapitools.server.Paths -import io.ktor.locations.KtorExperimentalLocationsAPI -import io.ktor.locations.delete -import io.ktor.locations.get -import io.ktor.locations.post -import io.ktor.locations.put -import io.ktor.locations.options -import io.ktor.locations.head - +import io.ktor.locations.* +import io.ktor.routing.* import org.openapitools.server.infrastructure.ApiPrincipal - - import org.openapitools.server.models.ApiResponse import org.openapitools.server.models.Pet @@ -42,6 +27,7 @@ import org.openapitools.server.models.Pet fun Route.PetApi() { val gson = Gson() val empty = mutableMapOf() + authenticate("petstore_auth") { post { val principal = call.authentication.principal()!! diff --git a/samples/server/petstore/kotlin-server/ktor/src/main/kotlin/org/openapitools/server/apis/StoreApi.kt b/samples/server/petstore/kotlin-server/ktor/src/main/kotlin/org/openapitools/server/apis/StoreApi.kt index 2e5f4ab8b96c..b195797a0203 100644 --- a/samples/server/petstore/kotlin-server/ktor/src/main/kotlin/org/openapitools/server/apis/StoreApi.kt +++ b/samples/server/petstore/kotlin-server/ktor/src/main/kotlin/org/openapitools/server/apis/StoreApi.kt @@ -12,35 +12,21 @@ package org.openapitools.server.apis import com.google.gson.Gson -import io.ktor.application.call -import io.ktor.auth.UserIdPrincipal -import io.ktor.auth.authentication -import io.ktor.auth.authenticate -import io.ktor.auth.OAuthAccessTokenResponse -import io.ktor.auth.OAuthServerSettings -import io.ktor.http.ContentType -import io.ktor.http.HttpStatusCode -import io.ktor.response.respond -import io.ktor.response.respondText -import io.ktor.routing.Route +import io.ktor.application.* +import io.ktor.auth.* +import io.ktor.http.* +import io.ktor.response.* import org.openapitools.server.Paths -import io.ktor.locations.KtorExperimentalLocationsAPI -import io.ktor.locations.delete -import io.ktor.locations.get -import io.ktor.locations.post -import io.ktor.locations.put -import io.ktor.locations.options -import io.ktor.locations.head - +import io.ktor.locations.* +import io.ktor.routing.* import org.openapitools.server.infrastructure.ApiPrincipal - - import org.openapitools.server.models.Order @KtorExperimentalLocationsAPI fun Route.StoreApi() { val gson = Gson() val empty = mutableMapOf() + delete { call.respond(HttpStatusCode.NotImplemented) } diff --git a/samples/server/petstore/kotlin-server/ktor/src/main/kotlin/org/openapitools/server/apis/UserApi.kt b/samples/server/petstore/kotlin-server/ktor/src/main/kotlin/org/openapitools/server/apis/UserApi.kt index e248d75ae0cc..1871c4b30975 100644 --- a/samples/server/petstore/kotlin-server/ktor/src/main/kotlin/org/openapitools/server/apis/UserApi.kt +++ b/samples/server/petstore/kotlin-server/ktor/src/main/kotlin/org/openapitools/server/apis/UserApi.kt @@ -12,35 +12,21 @@ package org.openapitools.server.apis import com.google.gson.Gson -import io.ktor.application.call -import io.ktor.auth.UserIdPrincipal -import io.ktor.auth.authentication -import io.ktor.auth.authenticate -import io.ktor.auth.OAuthAccessTokenResponse -import io.ktor.auth.OAuthServerSettings -import io.ktor.http.ContentType -import io.ktor.http.HttpStatusCode -import io.ktor.response.respond -import io.ktor.response.respondText -import io.ktor.routing.Route +import io.ktor.application.* +import io.ktor.auth.* +import io.ktor.http.* +import io.ktor.response.* import org.openapitools.server.Paths -import io.ktor.locations.KtorExperimentalLocationsAPI -import io.ktor.locations.delete -import io.ktor.locations.get -import io.ktor.locations.post -import io.ktor.locations.put -import io.ktor.locations.options -import io.ktor.locations.head - +import io.ktor.locations.* +import io.ktor.routing.* import org.openapitools.server.infrastructure.ApiPrincipal - - import org.openapitools.server.models.User @KtorExperimentalLocationsAPI fun Route.UserApi() { val gson = Gson() val empty = mutableMapOf() + post { call.respond(HttpStatusCode.NotImplemented) }