Skip to content

Commit

Permalink
[kotlin-server][javalin5] Add Javalin context to services
Browse files Browse the repository at this point in the history
Sometimes, services need to access certain contexts that aren't explicitly passed as service parameters, like authentication. Since there is not one way to handle auth in Javalin, let's pass the Javalin Context to the service for flexibility. This also allows services to return custom status codes if they want.
  • Loading branch information
dennisameling committed Jun 14, 2024
1 parent f365900 commit 6f5d337
Show file tree
Hide file tree
Showing 12 changed files with 92 additions and 63 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ class {{classname}}(private val service: {{classname}}Service) {
{{#allParams}}* @param {{paramName}} {{description}} {{^required}}(optional{{#defaultValue}}, default to {{{.}}}{{/defaultValue}}){{/required}}
{{/allParams}}*/
fun {{operationId}}(ctx: Context) {
ctx.status(200).json(service.{{operationId}}({{#allParams}}{{>queryParams}}{{>pathParams}}{{>headerParams}}{{>bodyParams}}{{>formParams}}{{^-last}}, {{/-last}}{{/allParams}}))
ctx.status(200).json(service.{{operationId}}({{#allParams}}{{>queryParams}}{{>pathParams}}{{>headerParams}}{{>bodyParams}}{{>formParams}}{{^-last}}, {{/-last}}{{/allParams}}{{#hasParams}}, {{/hasParams}}ctx))
}

{{/operation}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package {{package}}

{{#imports}}import {{import}}
{{/imports}}
import io.javalin.http.Context

{{#operations}}
interface {{classname}}Service {
Expand All @@ -16,6 +17,7 @@ interface {{classname}}Service {
{{#allParams}}
* @param {{{paramName}}} {{description}}{{#required}} (required){{/required}}{{^required}} (optional{{#defaultValue}}, default to {{.}}{{/defaultValue}}){{/required}}
{{/allParams}}
* @param ctx The Javalin context. Especially handy if you need to access things like authentication headers in your service. (required)
* @return {{#responses}}{{message}} (status code {{code}}){{^-last}}
* or {{/-last}}{{/responses}}
{{#isDeprecated}}
Expand All @@ -27,7 +29,7 @@ interface {{classname}}Service {
{{/externalDocs}}
* @see {{classname}}#{{operationId}}
*/
{{#reactive}}{{^isArray}}suspend {{/isArray}}{{/reactive}}fun {{operationId}}({{#allParams}}{{{paramName}}}: {{^isBodyParam}}{{>optionalDataType}}{{/isBodyParam}}{{#isBodyParam}}{{^reactive}}{{>optionalDataType}}{{/reactive}}{{#reactive}}{{^isArray}}{{>optionalDataType}}{{/isArray}}{{#isArray}}Flow<{{{baseType}}}>{{/isArray}}{{/reactive}}{{/isBodyParam}}{{^-last}}, {{/-last}}{{/allParams}}): {{>returnTypes}}
{{#reactive}}{{^isArray}}suspend {{/isArray}}{{/reactive}}fun {{operationId}}({{#allParams}}{{{paramName}}}: {{^isBodyParam}}{{>optionalDataType}}{{/isBodyParam}}{{#isBodyParam}}{{^reactive}}{{>optionalDataType}}{{/reactive}}{{#reactive}}{{^isArray}}{{>optionalDataType}}{{/isArray}}{{#isArray}}Flow<{{{baseType}}}>{{/isArray}}{{/reactive}}{{/isBodyParam}}{{^-last}}, {{/-last}}{{/allParams}}{{#hasParams}}, {{/hasParams}}ctx: Context): {{>returnTypes}}
{{/operation}}
}
{{/operations}}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package {{package}}

{{#imports}}import {{import}}
{{/imports}}
import io.javalin.http.Context
{{#reactive}}
import kotlinx.coroutines.flow.Flow
{{/reactive}}
Expand All @@ -10,7 +11,7 @@ import kotlinx.coroutines.flow.Flow
class {{classname}}ServiceImpl : {{classname}}Service {
{{#operation}}

override {{#reactive}}{{^isArray}}suspend {{/isArray}}{{/reactive}}fun {{operationId}}({{#allParams}}{{paramName}}: {{^isBodyParam}}{{>optionalDataType}}{{/isBodyParam}}{{#isBodyParam}}{{^reactive}}{{>optionalDataType}}{{/reactive}}{{#reactive}}{{^isArray}}{{>optionalDataType}}{{/isArray}}{{#isArray}}Flow<{{{baseType}}}>{{/isArray}}{{/reactive}}{{/isBodyParam}}{{^-last}}, {{/-last}}{{/allParams}}): {{>returnTypes}} {
override {{#reactive}}{{^isArray}}suspend {{/isArray}}{{/reactive}}fun {{operationId}}({{#allParams}}{{paramName}}: {{^isBodyParam}}{{>optionalDataType}}{{/isBodyParam}}{{#isBodyParam}}{{^reactive}}{{>optionalDataType}}{{/reactive}}{{#reactive}}{{^isArray}}{{>optionalDataType}}{{/isArray}}{{#isArray}}Flow<{{{baseType}}}>{{/isArray}}{{/reactive}}{{/isBodyParam}}{{^-last}}, {{/-last}}{{/allParams}}{{#hasParams}}, {{/hasParams}}ctx: Context): {{>returnTypes}} {
TODO("Implement me")
}
{{/operation}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ class PetApi(private val service: PetApiService) {
* @param pet Pet object that needs to be added to the store
*/
fun addPet(ctx: Context) {
ctx.status(200).json(service.addPet(ctx.bodyAsClass<Pet>()))
ctx.status(200).json(service.addPet(ctx.bodyAsClass<Pet>(), ctx))
}

/**
Expand All @@ -25,7 +25,7 @@ class PetApi(private val service: PetApiService) {
* @param apiKey (optional)
*/
fun deletePet(ctx: Context) {
ctx.status(200).json(service.deletePet(ctx.pathParamAsClass<kotlin.Long>("petId").get(), ctx.header("api_key")))
ctx.status(200).json(service.deletePet(ctx.pathParamAsClass<kotlin.Long>("petId").get(), ctx.header("api_key"), ctx))
}

/**
Expand All @@ -34,7 +34,7 @@ class PetApi(private val service: PetApiService) {
* @param status Status values that need to be considered for filter
*/
fun findPetsByStatus(ctx: Context) {
ctx.status(200).json(service.findPetsByStatus(ctx.queryParams("status")))
ctx.status(200).json(service.findPetsByStatus(ctx.queryParams("status"), ctx))
}

/**
Expand All @@ -43,7 +43,7 @@ class PetApi(private val service: PetApiService) {
* @param tags Tags to filter by
*/
fun findPetsByTags(ctx: Context) {
ctx.status(200).json(service.findPetsByTags(ctx.queryParams("tags")))
ctx.status(200).json(service.findPetsByTags(ctx.queryParams("tags"), ctx))
}

/**
Expand All @@ -52,7 +52,7 @@ class PetApi(private val service: PetApiService) {
* @param petId ID of pet to return
*/
fun getPetById(ctx: Context) {
ctx.status(200).json(service.getPetById(ctx.pathParamAsClass<kotlin.Long>("petId").get()))
ctx.status(200).json(service.getPetById(ctx.pathParamAsClass<kotlin.Long>("petId").get(), ctx))
}

/**
Expand All @@ -61,7 +61,7 @@ class PetApi(private val service: PetApiService) {
* @param pet Pet object that needs to be added to the store
*/
fun updatePet(ctx: Context) {
ctx.status(200).json(service.updatePet(ctx.bodyAsClass<Pet>()))
ctx.status(200).json(service.updatePet(ctx.bodyAsClass<Pet>(), ctx))
}

/**
Expand All @@ -72,7 +72,7 @@ class PetApi(private val service: PetApiService) {
* @param status Updated status of the pet (optional)
*/
fun updatePetWithForm(ctx: Context) {
ctx.status(200).json(service.updatePetWithForm(ctx.pathParamAsClass<kotlin.Long>("petId").get(), ctx.formParam("name"), ctx.formParam("status")))
ctx.status(200).json(service.updatePetWithForm(ctx.pathParamAsClass<kotlin.Long>("petId").get(), ctx.formParam("name"), ctx.formParam("status"), ctx))
}

/**
Expand All @@ -83,7 +83,7 @@ class PetApi(private val service: PetApiService) {
* @param file file to upload (optional)
*/
fun uploadFile(ctx: Context) {
ctx.status(200).json(service.uploadFile(ctx.pathParamAsClass<kotlin.Long>("petId").get(), ctx.formParam("additionalMetadata"), ctx.uploadedFile("file")))
ctx.status(200).json(service.uploadFile(ctx.pathParamAsClass<kotlin.Long>("petId").get(), ctx.formParam("additionalMetadata"), ctx.uploadedFile("file"), ctx))
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package org.openapitools.server.apis

import org.openapitools.server.models.ModelApiResponse
import org.openapitools.server.models.Pet
import io.javalin.http.Context

interface PetApiService {

Expand All @@ -10,63 +11,69 @@ interface PetApiService {
*
*
* @param pet Pet object that needs to be added to the store (required)
* @param ctx The Javalin context. Especially handy if you need to access things like authentication headers in your service. (required)
* @return successful operation (status code 200)
* or Invalid input (status code 405)
* @see PetApi#addPet
*/
fun addPet(pet: Pet): Pet
fun addPet(pet: Pet, ctx: Context): Pet

/**
* DELETE /pet/{petId} : Deletes a pet
*
*
* @param petId Pet id to delete (required)
* @param apiKey (optional)
* @param ctx The Javalin context. Especially handy if you need to access things like authentication headers in your service. (required)
* @return Invalid pet value (status code 400)
* @see PetApi#deletePet
*/
fun deletePet(petId: kotlin.Long, apiKey: kotlin.String?): Unit
fun deletePet(petId: kotlin.Long, apiKey: kotlin.String?, ctx: Context): Unit

/**
* GET /pet/findByStatus : 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 (required)
* @param ctx The Javalin context. Especially handy if you need to access things like authentication headers in your service. (required)
* @return successful operation (status code 200)
* or Invalid status value (status code 400)
* @see PetApi#findPetsByStatus
*/
fun findPetsByStatus(status: kotlin.collections.List<kotlin.String>): List<Pet>
fun findPetsByStatus(status: kotlin.collections.List<kotlin.String>, ctx: Context): List<Pet>

/**
* GET /pet/findByTags : 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 (required)
* @param ctx The Javalin context. Especially handy if you need to access things like authentication headers in your service. (required)
* @return successful operation (status code 200)
* or Invalid tag value (status code 400)
* @deprecated
* @see PetApi#findPetsByTags
*/
fun findPetsByTags(tags: kotlin.collections.List<kotlin.String>): List<Pet>
fun findPetsByTags(tags: kotlin.collections.List<kotlin.String>, ctx: Context): List<Pet>

/**
* GET /pet/{petId} : Find pet by ID
* Returns a single pet
*
* @param petId ID of pet to return (required)
* @param ctx The Javalin context. Especially handy if you need to access things like authentication headers in your service. (required)
* @return successful operation (status code 200)
* or Invalid ID supplied (status code 400)
* or Pet not found (status code 404)
* @see PetApi#getPetById
*/
fun getPetById(petId: kotlin.Long): Pet
fun getPetById(petId: kotlin.Long, ctx: Context): Pet

/**
* PUT /pet : Update an existing pet
*
*
* @param pet Pet object that needs to be added to the store (required)
* @param ctx The Javalin context. Especially handy if you need to access things like authentication headers in your service. (required)
* @return successful operation (status code 200)
* or Invalid ID supplied (status code 400)
* or Pet not found (status code 404)
Expand All @@ -75,7 +82,7 @@ interface PetApiService {
* @see <a href="http://petstore.swagger.io/v2/doc/updatePet">Update an existing pet Documentation</a>
* @see PetApi#updatePet
*/
fun updatePet(pet: Pet): Pet
fun updatePet(pet: Pet, ctx: Context): Pet

/**
* POST /pet/{petId} : Updates a pet in the store with form data
Expand All @@ -84,10 +91,11 @@ interface PetApiService {
* @param petId ID of pet that needs to be updated (required)
* @param name Updated name of the pet (optional)
* @param status Updated status of the pet (optional)
* @param ctx The Javalin context. Especially handy if you need to access things like authentication headers in your service. (required)
* @return Invalid input (status code 405)
* @see PetApi#updatePetWithForm
*/
fun updatePetWithForm(petId: kotlin.Long, name: kotlin.String?, status: kotlin.String?): Unit
fun updatePetWithForm(petId: kotlin.Long, name: kotlin.String?, status: kotlin.String?, ctx: Context): Unit

/**
* POST /pet/{petId}/uploadImage : uploads an image
Expand All @@ -96,8 +104,9 @@ interface PetApiService {
* @param petId ID of pet to update (required)
* @param additionalMetadata Additional data to pass to server (optional)
* @param file file to upload (optional)
* @param ctx The Javalin context. Especially handy if you need to access things like authentication headers in your service. (required)
* @return successful operation (status code 200)
* @see PetApi#uploadFile
*/
fun uploadFile(petId: kotlin.Long, additionalMetadata: kotlin.String?, file: io.javalin.http.UploadedFile?): ModelApiResponse
fun uploadFile(petId: kotlin.Long, additionalMetadata: kotlin.String?, file: io.javalin.http.UploadedFile?, ctx: Context): ModelApiResponse
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,38 +2,39 @@ package org.openapitools.server.apis

import org.openapitools.server.models.ModelApiResponse
import org.openapitools.server.models.Pet
import io.javalin.http.Context

class PetApiServiceImpl : PetApiService {

override fun addPet(pet: Pet): Pet {
override fun addPet(pet: Pet, ctx: Context): Pet {
TODO("Implement me")
}

override fun deletePet(petId: kotlin.Long, apiKey: kotlin.String?): Unit {
override fun deletePet(petId: kotlin.Long, apiKey: kotlin.String?, ctx: Context): Unit {
TODO("Implement me")
}

override fun findPetsByStatus(status: kotlin.collections.List<kotlin.String>): List<Pet> {
override fun findPetsByStatus(status: kotlin.collections.List<kotlin.String>, ctx: Context): List<Pet> {
TODO("Implement me")
}

override fun findPetsByTags(tags: kotlin.collections.List<kotlin.String>): List<Pet> {
override fun findPetsByTags(tags: kotlin.collections.List<kotlin.String>, ctx: Context): List<Pet> {
TODO("Implement me")
}

override fun getPetById(petId: kotlin.Long): Pet {
override fun getPetById(petId: kotlin.Long, ctx: Context): Pet {
TODO("Implement me")
}

override fun updatePet(pet: Pet): Pet {
override fun updatePet(pet: Pet, ctx: Context): Pet {
TODO("Implement me")
}

override fun updatePetWithForm(petId: kotlin.Long, name: kotlin.String?, status: kotlin.String?): Unit {
override fun updatePetWithForm(petId: kotlin.Long, name: kotlin.String?, status: kotlin.String?, ctx: Context): Unit {
TODO("Implement me")
}

override fun uploadFile(petId: kotlin.Long, additionalMetadata: kotlin.String?, file: io.javalin.http.UploadedFile?): ModelApiResponse {
override fun uploadFile(petId: kotlin.Long, additionalMetadata: kotlin.String?, file: io.javalin.http.UploadedFile?, ctx: Context): ModelApiResponse {
TODO("Implement me")
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,15 @@ class StoreApi(private val service: StoreApiService) {
* @param orderId ID of the order that needs to be deleted
*/
fun deleteOrder(ctx: Context) {
ctx.status(200).json(service.deleteOrder(ctx.pathParamAsClass<kotlin.String>("orderId").get()))
ctx.status(200).json(service.deleteOrder(ctx.pathParamAsClass<kotlin.String>("orderId").get(), ctx))
}

/**
* Returns pet inventories by status
* Returns a map of status codes to quantities
*/
fun getInventory(ctx: Context) {
ctx.status(200).json(service.getInventory())
ctx.status(200).json(service.getInventory(ctx))
}

/**
Expand All @@ -31,7 +31,7 @@ class StoreApi(private val service: StoreApiService) {
* @param orderId ID of pet that needs to be fetched
*/
fun getOrderById(ctx: Context) {
ctx.status(200).json(service.getOrderById(ctx.pathParamAsClass<kotlin.Long>("orderId").get()))
ctx.status(200).json(service.getOrderById(ctx.pathParamAsClass<kotlin.Long>("orderId").get(), ctx))
}

/**
Expand All @@ -40,7 +40,7 @@ class StoreApi(private val service: StoreApiService) {
* @param order order placed for purchasing the pet
*/
fun placeOrder(ctx: Context) {
ctx.status(200).json(service.placeOrder(ctx.bodyAsClass<Order>()))
ctx.status(200).json(service.placeOrder(ctx.bodyAsClass<Order>(), ctx))
}

}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package org.openapitools.server.apis

import org.openapitools.server.models.Order
import io.javalin.http.Context

interface StoreApiService {

Expand All @@ -9,41 +10,45 @@ interface StoreApiService {
* 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 (required)
* @param ctx The Javalin context. Especially handy if you need to access things like authentication headers in your service. (required)
* @return Invalid ID supplied (status code 400)
* or Order not found (status code 404)
* @see StoreApi#deleteOrder
*/
fun deleteOrder(orderId: kotlin.String): Unit
fun deleteOrder(orderId: kotlin.String, ctx: Context): Unit

/**
* GET /store/inventory : Returns pet inventories by status
* Returns a map of status codes to quantities
*
* @param ctx The Javalin context. Especially handy if you need to access things like authentication headers in your service. (required)
* @return successful operation (status code 200)
* @see StoreApi#getInventory
*/
fun getInventory(): Map<String, kotlin.Int>
fun getInventory(ctx: Context): Map<String, kotlin.Int>

/**
* GET /store/order/{orderId} : Find purchase order by ID
* For valid response try integer IDs with value &lt;&#x3D; 5 or &gt; 10. Other values will generate exceptions
*
* @param orderId ID of pet that needs to be fetched (required)
* @param ctx The Javalin context. Especially handy if you need to access things like authentication headers in your service. (required)
* @return successful operation (status code 200)
* or Invalid ID supplied (status code 400)
* or Order not found (status code 404)
* @see StoreApi#getOrderById
*/
fun getOrderById(orderId: kotlin.Long): Order
fun getOrderById(orderId: kotlin.Long, ctx: Context): Order

/**
* POST /store/order : Place an order for a pet
*
*
* @param order order placed for purchasing the pet (required)
* @param ctx The Javalin context. Especially handy if you need to access things like authentication headers in your service. (required)
* @return successful operation (status code 200)
* or Invalid Order (status code 400)
* @see StoreApi#placeOrder
*/
fun placeOrder(order: Order): Order
fun placeOrder(order: Order, ctx: Context): Order
}
Loading

0 comments on commit 6f5d337

Please sign in to comment.