diff --git a/bin/kotlin-vertx-server-petstore.sh b/bin/kotlin-vertx-server-petstore.sh new file mode 100755 index 0000000000000000000000000000000000000000..73d0d087f3bd7f16b8d1cc92b7a4b71385b0773b --- /dev/null +++ b/bin/kotlin-vertx-server-petstore.sh @@ -0,0 +1,31 @@ +#!/bin/sh + +SCRIPT="$0" + +while [ -h "$SCRIPT" ] ; do + ls=$(ls -ld "$SCRIPT") + link=$(expr "$ls" : '.*-> \(.*\)$') + if expr "$link" : '/.*' > /dev/null; then + SCRIPT="$link" + else + SCRIPT=$(dirname "$SCRIPT")/"$link" + fi +done + +if [ ! -d "${APP_DIR}" ]; then + APP_DIR=$(dirname "$SCRIPT")/.. + APP_DIR=$(cd "${APP_DIR}"; pwd) +fi + +executable="./modules/openapi-generator-cli/target/openapi-generator-cli.jar" + +if [ ! -f "$executable" ] +then + mvn clean package +fi + +# if you've executed sbt assembly previously it will use that instead. +export JAVA_OPTS="${JAVA_OPTS} -Xmx1024M -DloggerPath=conf/log4j.properties" +ags="$@ generate -i modules/openapi-generator/src/test/resources/2_0/petstore.yaml -g kotlin-vertx -o samples/server/petstore/kotlin/vertx" + +java ${JAVA_OPTS} -jar ${executable} ${ags} diff --git a/bin/windows/kotlin-vertx-server-petstore.bat b/bin/windows/kotlin-vertx-server-petstore.bat new file mode 100644 index 0000000000000000000000000000000000000000..6fd12f43d82c8b0e0d02d4e5a67c3ef56f288ee3 --- /dev/null +++ b/bin/windows/kotlin-vertx-server-petstore.bat @@ -0,0 +1,10 @@ +set executable=.\modules\openapi-generator-cli\target\openapi-generator-cli.jar + +If Not Exist %executable% ( + mvn clean package +) + +REM set JAVA_OPTS=%JAVA_OPTS% -Xmx1024M -DloggerPath=conf/log4j.properties +set ags=generate --artifact-id "kotlin-vertx-petstore-server" -i modules\openapi-generator\src\test\resources\2_0\petstore.yaml -g kotlin-vertx -o samples\server\petstore\kotlin\vertx + +java %JAVA_OPTS% -jar %executable% %ags% diff --git a/docs/generators.md b/docs/generators.md index 2bb9b1f5e28edfa10790db4824e6f3449f6a26d4..808b3cc5cb427ba66446fab03d5f19348ed65585 100644 --- a/docs/generators.md +++ b/docs/generators.md @@ -95,6 +95,7 @@ The following generators are available: * [jaxrs-spec](generators/jaxrs-spec) * [kotlin-server](generators/kotlin-server) * [kotlin-spring](generators/kotlin-spring) +* [korlin-vertx](generators/kotlin-vertx) * [nodejs-express-server (beta)](generators/nodejs-express-server) * [nodejs-server-deprecated (deprecated)](generators/nodejs-server-deprecated) * [php-laravel](generators/php-laravel) diff --git a/docs/generators/kotlin-vertx.md b/docs/generators/kotlin-vertx.md new file mode 100644 index 0000000000000000000000000000000000000000..6759792afbf8f4974f66b7563e400aa6a29f2195 --- /dev/null +++ b/docs/generators/kotlin-vertx.md @@ -0,0 +1,18 @@ + +--- +id: generator-opts-server-kotlin-vertx +title: Config Options for kotlin-vertx +sidebar_label: kotlin-vertx +--- + +| Option | Description | Values | Default | +| ------ | ----------- | ------ | ------- | +|sourceFolder|source folder for generated code| |src/main/kotlin| +|modelPackage|package for generated models| |org.openapitools.server.api.model| +|apiPackage|package for generated api classes| |org.openapitools.server.api.verticle| +|apiSuffix|suffix for api classes| |Api| +|groupId|Generated artifact package's organization (i.e. maven groupId).| |org.openapitools| +|artifactId|Generated artifact id (name of jar).| |kotlin-server| +|artifactVersion|Generated artifact's package version.| |1.0.0| +|enumPropertyNaming|Naming convention for enum properties: 'camelCase', 'PascalCase', 'snake_case', 'UPPERCASE', and 'original'| |camelCase| +|parcelizeModels|toggle "@Parcelize" for generated models| |null| diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinVertxServerCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinVertxServerCodegen.java new file mode 100644 index 0000000000000000000000000000000000000000..19863e9a67b8f94ea2136609a3aed43f9365e6a2 --- /dev/null +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinVertxServerCodegen.java @@ -0,0 +1,85 @@ +/* + * Copyright 2018 OpenAPI-Generator Contributors (https://openapi-generator.tech) + * + * 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 + * + * http://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 org.openapitools.codegen.CodegenConstants; +import org.openapitools.codegen.CodegenType; +import org.openapitools.codegen.SupportingFile; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; +import java.util.Locale; + +public class KotlinVertxServerCodegen extends AbstractKotlinCodegen { + + protected String rootPackage = "org.openapitools.server.api"; + protected String apiVersion = "1.0.0-SNAPSHOT"; + + public static final String ROOT_PACKAGE = "rootPackage"; + + public static final String PROJECT_NAME = "projectName"; + + static Logger LOGGER = LoggerFactory.getLogger(KotlinVertxServerCodegen.class); + + public CodegenType getTag() { + return CodegenType.SERVER; + } + + public String getName() { + return "kotlin-vertx"; + } + + public String getHelp() { + return "Generates a kotlin-vertx server."; + } + + public KotlinVertxServerCodegen() { + super(); + + outputFolder = "generated-code" + File.separator + "kotlin-vertx"; + modelTemplateFiles.put("model.mustache", ".kt"); + + apiTestTemplateFiles.clear(); + modelDocTemplateFiles.clear(); + supportingFiles.clear(); + + apiTemplateFiles.clear(); + apiTemplateFiles.put("api.mustache", ".kt"); + apiTemplateFiles.put("apiProxy.mustache", "VertxProxyHandler.kt"); + apiTemplateFiles.put("api_verticle.mustache","Verticle.kt"); + + embeddedTemplateDir = templateDir = "kotlin-vertx-server"; + apiPackage = rootPackage + ".verticle"; + modelPackage = rootPackage + ".model"; + artifactId = "openapi-kotlin-vertx-server"; + artifactVersion = apiVersion; + + updateOption(CodegenConstants.API_PACKAGE, apiPackage); + updateOption(CodegenConstants.MODEL_PACKAGE, modelPackage); + additionalProperties.put(ROOT_PACKAGE, rootPackage); + + supportingFiles.add(new SupportingFile("pom.mustache", "", "pom.xml")); + supportingFiles.add(new SupportingFile("README.mustache", "", "README.md")); + + } + + @Override + public String escapeReservedWord(String name) { + return name; + } +} diff --git a/modules/openapi-generator/src/main/resources/META-INF/services/org.openapitools.codegen.CodegenConfig b/modules/openapi-generator/src/main/resources/META-INF/services/org.openapitools.codegen.CodegenConfig index dcd64831edc6d0ddb0d8e05c930d5584b6e9ae92..5a6cb16c1ac2debf2516c37b9b4d50d9c7355e06 100644 --- a/modules/openapi-generator/src/main/resources/META-INF/services/org.openapitools.codegen.CodegenConfig +++ b/modules/openapi-generator/src/main/resources/META-INF/services/org.openapitools.codegen.CodegenConfig @@ -28,6 +28,7 @@ org.openapitools.codegen.languages.ErlangClientCodegen org.openapitools.codegen.languages.ErlangProperCodegen org.openapitools.codegen.languages.ErlangServerCodegen org.openapitools.codegen.languages.FlashClientCodegen +org.openapitools.codegen.languages.FsharpGiraffeServerCodegen org.openapitools.codegen.languages.GoClientCodegen org.openapitools.codegen.languages.GoClientExperimentalCodegen org.openapitools.codegen.languages.GoServerCodegen @@ -38,6 +39,7 @@ org.openapitools.codegen.languages.GroovyClientCodegen org.openapitools.codegen.languages.KotlinClientCodegen org.openapitools.codegen.languages.KotlinServerCodegen org.openapitools.codegen.languages.KotlinSpringServerCodegen +org.openapitools.codegen.languages.KotlinVertxServerCodegen org.openapitools.codegen.languages.HaskellHttpClientCodegen org.openapitools.codegen.languages.HaskellServantCodegen org.openapitools.codegen.languages.JavaClientCodegen @@ -114,5 +116,4 @@ org.openapitools.codegen.languages.TypeScriptJqueryClientCodegen org.openapitools.codegen.languages.TypeScriptNodeClientCodegen org.openapitools.codegen.languages.TypeScriptRxjsClientCodegen org.openapitools.codegen.languages.FsharpGiraffeServerCodegen - org.openapitools.codegen.languages.AsciidocDocumentationCodegen diff --git a/modules/openapi-generator/src/main/resources/kotlin-vertx-server/README.mustache b/modules/openapi-generator/src/main/resources/kotlin-vertx-server/README.mustache new file mode 100644 index 0000000000000000000000000000000000000000..f4db05742d00a09b2f593563da1811f20feea6f2 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/kotlin-vertx-server/README.mustache @@ -0,0 +1,76 @@ +# {{packageName}} - Kotlin Server library for {{appName}} + +## Requires + +* Kotlin 1.3.10 +* Maven 3.3 + +## Build + +``` +mvn clean package +``` + +This runs all tests and packages the library. + +## Features/Implementation Notes + +* Supports JSON inputs/outputs 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}} \ No newline at end of file diff --git a/modules/openapi-generator/src/main/resources/kotlin-vertx-server/api.mustache b/modules/openapi-generator/src/main/resources/kotlin-vertx-server/api.mustache new file mode 100644 index 0000000000000000000000000000000000000000..2792719607431920f8e32d6b6d714c40993cdc08 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/kotlin-vertx-server/api.mustache @@ -0,0 +1,53 @@ +package {{package}} + +{{#imports}}import {{import}} +{{/imports}} +import io.vertx.core.Vertx +import io.vertx.core.json.JsonObject +import io.vertx.core.json.JsonArray +import com.github.wooyme.openapi.Response +import io.vertx.ext.web.api.OperationRequest +import io.vertx.kotlin.ext.web.api.contract.openapi3.OpenAPI3RouterFactory +import io.vertx.serviceproxy.ServiceBinder +import io.vertx.ext.web.handler.CookieHandler +import io.vertx.ext.web.handler.SessionHandler +import io.vertx.ext.web.sstore.LocalSessionStore +import java.util.List +import java.util.Map + + +interface {{classname}} { + fun init(vertx:Vertx,config:JsonObject) +{{#operations}} + {{#operation}} + /* {{operationId}} + * {{summary}} */ + suspend fun {{operationId}}({{#allParams}}{{paramName}}:{{^isFile}}{{{dataType}}}{{/isFile}}{{#isFile}}kotlin.collections.List<java.io.File>{{/isFile}}{{^isRequired}}?{{/isRequired}},{{/allParams}}context:OperationRequest):Response<{{#returnType}}{{{returnType}}}{{/returnType}}{{^returnType}}Void{{/returnType}}> + {{/operation}} +{{/operations}} + companion object { + const val address = "{{classname}}-service" + suspend fun createRouterFactory(vertx: Vertx,path:String): io.vertx.ext.web.api.contract.openapi3.OpenAPI3RouterFactory { + val routerFactory = OpenAPI3RouterFactory.createAwait(vertx,path) + routerFactory.addGlobalHandler(CookieHandler.create()) + routerFactory.addGlobalHandler(SessionHandler.create(LocalSessionStore.create(vertx))) + routerFactory.setExtraOperationContextPayloadMapper{ + JsonObject().put("files",JsonArray(it.fileUploads().map { it.uploadedFileName() })) + } + val opf = routerFactory::class.java.getDeclaredField("operations") + opf.isAccessible = true + val operations = opf.get(routerFactory) as Map<String, Any> + for (m in {{classname}}::class.java.methods) { + val methodName = m.name + val op = operations[methodName] + if (op != null) { + val method = op::class.java.getDeclaredMethod("mountRouteToService",String::class.java,String::class.java) + method.isAccessible = true + method.invoke(op,address,methodName) + } + } + routerFactory.mountServiceInterface({{classname}}::class.java, address) + return routerFactory + } + } +} diff --git a/modules/openapi-generator/src/main/resources/kotlin-vertx-server/apiProxy.mustache b/modules/openapi-generator/src/main/resources/kotlin-vertx-server/apiProxy.mustache new file mode 100644 index 0000000000000000000000000000000000000000..8c6f81f1b43f636f31ec6970219aa6ea074813e8 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/kotlin-vertx-server/apiProxy.mustache @@ -0,0 +1,179 @@ +package {{package}} + +import io.vertx.core.Vertx +import io.vertx.core.eventbus.Message +import io.vertx.core.json.JsonObject +import io.vertx.ext.web.api.OperationRequest +import io.vertx.ext.web.api.OperationResponse +import io.vertx.ext.web.api.generator.ApiHandlerUtils +import io.vertx.serviceproxy.ProxyHandler +import io.vertx.serviceproxy.ServiceException +import io.vertx.serviceproxy.ServiceExceptionMessageCodec +import kotlinx.coroutines.GlobalScope +import kotlinx.coroutines.launch +import io.vertx.kotlin.coroutines.dispatcher +import io.vertx.core.json.Json +import io.vertx.core.json.JsonArray +import com.google.gson.reflect.TypeToken +import com.google.gson.Gson +{{#imports}}import {{import}} +{{/imports}} + +class {{classname}}VertxProxyHandler(private val vertx: Vertx, private val service: {{classname}}, topLevel: Boolean, private val timeoutSeconds: Long) : ProxyHandler() { + private val timerID: Long + private var lastAccessed: Long = 0 + init { + try { + this.vertx.eventBus().registerDefaultCodec(ServiceException::class.java, + ServiceExceptionMessageCodec()) + } catch (ex: IllegalStateException) {} + + if (timeoutSeconds != (-1).toLong() && !topLevel) { + var period = timeoutSeconds * 1000 / 2 + if (period > 10000) { + period = 10000 + } + this.timerID = vertx.setPeriodic(period) { this.checkTimedOut(it) } + } else { + this.timerID = -1 + } + accessed() + } + private fun checkTimedOut(id: Long) { + val now = System.nanoTime() + if (now - lastAccessed > timeoutSeconds * 1000000000) { + close() + } + } + + override fun close() { + if (timerID != (-1).toLong()) { + vertx.cancelTimer(timerID) + } + super.close() + } + + private fun accessed() { + this.lastAccessed = System.nanoTime() + } + override fun handle(msg: Message<JsonObject>) { + try { + val json = msg.body() + val action = msg.headers().get("action") ?: throw IllegalStateException("action not specified") + accessed() + val contextSerialized = json.getJsonObject("context") ?: throw IllegalStateException("Received action $action without OperationRequest \"context\"") + val context = OperationRequest(contextSerialized) + when (action) { + {{#operations}}{{#operation}} + "{{#vendorExtensions}}{{operationId}}{{/vendorExtensions}}" -> { + {{#hasParams}} + val params = context.params + {{#allParams}} + {{#isListContainer}} + val {{paramName}}Param = ApiHandlerUtils.searchJsonArrayInJson(params,"{{#isBodyParam}}body{{/isBodyParam}}{{^isBodyParam}}{{baseName}}{{/isBodyParam}}") + {{#required}} + if({{paramName}}Param == null){ + throw IllegalArgumentException("{{paramName}} is required") + } + val {{paramName}}:{{{dataType}}} = Gson().fromJson({{paramName}}Param.encode() + , object : TypeToken<kotlin.collections.List<{{{baseType}}}>>(){}.type) + {{/required}} + {{^required}} + val {{paramName}}:{{{dataType}}}? = if({{paramName}}Param == null) {{#defaultValue}}{{defaultValue}}{{/defaultValue}}{{^defaultValue}}null{{/defaultValue}} + else Gson().fromJson({{paramName}}Param.encode(), + , object : TypeToken<kotlin.collections.List<{{{baseType}}}>>(){}.type) + {{/required}} + {{/isListContainer}} + {{^isListContainer}} + {{#isFile}} + val {{paramName}}Param = context.extra.getJsonArray("files") + {{#required}} + if ({{paramName}}Param == null) { + throw IllegalArgumentException("{{paramName}} is required") + } + val {{paramName}} = {{paramName}}Param.map{ java.io.File(it as String) } + {{/required}} + {{^required}} + val {{paramName}} = {{paramName}}Param?.map{ java.io.File(it as String) } + {{/required}} + {{/isFile}} + {{#isPrimitiveType}} + {{#isString}} + val {{paramName}} = ApiHandlerUtils.searchStringInJson(params,"{{^isBodyParam}}{{baseName}}{{/isBodyParam}}{{#isBodyParam}}body{{/isBodyParam}}") + {{/isString}} + {{#isDate}} + val {{paramName}} = java.time.LocalDate.parse(ApiHandlerUtils.searchStringInJson(params,"{{^isBodyParam}}{{baseName}}{{/isBodyParam}}{{#isBodyParam}}body{{/isBodyParam}}")) + {{/isDate}} + {{#isDateTime}} + val {{paramName}} = java.time.LocalDateTime.parse(ApiHandlerUtils.searchStringInJson(params,"{{^isBodyParam}}{{baseName}}{{/isBodyParam}}{{#isBodyParam}}body{{/isBodyParam}}")) + {{/isDateTime}} + {{#isEmail}} + val {{paramName}} = ApiHandlerUtils.searchStringInJson(params,"{{^isBodyParam}}{{baseName}}{{/isBodyParam}}{{#isBodyParam}}body{{/isBodyParam}}") + {{/isEmail}} + {{#isUuid}} + val {{paramName}} = ApiHandlerUtils.searchStringInJson(params,"{{^isBodyParam}}{{baseName}}{{/isBodyParam}}{{#isBodyParam}}body{{/isBodyParam}}") + {{/isUuid}} + {{#isNumber}} + val {{paramName}} = ApiHandlerUtils.searchDoubleInJson(params,"{{^isBodyParam}}{{baseName}}{{/isBodyParam}}{{#isBodyParam}}body{{/isBodyParam}}") + {{/isNumber}} + {{#isLong}} + val {{paramName}} = ApiHandlerUtils.searchLongInJson(params,"{{^isBodyParam}}{{baseName}}{{/isBodyParam}}{{#isBodyParam}}body{{/isBodyParam}}") + {{/isLong}} + {{#isInteger}} + val {{paramName}} = ApiHandlerUtils.searchIntegerInJson(params,"{{^isBodyParam}}{{baseName}}{{/isBodyParam}}{{#isBodyParam}}body{{/isBodyParam}}") + {{/isInteger}} + {{#isFloat}} + val {{paramName}} = ApiHandlerUtils.searchDoubleInJson(params,"{{^isBodyParam}}{{baseName}}{{/isBodyParam}}{{#isBodyParam}}body{{/isBodyParam}}")?.toFloat() + {{/isFloat}} + {{#isDouble}} + val {{paramName}} = ApiHandlerUtils.searchDoubleInJson(params,"{{^isBodyParam}}{{baseName}}{{/isBodyParam}}{{#isBodyParam}}body{{/isBodyParam}}") + {{/isDouble}} + {{#isBoolean}} + val {{paramName}} = ApiHandlerUtils.searchStringInJson(params,"{{^isBodyParam}}{{baseName}}{{/isBodyParam}}{{#isBodyParam}}body{{/isBodyParam}}")?.toBoolean() + {{/isBoolean}} + {{#isFreeFormObject}} + val {{paramName}} = ApiHandlerUtils.searchJsonObjectInJson(params,"{{^isBodyParam}}{{baseName}}{{/isBodyParam}}{{#isBodyParam}}body{{/isBodyParam}}") + {{/isFreeFormObject}} + {{#required}} + if({{paramName}} == null){ + throw IllegalArgumentException("{{paramName}} is required") + } + {{/required}} + {{/isPrimitiveType}} + {{^isPrimitiveType}} + val {{paramName}}Param = ApiHandlerUtils.searchJsonObjectInJson(params,"{{^isBodyParam}}{{baseName}}{{/isBodyParam}}{{#isBodyParam}}body{{/isBodyParam}}") + {{#required}} + if ({{paramName}}Param == null) { + throw IllegalArgumentException("{{paramName}} is required") + } + val {{paramName}} = Gson().fromJson({{paramName}}Param.encode(), {{{dataType}}}::class.java) + {{/required}} + {{^required}} + val {{paramName}} = if({{paramName}}Param ==null) null else Gson().fromJson({{paramName}}Param.encode(), {{{dataType}}}::class.java) + {{/required}} + {{/isPrimitiveType}} + {{/isListContainer}} + {{/allParams}} + GlobalScope.launch(vertx.dispatcher()){ + val result = service.{{operationId}}({{#hasParams}}{{#allParams}}{{paramName}},{{/allParams}}{{/hasParams}}context) + {{#isListContainer}} + val payload = JsonArray(Json.encode(result.payload)).toBuffer() + {{/isListContainer}} + {{^isListContainer}} + val payload = JsonObject(Json.encode(result.payload)).toBuffer() + {{/isListContainer}} + val res = OperationResponse(result.statusCode,result.statusMessage,payload,result.headers) + msg.reply(res.toJson()) + }.invokeOnCompletion{ + it?.let{ throw it } + } + {{/hasParams}} + } + {{/operation}}{{/operations}} + } + }catch (t: Throwable) { + msg.reply(ServiceException(500, t.message)) + throw t + } + } +} diff --git a/modules/openapi-generator/src/main/resources/kotlin-vertx-server/api_doc.mustache b/modules/openapi-generator/src/main/resources/kotlin-vertx-server/api_doc.mustache new file mode 100644 index 0000000000000000000000000000000000000000..5a41503df5b99ccb33718e4ede9843658dfea0a1 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/kotlin-vertx-server/api_doc.mustache @@ -0,0 +1,42 @@ +# {{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}}}{{#hasMore}}, {{/hasMore}}{{/allParams}}) + +{{summary}}{{#notes}} + +{{notes}}{{/notes}} + +### 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}}}{{#hasMore}}, {{/hasMore}}{{/consumes}}{{^consumes}}Not defined{{/consumes}} + - **Accept**: {{#produces}}{{{mediaType}}}{{#hasMore}}, {{/hasMore}}{{/produces}}{{^produces}}Not defined{{/produces}} + +{{/operation}} +{{/operations}} diff --git a/modules/openapi-generator/src/main/resources/kotlin-vertx-server/api_verticle.mustache b/modules/openapi-generator/src/main/resources/kotlin-vertx-server/api_verticle.mustache new file mode 100644 index 0000000000000000000000000000000000000000..c168d12e03a3b453a0ec82e118ae6a03bae742e0 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/kotlin-vertx-server/api_verticle.mustache @@ -0,0 +1,19 @@ +package {{package}} +import io.vertx.core.Vertx +import io.vertx.core.AbstractVerticle +import io.vertx.serviceproxy.ServiceBinder + +fun main(){ + Vertx.vertx().deployVerticle({{classname}}Verticle()) +} + +class {{classname}}Verticle:AbstractVerticle() { + + override fun start() { + val instance = (javaClass.classLoader.loadClass("{{package}}.{{classname}}Impl").newInstance() as {{classname}}) + instance.init(vertx,config()) + ServiceBinder(vertx) + .setAddress({{classname}}.address) + .register({{classname}}::class.java,instance) + } +} \ No newline at end of file diff --git a/modules/openapi-generator/src/main/resources/kotlin-vertx-server/class_doc.mustache b/modules/openapi-generator/src/main/resources/kotlin-vertx-server/class_doc.mustache new file mode 100644 index 0000000000000000000000000000000000000000..b363fc5a61f21d12597a3e250bfca5825ec75e5d --- /dev/null +++ b/modules/openapi-generator/src/main/resources/kotlin-vertx-server/class_doc.mustache @@ -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}}{{#readOnly}} [readonly]{{/readOnly}} +{{/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}} diff --git a/modules/openapi-generator/src/main/resources/kotlin-vertx-server/data_class.mustache b/modules/openapi-generator/src/main/resources/kotlin-vertx-server/data_class.mustache new file mode 100644 index 0000000000000000000000000000000000000000..d4c099d64ea79759fc0ccaadf37df9a8fc8a4e16 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/kotlin-vertx-server/data_class.mustache @@ -0,0 +1,42 @@ + +{{#parcelizeModels}} +import android.os.Parcelable +import kotlinx.android.parcel.Parcelize +{{/parcelizeModels}} +import com.google.gson.annotations.SerializedName +import com.fasterxml.jackson.annotation.JsonIgnoreProperties +import com.fasterxml.jackson.annotation.JsonInclude +/** + * {{{description}}} +{{#vars}} + * @param {{name}} {{{description}}} +{{/vars}} + */ +{{#parcelizeModels}} +@Parcelize +{{/parcelizeModels}} +@JsonInclude(JsonInclude.Include.NON_NULL) +@JsonIgnoreProperties(ignoreUnknown = true) +data class {{classname}} ( +{{#requiredVars}} +{{>data_class_req_var}}{{^-last}}, +{{/-last}}{{/requiredVars}}{{#hasRequired}}{{#hasOptional}}, +{{/hasOptional}}{{/hasRequired}}{{#optionalVars}}{{>data_class_opt_var}}{{^-last}}, +{{/-last}}{{/optionalVars}} +){{#parcelizeModels}} : Parcelable{{/parcelizeModels}} { +{{#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}} + {{#requiredVars}} + var {{{name}}} get() = _{{{name}}} ?: throw IllegalArgumentException("{{{name}}} is required") + set(value){ _{{{name}}} = value } + {{/requiredVars}} +} diff --git a/modules/openapi-generator/src/main/resources/kotlin-vertx-server/data_class_opt_var.mustache b/modules/openapi-generator/src/main/resources/kotlin-vertx-server/data_class_opt_var.mustache new file mode 100644 index 0000000000000000000000000000000000000000..809b007586830dfa4b96e9f555ff621d7506f9ab --- /dev/null +++ b/modules/openapi-generator/src/main/resources/kotlin-vertx-server/data_class_opt_var.mustache @@ -0,0 +1,4 @@ +{{#description}} + /* {{{description}}} */ +{{/description}} + var {{{name}}}: {{#isEnum}}{{classname}}.{{nameInCamelCase}}{{/isEnum}}{{^isEnum}}{{{dataType}}}{{/isEnum}}? = {{#defaultvalue}}{{defaultvalue}}{{/defaultvalue}}{{^defaultvalue}}null{{/defaultvalue}} \ No newline at end of file diff --git a/modules/openapi-generator/src/main/resources/kotlin-vertx-server/data_class_req_var.mustache b/modules/openapi-generator/src/main/resources/kotlin-vertx-server/data_class_req_var.mustache new file mode 100644 index 0000000000000000000000000000000000000000..66ec56120beafabedc23d07dc78a2f27353fc8f6 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/kotlin-vertx-server/data_class_req_var.mustache @@ -0,0 +1,4 @@ +{{#description}} + /* {{{description}}} */ +{{/description}} + @SerializedName("{{{name}}}") private var _{{{name}}}: {{#isEnum}}{{classname}}.{{nameInCamelCase}}{{/isEnum}}{{^isEnum}}{{{dataType}}}{{/isEnum}}? \ No newline at end of file diff --git a/modules/openapi-generator/src/main/resources/kotlin-vertx-server/enumClass.mustache b/modules/openapi-generator/src/main/resources/kotlin-vertx-server/enumClass.mustache new file mode 100644 index 0000000000000000000000000000000000000000..0867107d9930647467370ddf02eabc3d07640841 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/kotlin-vertx-server/enumClass.mustache @@ -0,0 +1,17 @@ + + public enum {{{datatypeWithEnum}}} { + {{#allowableValues}}{{#enumVars}}{{{name}}}({{{value}}}){{^-last}}, + {{/-last}}{{#-last}};{{/-last}}{{/enumVars}}{{/allowableValues}} + + private String value; + + {{{datatypeWithEnum}}}(String value) { + this.value = value; + } + + @Override + @JsonValue + public String toString() { + return value; + } + } diff --git a/modules/openapi-generator/src/main/resources/kotlin-vertx-server/enum_class.mustache b/modules/openapi-generator/src/main/resources/kotlin-vertx-server/enum_class.mustache new file mode 100644 index 0000000000000000000000000000000000000000..791398b97894d171d705e79048d75d6dc652f2bc --- /dev/null +++ b/modules/openapi-generator/src/main/resources/kotlin-vertx-server/enum_class.mustache @@ -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}} +} diff --git a/modules/openapi-generator/src/main/resources/kotlin-vertx-server/enum_doc.mustache b/modules/openapi-generator/src/main/resources/kotlin-vertx-server/enum_doc.mustache new file mode 100644 index 0000000000000000000000000000000000000000..fcb3d7e61aa6ef1d7e1cd90b1d6eb3b265216f41 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/kotlin-vertx-server/enum_doc.mustache @@ -0,0 +1,7 @@ +# {{classname}} + +## Enum + +{{#allowableValues}}{{#enumVars}} + * `{{name}}` (value: `{{{value}}}`) +{{/enumVars}}{{/allowableValues}} diff --git a/modules/openapi-generator/src/main/resources/kotlin-vertx-server/licenseInfo.mustache b/modules/openapi-generator/src/main/resources/kotlin-vertx-server/licenseInfo.mustache new file mode 100644 index 0000000000000000000000000000000000000000..3a547de74bb7a2be286e81242b14c95c0f560690 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/kotlin-vertx-server/licenseInfo.mustache @@ -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. +*/ \ No newline at end of file diff --git a/modules/openapi-generator/src/main/resources/kotlin-vertx-server/model.mustache b/modules/openapi-generator/src/main/resources/kotlin-vertx-server/model.mustache new file mode 100644 index 0000000000000000000000000000000000000000..74b63c00c6f576078dd6019c702854040ce934f2 --- /dev/null +++ b/modules/openapi-generator/src/main/resources/kotlin-vertx-server/model.mustache @@ -0,0 +1,11 @@ +{{>licenseInfo}} +package {{modelPackage}} + +{{#imports}}import {{import}} +{{/imports}} + +{{#models}} + {{#model}} + {{#isEnum}}{{>enum_class}}{{/isEnum}}{{^isEnum}}{{>data_class}}{{/isEnum}} + {{/model}} +{{/models}} diff --git a/modules/openapi-generator/src/main/resources/kotlin-vertx-server/pom.mustache b/modules/openapi-generator/src/main/resources/kotlin-vertx-server/pom.mustache new file mode 100644 index 0000000000000000000000000000000000000000..08a7b3496ab3026a9b957ab0bd75678a0ab9713f --- /dev/null +++ b/modules/openapi-generator/src/main/resources/kotlin-vertx-server/pom.mustache @@ -0,0 +1,190 @@ +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> + <modelVersion>4.0.0</modelVersion> + + <groupId>{{groupId}}</groupId> + <artifactId>{{artifactId}}</artifactId> + <version>{{artifactVersion}}</version> + <packaging>jar</packaging> + + <name>{{appName}}</name> + + <properties> + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> + <java.version>1.8</java.version> + <kotlin.version>1.3.10</kotlin.version> + <kotlin.compiler.incremental>true</kotlin.compiler.incremental> + <junit.version>4.12</junit.version> + <vertx.version>3.4.1</vertx.version> + <maven-compiler-plugin.version>3.3</maven-compiler-plugin.version> + <vertx-openapi-router.version>1.0.2</vertx-openapi-router.version> + <maven-shade-plugin.version>2.3</maven-shade-plugin.version> + <jackson-datatype-jsr310.version>2.7.4</jackson-datatype-jsr310.version> + <vertx.version>3.6.0</vertx.version> + </properties> + + <dependencies> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <version>${junit.version}</version> + <scope>test</scope> + </dependency> + + <dependency> + <groupId>io.vertx</groupId> + <artifactId>vertx-unit</artifactId> + <version>${vertx.version}</version> + <scope>test</scope> + </dependency> + + <dependency> + <groupId>com.github.wooyme</groupId> + <artifactId>vertx-openapi-router</artifactId> + <version>${vertx-openapi-router.version}</version> + </dependency> + + <dependency> + <groupId>com.google.code.gson</groupId> + <artifactId>gson</artifactId> + <version>2.8.5</version> + </dependency> + + <dependency> + <groupId>javax.annotation</groupId> + <artifactId>javax.annotation-api</artifactId> + <version>1.2</version> + </dependency> + <dependency> + <groupId>org.jetbrains.kotlin</groupId> + <artifactId>kotlin-stdlib</artifactId> + <version>${kotlin.version}</version> + </dependency> + <dependency> + <groupId>org.jetbrains.kotlinx</groupId> + <artifactId>kotlinx-coroutines-core</artifactId> + <version>RELEASE</version> + </dependency> + + <dependency> + <groupId>io.vertx</groupId> + <artifactId>vertx-core</artifactId> + <version>${vertx.version}</version> + </dependency> + <dependency> + <groupId>io.vertx</groupId> + <artifactId>vertx-web</artifactId> + <version>${vertx.version}</version> + </dependency> + + <dependency> + <groupId>io.vertx</groupId> + <artifactId>vertx-lang-kotlin</artifactId> + <version>${vertx.version}</version> + </dependency> + + <dependency> + <groupId>io.vertx</groupId> + <artifactId>vertx-lang-kotlin-coroutines</artifactId> + <version>${vertx.version}</version> + </dependency> + + <dependency> + <groupId>io.swagger.parser.v3</groupId> + <artifactId>swagger-parser</artifactId> + <version>2.0.5</version> + </dependency> + + <dependency> + <groupId>io.vertx</groupId> + <artifactId>vertx-web-api-contract</artifactId> + <version>${vertx.version}</version> + </dependency> + + <dependency> + <groupId>io.vertx</groupId> + <artifactId>vertx-service-proxy</artifactId> + <version>${vertx.version}</version> + </dependency> + + <dependency> + <groupId>io.vertx</groupId> + <artifactId>vertx-web-api-service</artifactId> + <version>${vertx.version}</version> + </dependency> + + </dependencies> + + <build> + <plugins> + <plugin> + <artifactId>kotlin-maven-plugin</artifactId> + <groupId>org.jetbrains.kotlin</groupId> + <version>${kotlin.version}</version> + <executions> + <execution> + <id>compile</id> + <goals> + <goal>compile</goal> + </goals> + <configuration> + <sourceDirs> + <sourceDir>${project.basedir}/src/main/kotlin</sourceDir> + <sourceDir>${project.basedir}/src/main/java</sourceDir> + </sourceDirs> + <jvmTarget>1.8</jvmTarget> + </configuration> + </execution> + <execution> + <id>test-compile</id> + <goals> + <goal>test-compile</goal> + </goals> + <configuration> + <sourceDirs> + <sourceDir>${project.basedir}/src/test/kotlin</sourceDir> + <sourceDir>${project.basedir}/src/test/java</sourceDir> + </sourceDirs> + <jvmTarget>1.8</jvmTarget> + </configuration> + </execution> + </executions> + </plugin> + + <plugin> + <artifactId>maven-compiler-plugin</artifactId> + <version>${maven-compiler-plugin.version}</version> + <configuration> + <source>${java.version}</source> + <target>${java.version}</target> + </configuration> + </plugin> + + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-shade-plugin</artifactId> + <version>${maven-shade-plugin.version}</version> + <executions> + <execution> + <phase>package</phase> + <goals> + <goal>shade</goal> + </goals> + <configuration> + <transformers> + <transformer + implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"> + <manifestEntries> + <Main-Class>{{apiPackage}}.DefaultApiVerticleKt</Main-Class> + </manifestEntries> + </transformer> + </transformers> + <artifactSet /> + <outputFile>${project.build.directory}/${project.artifactId}-${project.version}-fat.jar</outputFile> + </configuration> + </execution> + </executions> + </plugin> + </plugins> + </build> +</project> \ No newline at end of file