Keep old Ktor server generator for backward compatibility (#9365)

This commit is contained in:
Rustam 2021-04-29 02:26:57 +02:00 committed by GitHub
parent 53398a0850
commit ccbb78e1b2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
58 changed files with 2759 additions and 0 deletions

View File

@ -0,0 +1,8 @@
generatorName: kotlin-server-deprecated
outputDir: samples/server/petstore/kotlin-server-deprecated/ktor
library: ktor
inputSpec: modules/openapi-generator/src/test/resources/2_0/petstore.yaml
templateDir: modules/openapi-generator/src/main/resources/kotlin-server-deprecated
additionalProperties:
hideGenerationTimestamp: "true"
serializableModel: "true"

View File

@ -106,6 +106,7 @@ The following generators are available:
* [jaxrs-resteasy-eap](generators/jaxrs-resteasy-eap.md)
* [jaxrs-spec](generators/jaxrs-spec.md)
* [kotlin-server](generators/kotlin-server.md)
* [kotlin-server-deprecated](generators/kotlin-server-deprecated.md)
* [kotlin-spring](generators/kotlin-spring.md)
* [kotlin-vertx (beta)](generators/kotlin-vertx.md)
* [nodejs-express-server (beta)](generators/nodejs-express-server.md)

View File

@ -91,6 +91,7 @@ The following generators are available:
* [jaxrs-resteasy-eap](jaxrs-resteasy-eap.md)
* [jaxrs-spec](jaxrs-spec.md)
* [kotlin-server](kotlin-server.md)
* [kotlin-server-deprecated](kotlin-server-deprecated.md)
* [kotlin-spring](kotlin-spring.md)
* [kotlin-vertx (beta)](kotlin-vertx.md)
* [nodejs-express-server (beta)](nodejs-express-server.md)

View File

@ -0,0 +1,214 @@
---
title: Config Options for kotlin-server-deprecated
sidebar_label: kotlin-server-deprecated
---
These options may be applied as additional-properties (cli) or configOptions (plugins). Refer to [configuration docs](https://openapi-generator.tech/docs/configuration) for more details.
| Option | Description | Values | Default |
| ------ | ----------- | ------ | ------- |
|apiSuffix|suffix for api classes| |Api|
|artifactId|Generated artifact id (name of jar).| |kotlin-server-deprecated|
|artifactVersion|Generated artifact's package version.| |1.0.0|
|enumPropertyNaming|Naming convention for enum properties: 'camelCase', 'PascalCase', 'snake_case', 'UPPERCASE', and 'original'| |camelCase|
|featureAutoHead|Automatically provide responses to HEAD requests for existing routes that have the GET verb defined.| |true|
|featureCORS|Ktor by default provides an interceptor for implementing proper support for Cross-Origin Resource Sharing (CORS). See enable-cors.org.| |false|
|featureCompression|Adds ability to compress outgoing content using gzip, deflate or custom encoder and thus reduce size of the response.| |true|
|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|
|groupId|Generated artifact package's organization (i.e. maven groupId).| |org.openapitools|
|library|library template (sub-template)|<dl><dt>**ktor**</dt><dd>ktor framework</dd></dl>|ktor|
|modelMutable|Create mutable models| |false|
|packageName|Generated artifact package name.| |org.openapitools.server|
|parcelizeModels|toggle &quot;@Parcelize&quot; for generated models| |null|
|serializableModel|boolean - toggle &quot;implements Serializable&quot; for generated models| |null|
|serializationLibrary|What serialization library to use: 'moshi' (default), or 'gson' or 'jackson'| |moshi|
|sortModelPropertiesByRequiredFlag|Sort model properties to place required parameters before optional parameters.| |null|
|sortParamsByRequiredFlag|Sort method arguments to place required parameters before optional parameters.| |null|
|sourceFolder|source folder for generated code| |src/main/kotlin|
## IMPORT MAPPING
| Type/Alias | Imports |
| ---------- | ------- |
|BigDecimal|java.math.BigDecimal|
|Date|java.time.LocalDate|
|DateTime|java.time.OffsetDateTime|
|File|java.io.File|
|LocalDate|java.time.LocalDate|
|LocalDateTime|java.time.LocalDateTime|
|LocalTime|java.time.LocalTime|
|Timestamp|java.sql.Timestamp|
|URI|java.net.URI|
|UUID|java.util.UUID|
## INSTANTIATION TYPES
| Type/Alias | Instantiated By |
| ---------- | --------------- |
|array|kotlin.collections.ArrayList|
|list|kotlin.collections.ArrayList|
|map|kotlin.collections.HashMap|
## LANGUAGE PRIMITIVES
<ul class="column-ul">
<li>kotlin.Array</li>
<li>kotlin.Boolean</li>
<li>kotlin.Byte</li>
<li>kotlin.ByteArray</li>
<li>kotlin.Char</li>
<li>kotlin.Double</li>
<li>kotlin.Float</li>
<li>kotlin.Int</li>
<li>kotlin.Long</li>
<li>kotlin.Short</li>
<li>kotlin.String</li>
<li>kotlin.collections.List</li>
<li>kotlin.collections.Map</li>
<li>kotlin.collections.Set</li>
</ul>
## RESERVED WORDS
<ul class="column-ul">
<li>as</li>
<li>break</li>
<li>class</li>
<li>continue</li>
<li>do</li>
<li>else</li>
<li>false</li>
<li>for</li>
<li>fun</li>
<li>if</li>
<li>in</li>
<li>interface</li>
<li>is</li>
<li>null</li>
<li>object</li>
<li>package</li>
<li>return</li>
<li>super</li>
<li>this</li>
<li>throw</li>
<li>true</li>
<li>try</li>
<li>typealias</li>
<li>typeof</li>
<li>val</li>
<li>var</li>
<li>when</li>
<li>while</li>
</ul>
## FEATURE SET
### Client Modification Feature
| Name | Supported | Defined By |
| ---- | --------- | ---------- |
|BasePath|✗|ToolingExtension
|Authorizations|✗|ToolingExtension
|UserAgent|✗|ToolingExtension
|MockServer|✗|ToolingExtension
### Data Type Feature
| Name | Supported | Defined By |
| ---- | --------- | ---------- |
|Custom|✗|OAS2,OAS3
|Int32|✓|OAS2,OAS3
|Int64|✓|OAS2,OAS3
|Float|✓|OAS2,OAS3
|Double|✓|OAS2,OAS3
|Decimal|✓|ToolingExtension
|String|✓|OAS2,OAS3
|Byte|✓|OAS2,OAS3
|Binary|✓|OAS2,OAS3
|Boolean|✓|OAS2,OAS3
|Date|✓|OAS2,OAS3
|DateTime|✓|OAS2,OAS3
|Password|✓|OAS2,OAS3
|File|✓|OAS2
|Array|✓|OAS2,OAS3
|Maps|✓|ToolingExtension
|CollectionFormat|✓|OAS2
|CollectionFormatMulti|✓|OAS2
|Enum|✓|OAS2,OAS3
|ArrayOfEnum|✓|ToolingExtension
|ArrayOfModel|✓|ToolingExtension
|ArrayOfCollectionOfPrimitives|✓|ToolingExtension
|ArrayOfCollectionOfModel|✓|ToolingExtension
|ArrayOfCollectionOfEnum|✓|ToolingExtension
|MapOfEnum|✓|ToolingExtension
|MapOfModel|✓|ToolingExtension
|MapOfCollectionOfPrimitives|✓|ToolingExtension
|MapOfCollectionOfModel|✓|ToolingExtension
|MapOfCollectionOfEnum|✓|ToolingExtension
### Documentation Feature
| Name | Supported | Defined By |
| ---- | --------- | ---------- |
|Readme|✓|ToolingExtension
|Model|✓|ToolingExtension
|Api|✓|ToolingExtension
### Global Feature
| Name | Supported | Defined By |
| ---- | --------- | ---------- |
|Host|✓|OAS2,OAS3
|BasePath|✓|OAS2,OAS3
|Info|✓|OAS2,OAS3
|Schemes|✗|OAS2,OAS3
|PartialSchemes|✓|OAS2,OAS3
|Consumes|✓|OAS2
|Produces|✓|OAS2
|ExternalDocumentation|✓|OAS2,OAS3
|Examples|✓|OAS2,OAS3
|XMLStructureDefinitions|✗|OAS2,OAS3
|MultiServer|✗|OAS3
|ParameterizedServer|✗|OAS3
|ParameterStyling|✗|OAS3
|Callbacks|✗|OAS3
|LinkObjects|✗|OAS3
### Parameter Feature
| Name | Supported | Defined By |
| ---- | --------- | ---------- |
|Path|✓|OAS2,OAS3
|Query|✓|OAS2,OAS3
|Header|✓|OAS2,OAS3
|Body|✓|OAS2
|FormUnencoded|✓|OAS2
|FormMultipart|✓|OAS2
|Cookie|✗|OAS3
### Schema Support Feature
| Name | Supported | Defined By |
| ---- | --------- | ---------- |
|Simple|✓|OAS2,OAS3
|Composite|✓|OAS2,OAS3
|Polymorphism|✗|OAS2,OAS3
|Union|✗|OAS3
### Security Feature
| Name | Supported | Defined By |
| ---- | --------- | ---------- |
|BasicAuth|✓|OAS2,OAS3
|ApiKey|✓|OAS2,OAS3
|OpenIDConnect|✗|OAS3
|BearerToken|✗|OAS3
|OAuth2_Implicit|✓|OAS2,OAS3
|OAuth2_Password|✗|OAS2,OAS3
|OAuth2_ClientCredentials|✗|OAS2,OAS3
|OAuth2_AuthorizationCode|✗|OAS2,OAS3
### Wire Format Feature
| Name | Supported | Defined By |
| ---- | --------- | ---------- |
|JSON|✓|OAS2,OAS3
|XML|✓|OAS2,OAS3
|PROTOBUF|✗|ToolingExtension
|Custom|✗|OAS2,OAS3

View File

@ -0,0 +1,263 @@
/*
* Copyright 2018 OpenAPI-Generator Contributors (https://openapi-generator.tech)
* Copyright 2018 SmartBear Software
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.openapitools.codegen.languages;
import com.google.common.collect.ImmutableMap;
import org.apache.commons.lang3.StringUtils;
import org.openapitools.codegen.CliOption;
import org.openapitools.codegen.CodegenConstants;
import org.openapitools.codegen.CodegenType;
import org.openapitools.codegen.SupportingFile;
import org.openapitools.codegen.meta.features.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.util.Arrays;
import java.util.EnumSet;
import java.util.List;
import java.util.Map;
public class KotlinServerDeprecatedCodegen extends AbstractKotlinCodegen {
public static final String DEFAULT_LIBRARY = Constants.KTOR;
private final Logger LOGGER = LoggerFactory.getLogger(KotlinServerDeprecatedCodegen.class);
private Boolean autoHeadFeatureEnabled = true;
private Boolean conditionalHeadersFeatureEnabled = false;
private Boolean hstsFeatureEnabled = true;
private Boolean corsFeatureEnabled = false;
private Boolean compressionFeatureEnabled = true;
// This is here to potentially warn the user when an option is not supported by the target framework.
private Map<String, List<String>> optionsSupportedPerFramework = new ImmutableMap.Builder<String, List<String>>()
.put(Constants.KTOR, Arrays.asList(
Constants.AUTOMATIC_HEAD_REQUESTS,
Constants.CONDITIONAL_HEADERS,
Constants.HSTS,
Constants.CORS,
Constants.COMPRESSION
))
.build();
/**
* Constructs an instance of `KotlinServerCodegen`.
*/
public KotlinServerDeprecatedCodegen() {
super();
modifyFeatureSet(features -> features
.includeDocumentationFeatures(DocumentationFeature.Readme)
.wireFormatFeatures(EnumSet.of(WireFormatFeature.JSON, WireFormatFeature.XML))
.securityFeatures(EnumSet.of(
SecurityFeature.BasicAuth,
SecurityFeature.ApiKey,
SecurityFeature.OAuth2_Implicit
))
.excludeGlobalFeatures(
GlobalFeature.XMLStructureDefinitions,
GlobalFeature.Callbacks,
GlobalFeature.LinkObjects,
GlobalFeature.ParameterStyling
)
.excludeSchemaSupportFeatures(
SchemaSupportFeature.Polymorphism
)
.excludeParameterFeatures(
ParameterFeature.Cookie
)
);
artifactId = "kotlin-server-deprecated";
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-deprecated";
modelTemplateFiles.put("model.mustache", ".kt");
apiTemplateFiles.put("api.mustache", ".kt");
embeddedTemplateDir = templateDir = "kotlin-server-deprecated";
apiPackage = packageName + ".apis";
modelPackage = packageName + ".models";
supportedLibraries.put(Constants.KTOR, "ktor framework");
// TODO: Configurable server engine. Defaults to netty in build.gradle.
CliOption library = new CliOption(CodegenConstants.LIBRARY, CodegenConstants.LIBRARY_DESC);
library.setDefault(DEFAULT_LIBRARY);
library.setEnum(supportedLibraries);
cliOptions.add(library);
addSwitch(Constants.AUTOMATIC_HEAD_REQUESTS, Constants.AUTOMATIC_HEAD_REQUESTS_DESC, getAutoHeadFeatureEnabled());
addSwitch(Constants.CONDITIONAL_HEADERS, Constants.CONDITIONAL_HEADERS_DESC, getConditionalHeadersFeatureEnabled());
addSwitch(Constants.HSTS, Constants.HSTS_DESC, getHstsFeatureEnabled());
addSwitch(Constants.CORS, Constants.CORS_DESC, getCorsFeatureEnabled());
addSwitch(Constants.COMPRESSION, Constants.COMPRESSION_DESC, getCompressionFeatureEnabled());
}
public Boolean getAutoHeadFeatureEnabled() {
return autoHeadFeatureEnabled;
}
public void setAutoHeadFeatureEnabled(Boolean autoHeadFeatureEnabled) {
this.autoHeadFeatureEnabled = autoHeadFeatureEnabled;
}
public Boolean getCompressionFeatureEnabled() {
return compressionFeatureEnabled;
}
public void setCompressionFeatureEnabled(Boolean compressionFeatureEnabled) {
this.compressionFeatureEnabled = compressionFeatureEnabled;
}
public Boolean getConditionalHeadersFeatureEnabled() {
return conditionalHeadersFeatureEnabled;
}
public void setConditionalHeadersFeatureEnabled(Boolean conditionalHeadersFeatureEnabled) {
this.conditionalHeadersFeatureEnabled = conditionalHeadersFeatureEnabled;
}
public Boolean getCorsFeatureEnabled() {
return corsFeatureEnabled;
}
public void setCorsFeatureEnabled(Boolean corsFeatureEnabled) {
this.corsFeatureEnabled = corsFeatureEnabled;
}
public String getHelp() {
return "Generates a Kotlin server.";
}
public Boolean getHstsFeatureEnabled() {
return hstsFeatureEnabled;
}
public void setHstsFeatureEnabled(Boolean hstsFeatureEnabled) {
this.hstsFeatureEnabled = hstsFeatureEnabled;
}
public String getName() {
return "kotlin-server-deprecated";
}
public CodegenType getTag() {
return CodegenType.SERVER;
}
@Override
public void processOpts() {
super.processOpts();
if (additionalProperties.containsKey(CodegenConstants.LIBRARY)) {
this.setLibrary((String) additionalProperties.get(CodegenConstants.LIBRARY));
}
// set default library to "ktor"
if (StringUtils.isEmpty(library)) {
this.setLibrary(DEFAULT_LIBRARY);
additionalProperties.put(CodegenConstants.LIBRARY, DEFAULT_LIBRARY);
LOGGER.info("`library` option is empty. Default to " + DEFAULT_LIBRARY);
}
if (additionalProperties.containsKey(Constants.AUTOMATIC_HEAD_REQUESTS)) {
setAutoHeadFeatureEnabled(convertPropertyToBooleanAndWriteBack(Constants.AUTOMATIC_HEAD_REQUESTS));
} else {
additionalProperties.put(Constants.AUTOMATIC_HEAD_REQUESTS, getAutoHeadFeatureEnabled());
}
if (additionalProperties.containsKey(Constants.CONDITIONAL_HEADERS)) {
setConditionalHeadersFeatureEnabled(convertPropertyToBooleanAndWriteBack(Constants.CONDITIONAL_HEADERS));
} else {
additionalProperties.put(Constants.CONDITIONAL_HEADERS, getConditionalHeadersFeatureEnabled());
}
if (additionalProperties.containsKey(Constants.HSTS)) {
setHstsFeatureEnabled(convertPropertyToBooleanAndWriteBack(Constants.HSTS));
} else {
additionalProperties.put(Constants.HSTS, getHstsFeatureEnabled());
}
if (additionalProperties.containsKey(Constants.CORS)) {
setCorsFeatureEnabled(convertPropertyToBooleanAndWriteBack(Constants.CORS));
} else {
additionalProperties.put(Constants.CORS, getCorsFeatureEnabled());
}
if (additionalProperties.containsKey(Constants.COMPRESSION)) {
setCompressionFeatureEnabled(convertPropertyToBooleanAndWriteBack(Constants.COMPRESSION));
} else {
additionalProperties.put(Constants.COMPRESSION, getCompressionFeatureEnabled());
}
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.
supportingFiles.add(new SupportingFile("README.mustache", "", "README.md"));
supportingFiles.add(new SupportingFile("Dockerfile.mustache", "", "Dockerfile"));
supportingFiles.add(new SupportingFile("build.gradle.mustache", "", "build.gradle"));
supportingFiles.add(new SupportingFile("settings.gradle.mustache", "", "settings.gradle"));
supportingFiles.add(new SupportingFile("gradle.properties", "", "gradle.properties"));
supportingFiles.add(new SupportingFile("AppMain.kt.mustache", packageFolder, "AppMain.kt"));
supportingFiles.add(new SupportingFile("Configuration.kt.mustache", packageFolder, "Configuration.kt"));
if (generateApis) {
supportingFiles.add(new SupportingFile("Paths.kt.mustache", packageFolder, "Paths.kt"));
}
supportingFiles.add(new SupportingFile("application.conf.mustache", resourcesFolder, "application.conf"));
supportingFiles.add(new SupportingFile("logback.xml", resourcesFolder, "logback.xml"));
final String infrastructureFolder = (sourceFolder + File.separator + packageName + File.separator + "infrastructure").replace(".", File.separator);
supportingFiles.add(new SupportingFile("ApiKeyAuth.kt.mustache", infrastructureFolder, "ApiKeyAuth.kt"));
}
public static class Constants {
public final static String KTOR = "ktor";
public final static String AUTOMATIC_HEAD_REQUESTS = "featureAutoHead";
public final static String AUTOMATIC_HEAD_REQUESTS_DESC = "Automatically provide responses to HEAD requests for existing routes that have the GET verb defined.";
public final static String CONDITIONAL_HEADERS = "featureConditionalHeaders";
public final static String CONDITIONAL_HEADERS_DESC = "Avoid sending content if client already has same content, by checking ETag or LastModified properties.";
public final static String HSTS = "featureHSTS";
public final static String HSTS_DESC = "Avoid sending content if client already has same content, by checking ETag or LastModified properties.";
public final static String CORS = "featureCORS";
public final static String CORS_DESC = "Ktor by default provides an interceptor for implementing proper support for Cross-Origin Resource Sharing (CORS). See enable-cors.org.";
public final static String COMPRESSION = "featureCompression";
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.";
}
@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("# 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("################################################################################");
}
}

View File

@ -44,6 +44,7 @@ org.openapitools.codegen.languages.GraphQLNodeJSExpressServerCodegen
org.openapitools.codegen.languages.GroovyClientCodegen
org.openapitools.codegen.languages.KotlinClientCodegen
org.openapitools.codegen.languages.KotlinServerCodegen
org.openapitools.codegen.languages.KotlinServerDeprecatedCodegen
org.openapitools.codegen.languages.KotlinSpringServerCodegen
org.openapitools.codegen.languages.KotlinVertxServerCodegen
org.openapitools.codegen.languages.KtormSchemaCodegen

View File

@ -0,0 +1,84 @@
# {{packageName}} - Kotlin Server library for {{appName}}
## Requires
* Kotlin 1.1.2
* Gradle 3.3
## Build
First, create the gradle wrapper script:
```
gradle wrapper
```
Then, run:
```
./gradlew check assemble
```
This runs all tests and packages the library.
## Features/Implementation Notes
* Supports JSON inputs/outputs, File inputs, and Form inputs.
* Supports collection formats for query parameters: csv, tsv, ssv, pipes.
* Some Kotlin and Java types are fully qualified to avoid conflicts with types defined in OpenAPI definitions.
{{#generateApiDocs}}
<a name="documentation-for-api-endpoints"></a>
## Documentation for API Endpoints
All URIs are relative to *{{{basePath}}}*
Class | Method | HTTP request | Description
------------ | ------------- | ------------- | -------------
{{#apiInfo}}{{#apis}}{{#operations}}{{#operation}}*{{classname}}* | [**{{operationId}}**]({{apiDocPath}}{{classname}}.md#{{operationIdLowerCase}}) | **{{httpMethod}}** {{path}} | {{#summary}}{{{summary}}}{{/summary}}
{{/operation}}{{/operations}}{{/apis}}{{/apiInfo}}
{{/generateApiDocs}}
{{#generateModelDocs}}
<a name="documentation-for-models"></a>
## Documentation for Models
{{#modelPackage}}
{{#models}}{{#model}} - [{{{modelPackage}}}.{{{classname}}}]({{modelDocPath}}{{{classname}}}.md)
{{/model}}{{/models}}
{{/modelPackage}}
{{^modelPackage}}
No model defined in this package
{{/modelPackage}}
{{/generateModelDocs}}
<a name="documentation-for-authorization"></a>{{! TODO: optional documentation for authorization? }}
## Documentation for Authorization
{{^authMethods}}
All endpoints do not require authorization.
{{/authMethods}}
{{#authMethods}}
{{#last}}
Authentication schemes defined for the API:
{{/last}}
{{/authMethods}}
{{#authMethods}}
<a name="{{name}}"></a>
### {{name}}
{{#isApiKey}}- **Type**: API key
- **API key parameter name**: {{keyParamName}}
- **Location**: {{#isKeyInQuery}}URL query string{{/isKeyInQuery}}{{#isKeyInHeader}}HTTP header{{/isKeyInHeader}}
{{/isApiKey}}
{{#isBasic}}- **Type**: HTTP basic authentication
{{/isBasic}}
{{#isOAuth}}- **Type**: OAuth
- **Flow**: {{flow}}
- **Authorization URL**: {{authorizationUrl}}
- **Scopes**: {{^scopes}}N/A{{/scopes}}
{{#scopes}} - {{scope}}: {{description}}
{{/scopes}}
{{/isOAuth}}
{{/authMethods}}

View File

@ -0,0 +1,65 @@
# {{classname}}{{#description}}
{{description}}{{/description}}
All URIs are relative to *{{basePath}}*
Method | HTTP request | Description
------------- | ------------- | -------------
{{#operations}}{{#operation}}[**{{operationId}}**]({{classname}}.md#{{operationId}}) | **{{httpMethod}}** {{path}} | {{#summary}}{{summary}}{{/summary}}
{{/operation}}{{/operations}}
{{#operations}}
{{#operation}}
<a name="{{operationId}}"></a>
# **{{operationId}}**
> {{#returnType}}{{returnType}} {{/returnType}}{{operationId}}({{#allParams}}{{{paramName}}}{{^-last}}, {{/-last}}{{/allParams}})
{{summary}}{{#notes}}
{{notes}}{{/notes}}
### Example
```kotlin
// Import classes:
//import {{{packageName}}}.infrastructure.*
//import {{{modelPackage}}}.*
{{! TODO: Auth method documentation examples}}
val apiInstance = {{{classname}}}()
{{#allParams}}
val {{{paramName}}} : {{{dataType}}} = {{{example}}} // {{{dataType}}} | {{{description}}}
{{/allParams}}
try {
{{#returnType}}val result : {{{returnType}}} = {{/returnType}}apiInstance.{{{operationId}}}({{#allParams}}{{{paramName}}}{{^-last}}, {{/-last}}{{/allParams}}){{#returnType}}
println(result){{/returnType}}
} catch (e: ClientException) {
println("4xx response calling {{{classname}}}#{{{operationId}}}")
e.printStackTrace()
} catch (e: ServerException) {
println("5xx response calling {{{classname}}}#{{{operationId}}}")
e.printStackTrace()
}
```
### Parameters
{{^allParams}}This endpoint does not need any parameter.{{/allParams}}{{#allParams}}{{#-last}}
Name | Type | Description | Notes
------------- | ------------- | ------------- | -------------{{/-last}}{{/allParams}}
{{#allParams}} **{{paramName}}** | {{#isPrimitiveType}}**{{dataType}}**{{/isPrimitiveType}}{{^isPrimitiveType}}{{#isFile}}**{{dataType}}**{{/isFile}}{{^isFile}}{{#generateModelDocs}}[**{{dataType}}**]({{baseType}}.md){{/generateModelDocs}}{{^generateModelDocs}}**{{dataType}}**{{/generateModelDocs}}{{/isFile}}{{/isPrimitiveType}}| {{description}} |{{^required}} [optional]{{/required}}{{#defaultValue}} [default to {{defaultValue}}]{{/defaultValue}}{{#allowableValues}} [enum: {{#values}}{{{.}}}{{^-last}}, {{/-last}}{{/values}}]{{/allowableValues}}
{{/allParams}}
### Return type
{{#returnType}}{{#returnTypeIsPrimitive}}**{{returnType}}**{{/returnTypeIsPrimitive}}{{^returnTypeIsPrimitive}}{{#generateModelDocs}}[**{{returnType}}**]({{returnBaseType}}.md){{/generateModelDocs}}{{^generateModelDocs}}**{{returnType}}**{{/generateModelDocs}}{{/returnTypeIsPrimitive}}{{/returnType}}{{^returnType}}null (empty response body){{/returnType}}
### Authorization
{{^authMethods}}No authorization required{{/authMethods}}{{#authMethods}}[{{name}}](../README.md#{{name}}){{^-last}}, {{/-last}}{{/authMethods}}
### HTTP request headers
- **Content-Type**: {{#consumes}}{{{mediaType}}}{{^-last}}, {{/-last}}{{/consumes}}{{^consumes}}Not defined{{/consumes}}
- **Accept**: {{#produces}}{{{mediaType}}}{{^-last}}, {{/-last}}{{/produces}}{{^produces}}Not defined{{/produces}}
{{/operation}}
{{/operations}}

View File

@ -0,0 +1,15 @@
# {{classname}}
## Properties
Name | Type | Description | Notes
------------ | ------------- | ------------- | -------------
{{#vars}}**{{name}}** | {{#isEnum}}[**inline**](#{{datatypeWithEnum}}){{/isEnum}}{{^isEnum}}{{#isPrimitiveType}}**{{dataType}}**{{/isPrimitiveType}}{{^isPrimitiveType}}[**{{dataType}}**]({{complexType}}.md){{/isPrimitiveType}}{{/isEnum}} | {{description}} | {{^required}} [optional]{{/required}}{{#isReadOnly}} [readonly]{{/isReadOnly}}
{{/vars}}
{{#vars}}{{#isEnum}}
<a name="{{{datatypeWithEnum}}}"></a>{{!NOTE: see java's resources "pojo_doc.mustache" once enums are fully implemented}}
## Enum: {{baseName}}
Name | Value
---- | -----{{#allowableValues}}
{{name}} | {{#values}}{{.}}{{^-last}}, {{/-last}}{{/values}}{{/allowableValues}}
{{/isEnum}}{{/vars}}

View File

@ -0,0 +1,52 @@
{{#parcelizeModels}}
import android.os.Parcelable
import kotlinx.parcelize.Parcelize
{{/parcelizeModels}}
{{#serializableModel}}
import java.io.Serializable
{{/serializableModel}}
/**
* {{{description}}}
{{#vars}}
* @param {{name}} {{{description}}}
{{/vars}}
*/
{{#parcelizeModels}}
@Parcelize
{{/parcelizeModels}}
data class {{classname}} (
{{#requiredVars}}
{{>data_class_req_var}}{{^-last}},
{{/-last}}{{/requiredVars}}{{#hasRequired}}{{#hasOptional}},
{{/hasOptional}}{{/hasRequired}}{{#optionalVars}}{{>data_class_opt_var}}{{^-last}},
{{/-last}}{{/optionalVars}}
) {{^serializableModel}}{{#parcelizeModels}} : Parcelable{{/parcelizeModels}}{{/serializableModel}}{{^parcelizeModels}}{{#serializableModel}}: Serializable {{/serializableModel}}{{/parcelizeModels}}{{#parcelizeModels}}{{#serializableModel}} : Parcelable, Serializable {{/serializableModel}}{{/parcelizeModels}}
{{#vendorExtensions.x-has-data-class-body}}
{
{{/vendorExtensions.x-has-data-class-body}}
{{#serializableModel}}
companion object {
private const val serialVersionUID: Long = 123
}
{{/serializableModel}}
{{#hasEnums}}
{{#vars}}
{{#isEnum}}
/**
* {{{description}}}
* Values: {{#allowableValues}}{{#enumVars}}{{&name}}{{^-last}},{{/-last}}{{/enumVars}}{{/allowableValues}}
*/
enum class {{nameInCamelCase}}(val value: {{dataType}}){
{{#allowableValues}}
{{#enumVars}}
{{&name}}({{{value}}}){{^-last}},{{/-last}}{{#-last}};{{/-last}}
{{/enumVars}}
{{/allowableValues}}
}
{{/isEnum}}
{{/vars}}
{{/hasEnums}}
{{#vendorExtensions.x-has-data-class-body}}
}
{{/vendorExtensions.x-has-data-class-body}}

View File

@ -0,0 +1,4 @@
{{#description}}
/* {{{description}}} */
{{/description}}
{{>modelMutable}} {{{name}}}: {{#isEnum}}{{classname}}.{{nameInCamelCase}}{{/isEnum}}{{^isEnum}}{{{dataType}}}{{/isEnum}}? = {{#defaultvalue}}{{defaultvalue}}{{/defaultvalue}}{{^defaultvalue}}null{{/defaultvalue}}

View File

@ -0,0 +1,4 @@
{{#description}}
/* {{{description}}} */
{{/description}}
{{>modelMutable}} {{{name}}}: {{#isEnum}}{{classname}}.{{nameInCamelCase}}{{/isEnum}}{{^isEnum}}{{{dataType}}}{{/isEnum}}

View File

@ -0,0 +1,9 @@
/**
* {{{description}}}
* Values: {{#allowableValues}}{{#enumVars}}{{&name}}{{^-last}},{{/-last}}{{/enumVars}}{{/allowableValues}}
*/
enum class {{classname}}(val value: {{dataType}}){
{{#allowableValues}}{{#enumVars}}
{{&name}}({{{value}}}){{^-last}},{{/-last}}{{#-last}};{{/-last}}
{{/enumVars}}{{/allowableValues}}
}

View File

@ -0,0 +1,7 @@
# {{classname}}
## Enum
{{#allowableValues}}{{#enumVars}}
* `{{name}}` (value: `{{{value}}}`)
{{/enumVars}}{{/allowableValues}}

View File

@ -0,0 +1,85 @@
package {{packageName}}.infrastructure
import io.ktor.application.ApplicationCall
import io.ktor.application.call
import io.ktor.auth.Authentication
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.response.respond
enum class ApiKeyLocation(val location: String) {
QUERY("query"),
HEADER("header")
}
data class ApiKeyCredential(val value: String): Credential
data class ApiPrincipal(val apiKeyCredential: ApiKeyCredential?) : Principal
/**
* Represents a Api Key authentication provider
* @param name is the name of the provider, or `null` for a default provider
*/
class ApiKeyAuthenticationProvider(name: String?) : AuthenticationProvider(name) {
internal var authenticationFunction: suspend ApplicationCall.(ApiKeyCredential) -> Principal? = { null }
var apiKeyName: String = "";
var apiKeyLocation: ApiKeyLocation = ApiKeyLocation.QUERY;
/**
* Sets a validation function that will check given [ApiKeyCredential] instance and return [Principal],
* or null if credential does not correspond to an authenticated principal
*/
fun validate(body: suspend ApplicationCall.(ApiKeyCredential) -> Principal?) {
authenticationFunction = body
}
}
fun Authentication.Configuration.apiKeyAuth(name: String? = null, configure: ApiKeyAuthenticationProvider.() -> Unit) {
val provider = ApiKeyAuthenticationProvider(name).apply(configure)
val apiKeyName = provider.apiKeyName
val apiKeyLocation = provider.apiKeyLocation
val authenticate = provider.authenticationFunction
provider.pipeline.intercept(AuthenticationPipeline.RequestAuthentication) { context ->
val credentials = call.request.apiKeyAuthenticationCredentials(apiKeyName, apiKeyLocation)
val principal = credentials?.let { authenticate(call, it) }
val cause = when {
credentials == null -> AuthenticationFailedCause.NoCredentials
principal == null -> AuthenticationFailedCause.InvalidCredentials
else -> null
}
if (cause != null) {
context.challenge(apiKeyName, cause) {
// TODO: Verify correct response structure here.
call.respond(UnauthorizedResponse(HttpAuthHeader.Parameterized("API_KEY", mapOf("key" to apiKeyName), HeaderValueEncoding.QUOTED_ALWAYS)))
it.complete()
}
}
if (principal != null) {
context.principal(principal)
}
}
}
fun ApplicationRequest.apiKeyAuthenticationCredentials(apiKeyName: String, apiKeyLocation: ApiKeyLocation): ApiKeyCredential? {
val value: String? = when(apiKeyLocation) {
ApiKeyLocation.QUERY -> this.queryParameters[apiKeyName]
ApiKeyLocation.HEADER -> this.headers[apiKeyName]
}
when (value) {
null -> return null
else -> return ApiKeyCredential(value)
}
}

View File

@ -0,0 +1,145 @@
package {{packageName}}
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
import io.ktor.locations.KtorExperimentalLocationsAPI
import io.ktor.locations.Locations
import io.ktor.metrics.Metrics
import io.ktor.routing.Routing
import java.util.concurrent.TimeUnit
import io.ktor.util.KtorExperimentalAPI
{{#hasAuthMethods}}
import io.ktor.auth.Authentication
import io.ktor.auth.oauth
import org.openapitools.server.infrastructure.ApiKeyCredential
import org.openapitools.server.infrastructure.ApiPrincipal
import org.openapitools.server.infrastructure.apiKeyAuth
{{/hasAuthMethods}}
{{#generateApis}}{{#apiInfo}}{{#apis}}import {{apiPackage}}.{{classname}}
{{/apis}}{{/apiInfo}}{{/generateApis}}
@KtorExperimentalAPI
internal val settings = HoconApplicationConfig(ConfigFactory.defaultApplication(HTTP::class.java.classLoader))
object HTTP {
val client = HttpClient(Apache)
}
@KtorExperimentalAPI
@KtorExperimentalLocationsAPI
fun Application.main() {
install(DefaultHeaders)
install(Metrics) {
val reporter = Slf4jReporter.forRegistry(registry)
.outputTo(log)
.convertRatesTo(TimeUnit.SECONDS)
.convertDurationsTo(TimeUnit.MILLISECONDS)
.build()
reporter.start(10, TimeUnit.SECONDS)
}
{{#generateApis}}
install(ContentNegotiation) {
register(ContentType.Application.Json, GsonConverter())
}
{{#featureAutoHead}}
install(AutoHeadResponse) // see http://ktor.io/features/autoheadresponse.html
{{/featureAutoHead}}
{{#featureConditionalHeaders}}
install(ConditionalHeaders) // see http://ktor.io/features/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
{{/featureCompression}}
install(Locations) // see http://ktor.io/features/locations.html
{{#hasAuthMethods}}
install(Authentication) {
{{#authMethods}}
{{#isBasic}}
basic("{{{name}}}") {
validate { credentials ->
// TODO: "Apply your basic authentication functionality."
// Accessible in-method via call.principal<UserIdPrincipal>()
if (credentials.name == "Swagger" && "Codegen" == credentials.password) {
UserIdPrincipal(credentials.name)
} else {
null
}
}
{{/isBasic}}
{{#isApiKey}}
// "Implement API key auth ({{{name}}}) for parameter name '{{{keyParamName}}}'."
apiKeyAuth("{{{name}}}") {
validate { apikeyCredential: ApiKeyCredential ->
when {
apikeyCredential.value == "keyboardcat" -> ApiPrincipal(apikeyCredential)
else -> null
}
}
}
{{/isApiKey}}
{{#isOAuth}}
{{#bodyAllowed}}
{{/bodyAllowed}}
{{^bodyAllowed}}
oauth("{{name}}") {
client = HttpClient(Apache)
providerLookup = { ApplicationAuthProviders["{{{name}}}"] }
urlProvider = { _ ->
// TODO: define a callback url here.
"/"
}
}
{{/bodyAllowed}}
{{/isOAuth}}
{{/authMethods}}
}
{{/hasAuthMethods}}
install(Routing) {
{{#apiInfo}}
{{#apis}}
{{#operations}}
{{classname}}()
{{/operations}}
{{/apis}}
{{/apiInfo}}
}
{{/generateApis}}
environment.monitor.subscribe(ApplicationStopping)
{
HTTP.client.close()
}
}

View File

@ -0,0 +1,114 @@
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.util.KtorExperimentalAPI
import java.time.Duration
import java.util.concurrent.Executors
import {{packageName}}.settings
{{#featureCORS}}
/**
* Application block for [CORS] configuration.
*
* This file may be excluded in .openapi-generator-ignore,
* and application specific configuration can be applied in this function.
*
* See http://ktor.io/features/cors.html
*/
internal fun ApplicationCORSConfiguration(): CORS.Configuration.() -> Unit {
return {
// method(HttpMethod.Options)
// header(HttpHeaders.XForwardedProto)
// anyHost()
// host("my-host")
// host("my-host:80")
// host("my-host", subDomains = listOf("www"))
// host("my-host", schemes = listOf("http", "https"))
// allowCredentials = true
// maxAge = Duration.ofDays(1)
}
}
{{/featureCORS}}
{{#featureHSTS}}
/**
* Application block for [HSTS] configuration.
*
* This file may be excluded in .openapi-generator-ignore,
* and application specific configuration can be applied in this function.
*
* See http://ktor.io/features/hsts.html
*/
internal fun ApplicationHstsConfiguration(): HSTS.Configuration.() -> Unit {
return {
maxAge = Duration.ofDays(365)
includeSubDomains = true
preload = false
// You may also apply any custom directives supported by specific user-agent. For example:
// customDirectives.put("redirectHttpToHttps", "false")
}
}
{{/featureHSTS}}
{{#featureCompression}}
/**
* Application block for [Compression] configuration.
*
* This file may be excluded in .openapi-generator-ignore,
* and application specific configuration can be applied in this function.
*
* See http://ktor.io/features/compression.html
*/
internal fun ApplicationCompressionConfiguration(): Compression.Configuration.() -> Unit {
return {
gzip {
priority = 1.0
}
deflate {
priority = 10.0
minimumSize(1024) // condition
}
}
}
{{/featureCompression}}
// Defines authentication mechanisms used throughout the application.
@KtorExperimentalAPI
val ApplicationAuthProviders: Map<String, OAuthServerSettings> = listOf<OAuthServerSettings>(
{{#authMethods}}
{{#isOAuth}}
OAuthServerSettings.OAuth2ServerSettings(
name = "{{name}}",
authorizeUrl = "{{authorizationUrl}}",
accessTokenUrl = "{{tokenUrl}}",
requestMethod = HttpMethod.Get,
{{! TODO: flow, doesn't seem to be supported yet by ktor }}
clientId = settings.property("auth.oauth.{{name}}.clientId").getString(),
clientSecret = settings.property("auth.oauth.{{name}}.clientSecret").getString(),
defaultScopes = listOf({{#scopes}}"{{scope}}"{{^-last}}, {{/-last}}{{/scopes}})
){{^-last}},{{/-last}}
{{/isOAuth}}
{{/authMethods}}
// OAuthServerSettings.OAuth2ServerSettings(
// name = "facebook",
// authorizeUrl = "https://graph.facebook.com/oauth/authorize",
// accessTokenUrl = "https://graph.facebook.com/oauth/access_token",
// requestMethod = HttpMethod.Post,
//
// clientId = "settings.property("auth.oauth.facebook.clientId").getString()",
// clientSecret = "settings.property("auth.oauth.facebook.clientSecret").getString()",
// defaultScopes = listOf("public_profile")
// )
).associateBy { it.name }
// Provides an application-level fixed thread pool on which to execute coroutines (mainly)
internal val ApplicationExecutors = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() * 4)

View File

@ -0,0 +1,7 @@
FROM openjdk:8-jre-alpine
COPY ./build/libs/{{artifactId}}.jar /root/{{artifactId}}.jar
WORKDIR /root
CMD ["java", "-server", "-Xms4g", "-Xmx4g", "-XX:+UseG1GC", "-XX:MaxGCPauseMillis=100", "-XX:+UseStringDeduplication", "-jar", "{{artifactId}}.jar"]

View File

@ -0,0 +1,28 @@
{{>licenseInfo}}
package {{packageName}}
import io.ktor.locations.KtorExperimentalLocationsAPI
import io.ktor.locations.Location
{{#imports}}import {{import}}
{{/imports}}
{{#apiInfo}}
object Paths {
{{#apis}}
{{#operations}}
{{#operation}}
{{^bodyAllowed}}
/**
* {{summary}}
* {{#unescapedNotes}}{{.}}{{/unescapedNotes}}
{{#allParams}}* @param {{paramName}} {{description}} {{^required}}(optional{{#defaultValue}}, default to {{{.}}}{{/defaultValue}}){{/required}}
{{/allParams}}*/
@KtorExperimentalLocationsAPI
@Location("{{path}}") class {{operationId}}({{#allParams}}val {{paramName}}: {{{dataType}}}{{^required}}? = null{{/required}}{{#required}}{{#isNullable}}?{{/isNullable}}{{/required}}{{^-last}}, {{/-last}}{{/allParams}})
{{/bodyAllowed}}
{{/operation}}
{{/operations}}
{{/apis}}
}
{{/apiInfo}}

View File

@ -0,0 +1,101 @@
# {{packageName}} - Kotlin Server library for {{appName}}
{{#unescapedAppDescription}}
{{.}}
{{/unescapedAppDescription}}
Generated by OpenAPI Generator {{generatorVersion}}{{^hideGenerationTimestamp}} ({{generatedDate}}){{/hideGenerationTimestamp}}.
## Requires
* Kotlin 1.3.21
* Gradle 4.9
## Build
First, create the gradle wrapper script:
```
gradle wrapper
```
Then, run:
```
./gradlew check assemble
```
This runs all tests and packages the library.
## Running
The server builds as a fat jar with a main entrypoint. To start the service, run `java -jar ./build/libs/{{artifactId}}.jar`.
You may also run in docker:
```
docker build -t {{artifactId}} .
docker run -p 8080:8080 {{artifactId}}
```
## Features/Implementation Notes
* Supports JSON inputs/outputs, File inputs, and Form inputs (see ktor documentation for more info).
* ~Supports collection formats for query parameters: csv, tsv, ssv, pipes.~
* Some Kotlin and Java types are fully qualified to avoid conflicts with types defined in OpenAPI definitions.
{{#generateApiDocs}}
<a name="documentation-for-api-endpoints"></a>
## Documentation for API Endpoints
All URIs are relative to *{{{basePath}}}*
Class | Method | HTTP request | Description
------------ | ------------- | ------------- | -------------
{{#apiInfo}}{{#apis}}{{#operations}}{{#operation}}*{{classname}}* | [**{{operationId}}**]({{apiDocPath}}{{classname}}.md#{{operationIdLowerCase}}) | **{{httpMethod}}** {{path}} | {{#summary}}{{{summary}}}{{/summary}}
{{/operation}}{{/operations}}{{/apis}}{{/apiInfo}}
{{/generateApiDocs}}
{{#generateModelDocs}}
<a name="documentation-for-models"></a>
## Documentation for Models
{{#modelPackage}}
{{#models}}{{#model}} - [{{{modelPackage}}}.{{{classname}}}]({{modelDocPath}}{{{classname}}}.md)
{{/model}}{{/models}}
{{/modelPackage}}
{{^modelPackage}}
No model defined in this package
{{/modelPackage}}
{{/generateModelDocs}}
<a name="documentation-for-authorization"></a>{{! TODO: optional documentation for authorization? }}
## Documentation for Authorization
{{^authMethods}}
All endpoints do not require authorization.
{{/authMethods}}
{{#authMethods}}
{{#last}}
Authentication schemes defined for the API:
{{/last}}
{{/authMethods}}
{{#authMethods}}
<a name="{{name}}"></a>
### {{name}}
{{#isApiKey}}- **Type**: API key
- **API key parameter name**: {{keyParamName}}
- **Location**: {{#isKeyInQuery}}URL query string{{/isKeyInQuery}}{{#isKeyInHeader}}HTTP header{{/isKeyInHeader}}
{{/isApiKey}}
{{#isBasic}}- **Type**: HTTP basic authentication
{{/isBasic}}
{{#isOAuth}}- **Type**: OAuth
- **Flow**: {{flow}}
- **Authorization URL**: {{authorizationUrl}}
- **Scopes**: {{^scopes}}N/A{{/scopes}}
{{#scopes}} - {{scope}}: {{description}}
{{/scopes}}
{{/isOAuth}}
{{/authMethods}}

View File

@ -0,0 +1,25 @@
{{#hasAuthMethods}}
{{>libraries/ktor/_principal}}
if (principal == null) {
call.respond(HttpStatusCode.Unauthorized)
} else {
{{#examples}}
{{#-first}}
{{#lambda.indented}}{{>_response}}{{/lambda.indented}}
{{/-first}}
{{/examples}}
{{^examples}}
call.respond(HttpStatusCode.NotImplemented)
{{/examples}}
}
{{/hasAuthMethods}}
{{^hasAuthMethods}}
{{#examples}}
{{#-first}}
{{>libraries/ktor/_response}}
{{/-first}}
{{/examples}}
{{^examples}}
call.respond(HttpStatusCode.NotImplemented)
{{/examples}}
{{/hasAuthMethods}}

View File

@ -0,0 +1,11 @@
{{#authMethods}}
{{#isBasic}}
val principal = call.authentication.principal<UserIdPrincipal>()
{{/isBasic}}
{{#isApiKey}}
val principal = call.authentication.principal<ApiPrincipal>()
{{/isApiKey}}
{{#isOAuth}}
val principal = call.authentication.principal<OAuthAccessTokenResponse>()
{{/isOAuth}}
{{/authMethods}}

View File

@ -0,0 +1,8 @@
val exampleContentType = "{{{contentType}}}"
val exampleContentString = """{{&example}}"""
when(exampleContentType) {
"application/json" -> call.respond(gson.fromJson(exampleContentString, empty::class.java))
"application/xml" -> call.respondText(exampleContentString, ContentType.Text.Xml)
else -> call.respondText(exampleContentString)
}

View File

@ -0,0 +1,62 @@
{{>licenseInfo}}
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.locations.KtorExperimentalLocationsAPI
import io.ktor.locations.delete
import io.ktor.locations.get
import io.ktor.response.respond
import io.ktor.response.respondText
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}}.infrastructure.ApiPrincipal
{{#imports}}import {{import}}
{{/imports}}
{{#operations}}
@KtorExperimentalLocationsAPI
fun Route.{{classname}}() {
val gson = Gson()
val empty = mutableMapOf<String, Any?>()
{{#operation}}
{{#bodyAllowed}}
route("{{path}}") {
{{#hasAuthMethods}}
{{#authMethods}}
authenticate("{{{name}}}") {
{{/authMethods}}
{{/hasAuthMethods}}
{{#lambda.lowercase}}{{httpMethod}}{{/lambda.lowercase}} {
{{#lambda.indented_12}}{{>libraries/ktor/_api_body}}{{/lambda.indented_12}}
}
{{#hasAuthMethods}}
}
{{/hasAuthMethods}}
}
{{/bodyAllowed}}
{{^bodyAllowed}}
{{! NOTE: Locations can be used on routes without body parameters.}}
{{#lambda.lowercase}}{{httpMethod}}{{/lambda.lowercase}}<Paths.{{operationId}}> { _: Paths.{{operationId}} ->
{{#lambda.indented_8}}{{>libraries/ktor/_api_body}}{{/lambda.indented_8}}
}
{{/bodyAllowed}}
{{/operation}}
}
{{/operations}}

View File

@ -0,0 +1,27 @@
ktor {
deployment {
environment = development
port = 8080
autoreload = true
watch = [ {{packageName}} ]
}
application {
modules = [ {{packageName}}.AppMainKt.main ]
}
}
# Typesafe config allows multiple ways to provide configuration values without hard-coding them here.
# Please see https://github.com/lightbend/config for details.
auth {
oauth {
{{#authMethods}}
{{#isOAuth}}
{{name}} {
clientId = ""
clientSecret = ""
}
{{/isOAuth}}
{{/authMethods}}
}
}

View File

@ -0,0 +1,68 @@
group '{{groupId}}'
version '{{artifactVersion}}'
wrapper {
gradleVersion = '4.9'
distributionUrl = "https://services.gradle.org/distributions/gradle-$gradleVersion-all.zip"
}
buildscript {
ext.kotlin_version = '1.3.21'
ext.ktor_version = '1.1.3'
ext.shadow_version = '2.0.3'
repositories {
maven { url "https://repo1.maven.org/maven2" }
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"
}
}
apply plugin: 'java'
apply plugin: 'kotlin'
apply plugin: 'application'
mainClassName = "io.ktor.server.netty.DevelopmentEngine"
// Initialization order with shadow 2.0.1 and Gradle 4.3 is weird.
// See https://github.com/johnrengelman/shadow/issues/336#issuecomment-355402508
apply plugin: 'com.github.johnrengelman.shadow'
sourceCompatibility = 1.8
compileKotlin {
kotlinOptions.jvmTarget = "1.8"
}
compileTestKotlin {
kotlinOptions.jvmTarget = "1.8"
}
shadowJar {
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" }
}
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-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'
}

View File

@ -0,0 +1,11 @@
/**
* {{{appName}}}
* {{{appDescription}}}
*
* {{#version}}The version of the OpenAPI document: {{{version}}}{{/version}}
* {{#infoEmail}}Contact: {{{infoEmail}}}{{/infoEmail}}
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
* Do not edit the class manually.
*/

View File

@ -0,0 +1,15 @@
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{YYYY-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<root level="trace">
<appender-ref ref="STDOUT"/>
</root>
<logger name="org.eclipse.jetty" level="INFO"/>
<logger name="io.netty" level="INFO"/>
</configuration>

View File

@ -0,0 +1,11 @@
/**
* {{{appName}}}
* {{{appDescription}}}
*
* {{#version}}The version of the OpenAPI document: {{{version}}}{{/version}}
* {{#infoEmail}}Contact: {{{infoEmail}}}{{/infoEmail}}
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
* Do not edit the class manually.
*/

View File

@ -0,0 +1,11 @@
{{>licenseInfo}}
package {{modelPackage}}
{{#imports}}import {{import}}
{{/imports}}
{{#models}}
{{#model}}
{{#isEnum}}{{>enum_class}}{{/isEnum}}{{^isEnum}}{{>data_class}}{{/isEnum}}
{{/model}}
{{/models}}

View File

@ -0,0 +1 @@
{{#modelMutable}}var{{/modelMutable}}{{^modelMutable}}val{{/modelMutable}}

View File

@ -0,0 +1,3 @@
{{#models}}{{#model}}
{{#isEnum}}{{>enum_doc}}{{/isEnum}}{{^isEnum}}{{>class_doc}}{{/isEnum}}
{{/model}}{{/models}}

View File

@ -0,0 +1 @@
rootProject.name = '{{artifactId}}'

View File

@ -9,6 +9,7 @@ import org.openapitools.codegen.DefaultGenerator;
import org.openapitools.codegen.languages.AbstractKotlinCodegen;
import org.openapitools.codegen.languages.KotlinClientCodegen;
import org.openapitools.codegen.languages.KotlinServerCodegen;
import org.openapitools.codegen.languages.KotlinServerDeprecatedCodegen;
import org.openapitools.codegen.languages.KotlinSpringServerCodegen;
import org.openapitools.codegen.languages.KotlinVertxServerCodegen;
import org.testng.annotations.DataProvider;
@ -28,6 +29,7 @@ public class KotlinModelCodegenTest {
return new Object[][]{
{new KotlinClientCodegen()},
{new KotlinServerCodegen()},
{new KotlinServerDeprecatedCodegen()},
{new KotlinSpringServerCodegen()},
{new KotlinVertxServerCodegen()},
};

View File

@ -0,0 +1,23 @@
# OpenAPI Generator Ignore
# Generated by openapi-generator https://github.com/openapitools/openapi-generator
# Use this file to prevent files from being overwritten by the generator.
# The patterns follow closely to .gitignore or .dockerignore.
# As an example, the C# client generator defines ApiClient.cs.
# You can make changes and tell OpenAPI Generator to ignore just this file by uncommenting the following line:
#ApiClient.cs
# You can match any string of characters against a directory, file or extension with a single asterisk (*):
#foo/*/qux
# The above matches foo/bar/qux and foo/baz/qux, but not foo/bar/baz/qux
# You can recursively match patterns against a directory, file or extension with a double asterisk (**):
#foo/**/qux
# This matches foo/bar/qux, foo/baz/qux, and foo/bar/baz/qux
# You can also negate patterns with an exclamation (!).
# For example, you can ignore all files in a docs folder with the file extension .md:
#docs/*.md
# Then explicitly reverse the ignore rule for a single file:
#!docs/README.md

View File

@ -0,0 +1,20 @@
Dockerfile
README.md
build.gradle
gradle.properties
settings.gradle
src/main/kotlin/org/openapitools/server/AppMain.kt
src/main/kotlin/org/openapitools/server/Configuration.kt
src/main/kotlin/org/openapitools/server/Paths.kt
src/main/kotlin/org/openapitools/server/apis/PetApi.kt
src/main/kotlin/org/openapitools/server/apis/StoreApi.kt
src/main/kotlin/org/openapitools/server/apis/UserApi.kt
src/main/kotlin/org/openapitools/server/infrastructure/ApiKeyAuth.kt
src/main/kotlin/org/openapitools/server/models/ApiResponse.kt
src/main/kotlin/org/openapitools/server/models/Category.kt
src/main/kotlin/org/openapitools/server/models/Order.kt
src/main/kotlin/org/openapitools/server/models/Pet.kt
src/main/kotlin/org/openapitools/server/models/Tag.kt
src/main/kotlin/org/openapitools/server/models/User.kt
src/main/resources/application.conf
src/main/resources/logback.xml

View File

@ -0,0 +1 @@
5.2.0-SNAPSHOT

View File

@ -0,0 +1,7 @@
FROM openjdk:8-jre-alpine
COPY ./build/libs/kotlin-server-deprecated.jar /root/kotlin-server-deprecated.jar
WORKDIR /root
CMD ["java", "-server", "-Xms4g", "-Xmx4g", "-XX:+UseG1GC", "-XX:MaxGCPauseMillis=100", "-XX:+UseStringDeduplication", "-jar", "kotlin-server-deprecated.jar"]

View File

@ -0,0 +1,104 @@
# org.openapitools.server - Kotlin Server library for OpenAPI Petstore
This is a sample server Petstore server. For this sample, you can use the api key &#x60;special-key&#x60; to test the authorization filters.
Generated by OpenAPI Generator 5.2.0-SNAPSHOT.
## Requires
* Kotlin 1.3.21
* Gradle 4.9
## Build
First, create the gradle wrapper script:
```
gradle wrapper
```
Then, run:
```
./gradlew check assemble
```
This runs all tests and packages the library.
## Running
The server builds as a fat jar with a main entrypoint. To start the service, run `java -jar ./build/libs/kotlin-server-deprecated.jar`.
You may also run in docker:
```
docker build -t kotlin-server-deprecated .
docker run -p 8080:8080 kotlin-server-deprecated
```
## Features/Implementation Notes
* Supports JSON inputs/outputs, File inputs, and Form inputs (see ktor documentation for more info).
* ~Supports collection formats for query parameters: csv, tsv, ssv, pipes.~
* Some Kotlin and Java types are fully qualified to avoid conflicts with types defined in OpenAPI definitions.
<a name="documentation-for-api-endpoints"></a>
## Documentation for API Endpoints
All URIs are relative to *http://petstore.swagger.io/v2*
Class | Method | HTTP request | Description
------------ | ------------- | ------------- | -------------
*PetApi* | [**addPet**](docs/PetApi.md#addpet) | **POST** /pet | Add a new pet to the store
*PetApi* | [**deletePet**](docs/PetApi.md#deletepet) | **DELETE** /pet/{petId} | Deletes a pet
*PetApi* | [**findPetsByStatus**](docs/PetApi.md#findpetsbystatus) | **GET** /pet/findByStatus | Finds Pets by status
*PetApi* | [**findPetsByTags**](docs/PetApi.md#findpetsbytags) | **GET** /pet/findByTags | Finds Pets by tags
*PetApi* | [**getPetById**](docs/PetApi.md#getpetbyid) | **GET** /pet/{petId} | Find pet by ID
*PetApi* | [**updatePet**](docs/PetApi.md#updatepet) | **PUT** /pet | Update an existing pet
*PetApi* | [**updatePetWithForm**](docs/PetApi.md#updatepetwithform) | **POST** /pet/{petId} | Updates a pet in the store with form data
*PetApi* | [**uploadFile**](docs/PetApi.md#uploadfile) | **POST** /pet/{petId}/uploadImage | uploads an image
*StoreApi* | [**deleteOrder**](docs/StoreApi.md#deleteorder) | **DELETE** /store/order/{orderId} | Delete purchase order by ID
*StoreApi* | [**getInventory**](docs/StoreApi.md#getinventory) | **GET** /store/inventory | Returns pet inventories by status
*StoreApi* | [**getOrderById**](docs/StoreApi.md#getorderbyid) | **GET** /store/order/{orderId} | Find purchase order by ID
*StoreApi* | [**placeOrder**](docs/StoreApi.md#placeorder) | **POST** /store/order | Place an order for a pet
*UserApi* | [**createUser**](docs/UserApi.md#createuser) | **POST** /user | Create user
*UserApi* | [**createUsersWithArrayInput**](docs/UserApi.md#createuserswitharrayinput) | **POST** /user/createWithArray | Creates list of users with given input array
*UserApi* | [**createUsersWithListInput**](docs/UserApi.md#createuserswithlistinput) | **POST** /user/createWithList | Creates list of users with given input array
*UserApi* | [**deleteUser**](docs/UserApi.md#deleteuser) | **DELETE** /user/{username} | Delete user
*UserApi* | [**getUserByName**](docs/UserApi.md#getuserbyname) | **GET** /user/{username} | Get user by user name
*UserApi* | [**loginUser**](docs/UserApi.md#loginuser) | **GET** /user/login | Logs user into the system
*UserApi* | [**logoutUser**](docs/UserApi.md#logoutuser) | **GET** /user/logout | Logs out current logged in user session
*UserApi* | [**updateUser**](docs/UserApi.md#updateuser) | **PUT** /user/{username} | Updated user
<a name="documentation-for-models"></a>
## Documentation for Models
- [org.openapitools.server.models.ApiResponse](docs/ApiResponse.md)
- [org.openapitools.server.models.Category](docs/Category.md)
- [org.openapitools.server.models.Order](docs/Order.md)
- [org.openapitools.server.models.Pet](docs/Pet.md)
- [org.openapitools.server.models.Tag](docs/Tag.md)
- [org.openapitools.server.models.User](docs/User.md)
<a name="documentation-for-authorization"></a>
## Documentation for Authorization
<a name="api_key"></a>
### api_key
- **Type**: API key
- **API key parameter name**: api_key
- **Location**: HTTP header
<a name="petstore_auth"></a>
### petstore_auth
- **Type**: OAuth
- **Flow**: implicit
- **Authorization URL**: http://petstore.swagger.io/api/oauth/dialog
- **Scopes**:
- write:pets: modify pets in your account
- read:pets: read your pets

View File

@ -0,0 +1,68 @@
group 'org.openapitools'
version '1.0.0'
wrapper {
gradleVersion = '4.9'
distributionUrl = "https://services.gradle.org/distributions/gradle-$gradleVersion-all.zip"
}
buildscript {
ext.kotlin_version = '1.3.21'
ext.ktor_version = '1.1.3'
ext.shadow_version = '2.0.3'
repositories {
maven { url "https://repo1.maven.org/maven2" }
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"
}
}
apply plugin: 'java'
apply plugin: 'kotlin'
apply plugin: 'application'
mainClassName = "io.ktor.server.netty.DevelopmentEngine"
// Initialization order with shadow 2.0.1 and Gradle 4.3 is weird.
// See https://github.com/johnrengelman/shadow/issues/336#issuecomment-355402508
apply plugin: 'com.github.johnrengelman.shadow'
sourceCompatibility = 1.8
compileKotlin {
kotlinOptions.jvmTarget = "1.8"
}
compileTestKotlin {
kotlinOptions.jvmTarget = "1.8"
}
shadowJar {
baseName = 'kotlin-server-deprecated'
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" }
}
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-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'
}

View File

@ -0,0 +1 @@
org.gradle.caching=true

View File

@ -0,0 +1 @@
rootProject.name = 'kotlin-server-deprecated'

View File

@ -0,0 +1,91 @@
package org.openapitools.server
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
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.metrics.Metrics
import io.ktor.routing.Routing
import java.util.concurrent.TimeUnit
import io.ktor.util.KtorExperimentalAPI
import io.ktor.auth.Authentication
import io.ktor.auth.oauth
import org.openapitools.server.infrastructure.ApiKeyCredential
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
internal val settings = HoconApplicationConfig(ConfigFactory.defaultApplication(HTTP::class.java.classLoader))
object HTTP {
val client = HttpClient(Apache)
}
@KtorExperimentalAPI
@KtorExperimentalLocationsAPI
fun Application.main() {
install(DefaultHeaders)
install(Metrics) {
val reporter = Slf4jReporter.forRegistry(registry)
.outputTo(log)
.convertRatesTo(TimeUnit.SECONDS)
.convertDurationsTo(TimeUnit.MILLISECONDS)
.build()
reporter.start(10, TimeUnit.SECONDS)
}
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(Authentication) {
// "Implement API key auth (api_key) for parameter name 'api_key'."
apiKeyAuth("api_key") {
validate { apikeyCredential: ApiKeyCredential ->
when {
apikeyCredential.value == "keyboardcat" -> ApiPrincipal(apikeyCredential)
else -> null
}
}
}
oauth("petstore_auth") {
client = HttpClient(Apache)
providerLookup = { ApplicationAuthProviders["petstore_auth"] }
urlProvider = { _ ->
// TODO: define a callback url here.
"/"
}
}
}
install(Routing) {
PetApi()
StoreApi()
UserApi()
}
environment.monitor.subscribe(ApplicationStopping)
{
HTTP.client.close()
}
}

View File

@ -0,0 +1,82 @@
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.util.KtorExperimentalAPI
import java.time.Duration
import java.util.concurrent.Executors
import org.openapitools.server.settings
/**
* Application block for [HSTS] configuration.
*
* This file may be excluded in .openapi-generator-ignore,
* and application specific configuration can be applied in this function.
*
* See http://ktor.io/features/hsts.html
*/
internal fun ApplicationHstsConfiguration(): HSTS.Configuration.() -> Unit {
return {
maxAge = Duration.ofDays(365)
includeSubDomains = true
preload = false
// You may also apply any custom directives supported by specific user-agent. For example:
// customDirectives.put("redirectHttpToHttps", "false")
}
}
/**
* Application block for [Compression] configuration.
*
* This file may be excluded in .openapi-generator-ignore,
* and application specific configuration can be applied in this function.
*
* See http://ktor.io/features/compression.html
*/
internal fun ApplicationCompressionConfiguration(): Compression.Configuration.() -> Unit {
return {
gzip {
priority = 1.0
}
deflate {
priority = 10.0
minimumSize(1024) // condition
}
}
}
// Defines authentication mechanisms used throughout the application.
@KtorExperimentalAPI
val ApplicationAuthProviders: Map<String, OAuthServerSettings> = listOf<OAuthServerSettings>(
OAuthServerSettings.OAuth2ServerSettings(
name = "petstore_auth",
authorizeUrl = "http://petstore.swagger.io/api/oauth/dialog",
accessTokenUrl = "",
requestMethod = HttpMethod.Get,
clientId = settings.property("auth.oauth.petstore_auth.clientId").getString(),
clientSecret = settings.property("auth.oauth.petstore_auth.clientSecret").getString(),
defaultScopes = listOf("write:pets", "read:pets")
)
// OAuthServerSettings.OAuth2ServerSettings(
// name = "facebook",
// authorizeUrl = "https://graph.facebook.com/oauth/authorize",
// accessTokenUrl = "https://graph.facebook.com/oauth/access_token",
// requestMethod = HttpMethod.Post,
//
// clientId = "settings.property("auth.oauth.facebook.clientId").getString()",
// clientSecret = "settings.property("auth.oauth.facebook.clientSecret").getString()",
// defaultScopes = listOf("public_profile")
// )
).associateBy { it.name }
// Provides an application-level fixed thread pool on which to execute coroutines (mainly)
internal val ApplicationExecutors = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() * 4)

View File

@ -0,0 +1,106 @@
/**
* OpenAPI Petstore
* This is a sample server Petstore server. For this sample, you can use the api key `special-key` to test the authorization filters.
*
* The version of the OpenAPI document: 1.0.0
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
* Do not edit the class manually.
*/
package org.openapitools.server
import io.ktor.locations.KtorExperimentalLocationsAPI
import io.ktor.locations.Location
object Paths {
/**
* Deletes a pet
*
* @param petId Pet id to delete
* @param apiKey (optional)
*/
@KtorExperimentalLocationsAPI
@Location("/pet/{petId}") class deletePet(val petId: kotlin.Long, val apiKey: kotlin.String? = null)
/**
* Finds Pets by status
* Multiple status values can be provided with comma separated strings
* @param status Status values that need to be considered for filter
*/
@KtorExperimentalLocationsAPI
@Location("/pet/findByStatus") class findPetsByStatus(val status: kotlin.Array<kotlin.String>)
/**
* Finds Pets by tags
* Multiple tags can be provided with comma separated strings. Use tag1, tag2, tag3 for testing.
* @param tags Tags to filter by
*/
@KtorExperimentalLocationsAPI
@Location("/pet/findByTags") class findPetsByTags(val tags: kotlin.Array<kotlin.String>)
/**
* Find pet by ID
* Returns a single pet
* @param petId ID of pet to return
*/
@KtorExperimentalLocationsAPI
@Location("/pet/{petId}") class getPetById(val petId: kotlin.Long)
/**
* Delete purchase order by ID
* For valid response try integer IDs with value &lt; 1000. Anything above 1000 or nonintegers will generate API errors
* @param orderId ID of the order that needs to be deleted
*/
@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()
/**
* Find purchase order by ID
* For valid response try integer IDs with value &lt;&#x3D; 5 or &gt; 10. Other values will generated exceptions
* @param orderId ID of pet that needs to be fetched
*/
@KtorExperimentalLocationsAPI
@Location("/store/order/{orderId}") class getOrderById(val orderId: kotlin.Long)
/**
* Delete user
* 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)
/**
* Get user by user name
*
* @param username The name that needs to be fetched. Use user1 for testing.
*/
@KtorExperimentalLocationsAPI
@Location("/user/{username}") class getUserByName(val username: kotlin.String)
/**
* Logs user into the system
*
* @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()
}

View File

@ -0,0 +1,228 @@
/**
* OpenAPI Petstore
* This is a sample server Petstore server. For this sample, you can use the api key `special-key` to test the authorization filters.
*
* The version of the OpenAPI document: 1.0.0
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
* Do not edit the class manually.
*/
package org.openapitools.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.locations.KtorExperimentalLocationsAPI
import io.ktor.locations.delete
import io.ktor.locations.get
import io.ktor.response.respond
import io.ktor.response.respondText
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.infrastructure.ApiPrincipal
import org.openapitools.server.models.ApiResponse
import org.openapitools.server.models.Pet
@KtorExperimentalLocationsAPI
fun Route.PetApi() {
val gson = Gson()
val empty = mutableMapOf<String, Any?>()
route("/pet") {
authenticate("petstore_auth") {
post {
val principal = call.authentication.principal<OAuthAccessTokenResponse>()
if (principal == null) {
call.respond(HttpStatusCode.Unauthorized)
} else {
call.respond(HttpStatusCode.NotImplemented)
}
}
}
}
delete<Paths.deletePet> { _: Paths.deletePet ->
val principal = call.authentication.principal<OAuthAccessTokenResponse>()
if (principal == null) {
call.respond(HttpStatusCode.Unauthorized)
} else {
call.respond(HttpStatusCode.NotImplemented)
}
}
get<Paths.findPetsByStatus> { _: Paths.findPetsByStatus ->
val principal = call.authentication.principal<OAuthAccessTokenResponse>()
if (principal == null) {
call.respond(HttpStatusCode.Unauthorized)
} else {
val exampleContentType = "application/json"
val exampleContentString = """{
"photoUrls" : [ "photoUrls", "photoUrls" ],
"name" : "doggie",
"id" : 0,
"category" : {
"name" : "name",
"id" : 6
},
"tags" : [ {
"name" : "name",
"id" : 1
}, {
"name" : "name",
"id" : 1
} ],
"status" : "available"
}"""
when(exampleContentType) {
"application/json" -> call.respond(gson.fromJson(exampleContentString, empty::class.java))
"application/xml" -> call.respondText(exampleContentString, ContentType.Text.Xml)
else -> call.respondText(exampleContentString)
}
}
}
get<Paths.findPetsByTags> { _: Paths.findPetsByTags ->
val principal = call.authentication.principal<OAuthAccessTokenResponse>()
if (principal == null) {
call.respond(HttpStatusCode.Unauthorized)
} else {
val exampleContentType = "application/json"
val exampleContentString = """{
"photoUrls" : [ "photoUrls", "photoUrls" ],
"name" : "doggie",
"id" : 0,
"category" : {
"name" : "name",
"id" : 6
},
"tags" : [ {
"name" : "name",
"id" : 1
}, {
"name" : "name",
"id" : 1
} ],
"status" : "available"
}"""
when(exampleContentType) {
"application/json" -> call.respond(gson.fromJson(exampleContentString, empty::class.java))
"application/xml" -> call.respondText(exampleContentString, ContentType.Text.Xml)
else -> call.respondText(exampleContentString)
}
}
}
get<Paths.getPetById> { _: Paths.getPetById ->
val principal = call.authentication.principal<ApiPrincipal>()
if (principal == null) {
call.respond(HttpStatusCode.Unauthorized)
} else {
val exampleContentType = "application/json"
val exampleContentString = """{
"photoUrls" : [ "photoUrls", "photoUrls" ],
"name" : "doggie",
"id" : 0,
"category" : {
"name" : "name",
"id" : 6
},
"tags" : [ {
"name" : "name",
"id" : 1
}, {
"name" : "name",
"id" : 1
} ],
"status" : "available"
}"""
when(exampleContentType) {
"application/json" -> call.respond(gson.fromJson(exampleContentString, empty::class.java))
"application/xml" -> call.respondText(exampleContentString, ContentType.Text.Xml)
else -> call.respondText(exampleContentString)
}
}
}
route("/pet") {
authenticate("petstore_auth") {
put {
val principal = call.authentication.principal<OAuthAccessTokenResponse>()
if (principal == null) {
call.respond(HttpStatusCode.Unauthorized)
} else {
call.respond(HttpStatusCode.NotImplemented)
}
}
}
}
route("/pet/{petId}") {
authenticate("petstore_auth") {
post {
val principal = call.authentication.principal<OAuthAccessTokenResponse>()
if (principal == null) {
call.respond(HttpStatusCode.Unauthorized)
} else {
call.respond(HttpStatusCode.NotImplemented)
}
}
}
}
route("/pet/{petId}/uploadImage") {
authenticate("petstore_auth") {
post {
val principal = call.authentication.principal<OAuthAccessTokenResponse>()
if (principal == null) {
call.respond(HttpStatusCode.Unauthorized)
} else {
val exampleContentType = "application/json"
val exampleContentString = """{
"code" : 0,
"type" : "type",
"message" : "message"
}"""
when(exampleContentType) {
"application/json" -> call.respond(gson.fromJson(exampleContentString, empty::class.java))
"application/xml" -> call.respondText(exampleContentString, ContentType.Text.Xml)
else -> call.respondText(exampleContentString)
}
}
}
}
}
}

View File

@ -0,0 +1,99 @@
/**
* OpenAPI Petstore
* This is a sample server Petstore server. For this sample, you can use the api key `special-key` to test the authorization filters.
*
* The version of the OpenAPI document: 1.0.0
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
* Do not edit the class manually.
*/
package org.openapitools.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.locations.KtorExperimentalLocationsAPI
import io.ktor.locations.delete
import io.ktor.locations.get
import io.ktor.response.respond
import io.ktor.response.respondText
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.infrastructure.ApiPrincipal
import org.openapitools.server.models.Order
@KtorExperimentalLocationsAPI
fun Route.StoreApi() {
val gson = Gson()
val empty = mutableMapOf<String, Any?>()
delete<Paths.deleteOrder> { _: Paths.deleteOrder ->
call.respond(HttpStatusCode.NotImplemented)
}
get<Paths.getInventory> { _: Paths.getInventory ->
val principal = call.authentication.principal<ApiPrincipal>()
if (principal == null) {
call.respond(HttpStatusCode.Unauthorized)
} else {
call.respond(HttpStatusCode.NotImplemented)
}
}
get<Paths.getOrderById> { _: Paths.getOrderById ->
val exampleContentType = "application/json"
val exampleContentString = """{
"petId" : 6,
"quantity" : 1,
"id" : 0,
"shipDate" : "2000-01-23T04:56:07.000+00:00",
"complete" : false,
"status" : "placed"
}"""
when(exampleContentType) {
"application/json" -> call.respond(gson.fromJson(exampleContentString, empty::class.java))
"application/xml" -> call.respondText(exampleContentString, ContentType.Text.Xml)
else -> call.respondText(exampleContentString)
}
}
route("/store/order") {
post {
val exampleContentType = "application/json"
val exampleContentString = """{
"petId" : 6,
"quantity" : 1,
"id" : 0,
"shipDate" : "2000-01-23T04:56:07.000+00:00",
"complete" : false,
"status" : "placed"
}"""
when(exampleContentType) {
"application/json" -> call.respond(gson.fromJson(exampleContentString, empty::class.java))
"application/xml" -> call.respondText(exampleContentString, ContentType.Text.Xml)
else -> call.respondText(exampleContentString)
}
}
}
}

View File

@ -0,0 +1,107 @@
/**
* OpenAPI Petstore
* This is a sample server Petstore server. For this sample, you can use the api key `special-key` to test the authorization filters.
*
* The version of the OpenAPI document: 1.0.0
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
* Do not edit the class manually.
*/
package org.openapitools.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.locations.KtorExperimentalLocationsAPI
import io.ktor.locations.delete
import io.ktor.locations.get
import io.ktor.response.respond
import io.ktor.response.respondText
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.infrastructure.ApiPrincipal
import org.openapitools.server.models.User
@KtorExperimentalLocationsAPI
fun Route.UserApi() {
val gson = Gson()
val empty = mutableMapOf<String, Any?>()
route("/user") {
post {
call.respond(HttpStatusCode.NotImplemented)
}
}
route("/user/createWithArray") {
post {
call.respond(HttpStatusCode.NotImplemented)
}
}
route("/user/createWithList") {
post {
call.respond(HttpStatusCode.NotImplemented)
}
}
delete<Paths.deleteUser> { _: Paths.deleteUser ->
call.respond(HttpStatusCode.NotImplemented)
}
get<Paths.getUserByName> { _: Paths.getUserByName ->
val exampleContentType = "application/json"
val exampleContentString = """{
"firstName" : "firstName",
"lastName" : "lastName",
"password" : "password",
"userStatus" : 6,
"phone" : "phone",
"id" : 0,
"email" : "email",
"username" : "username"
}"""
when(exampleContentType) {
"application/json" -> call.respond(gson.fromJson(exampleContentString, empty::class.java))
"application/xml" -> call.respondText(exampleContentString, ContentType.Text.Xml)
else -> call.respondText(exampleContentString)
}
}
get<Paths.loginUser> { _: Paths.loginUser ->
call.respond(HttpStatusCode.NotImplemented)
}
get<Paths.logoutUser> { _: Paths.logoutUser ->
call.respond(HttpStatusCode.NotImplemented)
}
route("/user/{username}") {
put {
call.respond(HttpStatusCode.NotImplemented)
}
}
}

View File

@ -0,0 +1,85 @@
package org.openapitools.server.infrastructure
import io.ktor.application.ApplicationCall
import io.ktor.application.call
import io.ktor.auth.Authentication
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.response.respond
enum class ApiKeyLocation(val location: String) {
QUERY("query"),
HEADER("header")
}
data class ApiKeyCredential(val value: String): Credential
data class ApiPrincipal(val apiKeyCredential: ApiKeyCredential?) : Principal
/**
* Represents a Api Key authentication provider
* @param name is the name of the provider, or `null` for a default provider
*/
class ApiKeyAuthenticationProvider(name: String?) : AuthenticationProvider(name) {
internal var authenticationFunction: suspend ApplicationCall.(ApiKeyCredential) -> Principal? = { null }
var apiKeyName: String = "";
var apiKeyLocation: ApiKeyLocation = ApiKeyLocation.QUERY;
/**
* Sets a validation function that will check given [ApiKeyCredential] instance and return [Principal],
* or null if credential does not correspond to an authenticated principal
*/
fun validate(body: suspend ApplicationCall.(ApiKeyCredential) -> Principal?) {
authenticationFunction = body
}
}
fun Authentication.Configuration.apiKeyAuth(name: String? = null, configure: ApiKeyAuthenticationProvider.() -> Unit) {
val provider = ApiKeyAuthenticationProvider(name).apply(configure)
val apiKeyName = provider.apiKeyName
val apiKeyLocation = provider.apiKeyLocation
val authenticate = provider.authenticationFunction
provider.pipeline.intercept(AuthenticationPipeline.RequestAuthentication) { context ->
val credentials = call.request.apiKeyAuthenticationCredentials(apiKeyName, apiKeyLocation)
val principal = credentials?.let { authenticate(call, it) }
val cause = when {
credentials == null -> AuthenticationFailedCause.NoCredentials
principal == null -> AuthenticationFailedCause.InvalidCredentials
else -> null
}
if (cause != null) {
context.challenge(apiKeyName, cause) {
// TODO: Verify correct response structure here.
call.respond(UnauthorizedResponse(HttpAuthHeader.Parameterized("API_KEY", mapOf("key" to apiKeyName), HeaderValueEncoding.QUOTED_ALWAYS)))
it.complete()
}
}
if (principal != null) {
context.principal(principal)
}
}
}
fun ApplicationRequest.apiKeyAuthenticationCredentials(apiKeyName: String, apiKeyLocation: ApiKeyLocation): ApiKeyCredential? {
val value: String? = when(apiKeyLocation) {
ApiKeyLocation.QUERY -> this.queryParameters[apiKeyName]
ApiKeyLocation.HEADER -> this.headers[apiKeyName]
}
when (value) {
null -> return null
else -> return ApiKeyCredential(value)
}
}

View File

@ -0,0 +1,32 @@
/**
* OpenAPI Petstore
* This is a sample server Petstore server. For this sample, you can use the api key `special-key` to test the authorization filters.
*
* The version of the OpenAPI document: 1.0.0
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
* Do not edit the class manually.
*/
package org.openapitools.server.models
import java.io.Serializable
/**
* Describes the result of uploading an image resource
* @param code
* @param type
* @param message
*/
data class ApiResponse (
val code: kotlin.Int? = null,
val type: kotlin.String? = null,
val message: kotlin.String? = null
) : Serializable
{
companion object {
private const val serialVersionUID: Long = 123
}
}

View File

@ -0,0 +1,30 @@
/**
* OpenAPI Petstore
* This is a sample server Petstore server. For this sample, you can use the api key `special-key` to test the authorization filters.
*
* The version of the OpenAPI document: 1.0.0
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
* Do not edit the class manually.
*/
package org.openapitools.server.models
import java.io.Serializable
/**
* A category for a pet
* @param id
* @param name
*/
data class Category (
val id: kotlin.Long? = null,
val name: kotlin.String? = null
) : Serializable
{
companion object {
private const val serialVersionUID: Long = 123
}
}

View File

@ -0,0 +1,48 @@
/**
* OpenAPI Petstore
* This is a sample server Petstore server. For this sample, you can use the api key `special-key` to test the authorization filters.
*
* The version of the OpenAPI document: 1.0.0
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
* Do not edit the class manually.
*/
package org.openapitools.server.models
import java.io.Serializable
/**
* An order for a pets from the pet store
* @param id
* @param petId
* @param quantity
* @param shipDate
* @param status Order Status
* @param complete
*/
data class Order (
val id: kotlin.Long? = null,
val petId: kotlin.Long? = null,
val quantity: kotlin.Int? = null,
val shipDate: java.time.OffsetDateTime? = null,
/* Order Status */
val status: Order.Status? = null,
val complete: kotlin.Boolean? = null
) : Serializable
{
companion object {
private const val serialVersionUID: Long = 123
}
/**
* Order Status
* Values: placed,approved,delivered
*/
enum class Status(val value: kotlin.String){
placed("placed"),
approved("approved"),
delivered("delivered");
}
}

View File

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

View File

@ -0,0 +1,30 @@
/**
* OpenAPI Petstore
* This is a sample server Petstore server. For this sample, you can use the api key `special-key` to test the authorization filters.
*
* The version of the OpenAPI document: 1.0.0
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
* Do not edit the class manually.
*/
package org.openapitools.server.models
import java.io.Serializable
/**
* A tag for a pet
* @param id
* @param name
*/
data class Tag (
val id: kotlin.Long? = null,
val name: kotlin.String? = null
) : Serializable
{
companion object {
private const val serialVersionUID: Long = 123
}
}

View File

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

View File

@ -0,0 +1,23 @@
ktor {
deployment {
environment = development
port = 8080
autoreload = true
watch = [ org.openapitools.server ]
}
application {
modules = [ org.openapitools.server.AppMainKt.main ]
}
}
# Typesafe config allows multiple ways to provide configuration values without hard-coding them here.
# Please see https://github.com/lightbend/config for details.
auth {
oauth {
petstore_auth {
clientId = ""
clientSecret = ""
}
}
}

View File

@ -0,0 +1,15 @@
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{YYYY-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<root level="trace">
<appender-ref ref="STDOUT"/>
</root>
<logger name="org.eclipse.jetty" level="INFO"/>
<logger name="io.netty" level="INFO"/>
</configuration>