Git Product home page Git Product logo

ktor-swagger-ui's Introduction

Ktor Swagger-UI

Maven Central Checks Passing

This library provides a Ktor plugin to document routes, generate an OpenApi Specification and serve a Swagger UI. It is meant to be minimally invasive, meaning it can be plugged into existing application without requiring immediate changes to the code. Routes can then be gradually enhanced with documentation.

Features

  • minimally invasive (no immediate change to existing code required)
  • provides swagger-ui and openapi-spec with minimal configuration
  • supports most of the OpenAPI 3.1.0 Specification
  • automatic json-schema generation from arbitrary types/classes for bodies and parameters
    • supports generics, inheritance, collections, ...
    • support for Jackson-annotations and swagger Schema-annotations (optional)
    • use with reflection or kotlinx-serialization
    • customizable schema-generation

Documentation

A wiki with a short documentation is available here.

Installation

dependencies {
    implementation "io.github.smiley4:ktor-swagger-ui:<VERSION>"
}

Examples

Runnable examples can be found in ktor-swagger-ui-examples/src/main/kotlin/io/github/smiley4/ktorswaggerui/examples.

Configuration

install(SwaggerUI) {
    swagger {
        swaggerUrl = "swagger-ui"
        forwardRoot = true
    }
    info {
        title = "Example API"
        version = "latest"
        description = "Example API for testing and demonstration purposes."
    }
    server {
        url = "http://localhost:8080"
        description = "Development Server"
    }
}

Routes

get("hello", {
    description = "Hello World Endpoint."
    response {
        HttpStatusCode.OK to {
            description = "Successful Request"
            body<String> { description = "the response" }
        }
        HttpStatusCode.InternalServerError to {
            description = "Something unexpected happened"
        }
    }
}) {
    call.respondText("Hello World!")
}
post("math/{operation}", {
    tags = listOf("test")
    description = "Performs the given operation on the given values and returns the result"
    request {
        pathParameter<String>("operation") {
            description = "the math operation to perform. Either 'add' or 'sub'"
        }
        body<MathRequest>()
    }
    response {
        HttpStatusCode.OK to {
            description = "The operation was successful"
            body<MathResult> {
                description = "The result of the operation"
            }
        }
        HttpStatusCode.BadRequest to {
            description = "An invalid operation was provided"
        }
    }
}) {
    val operation = call.parameters["operation"]!!
    call.receive<MathRequest>().let { request ->
        when (operation) {
            "add" -> call.respond(HttpStatusCode.OK, MathResult(request.a + request.b))
            "sub" -> call.respond(HttpStatusCode.OK, MathResult(request.a - request.b))
            else -> call.respond(HttpStatusCode.BadRequest, Unit)
        }
    }
}

data class MathRequest(
    val a: Int,
    val b: Int
)

data class MathResult(
    val value: Int
)

ktor-swagger-ui's People

Contributors

bernljung avatar blinchk avatar giuliopime avatar mcxinyu avatar mkatrenik avatar ndy2 avatar notnotdaniel avatar s76527 avatar shildebrandt avatar smiley4 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

ktor-swagger-ui's Issues

File Upload feature is not working

https://github.com/SMILEY4/ktor-swagger-ui/wiki/Request-and-Response-Bodies-Basics

I followed the example in the linked wiki above, However, it is displayed as shown in the picture below.

2

The function I want is like the picture below. How do I fix it?

image

Here is the code.

import java.io.File
...

post({
                request {
                    multipartBody {
                        required = true
                        description = "profile image"
                        mediaType(ContentType.MultiPart.FormData)
                        part<File>("profileImage") {
                            mediaTypes = setOf(
                                ContentType.Image.PNG,
                                ContentType.Image.JPEG,
                                ContentType.Image.GIF
                            )
                        }
                        part<Metadata>("myMetadata")
                    }
                }
            }) {
...
}

build.gradle.kts

...
dependencies {
    implementation("io.ktor:ktor-server-swagger-jvm:2.3.2")
    implementation("io.ktor:ktor-server-openapi:2.3.2")
    implementation("io.github.smiley4:ktor-swagger-ui:2.2.0")
...
}

Unable to have DEFINITIONS_FOR_ALL_OBJECTS in the open api spec

I have tried multiple config options in the schema builder, but am not able to configure "All Schema in definitions". The spec being generated has the main schema in components, but the internal models are coming inline. This is leading to very long class names, as it is concatenating the main class name with the field name and putting "inner" in the name as well.

I think this should be the correct config for what I want, but if I try this then the schema does not get generated:

install(SwaggerUI) {
   //...
    schemasInComponentSection = true
    examplesInComponentSection = true
    schemaGeneratorConfigBuilder.with(Option.DEFINITIONS_FOR_ALL_OBJECTS)
                                                          .with(Option.DEFINITION_FOR_MAIN_SCHEMA)
                                                          .without(Option.INLINE_ALL_SCHEMAS)

    //...
}

What I want is to generate the spec where for this class:

data class Y(val a: String)
data class X(val y: Y)

The generated schema should be:

"X": {
      "type": "object",
      "properties": {
        "y": {
          "$ref": "#/components/schemas/Y"
        }
      },
      "xml": {
        "name": "X"
      }
    },
    "Y": {
      "type": "object",
      "properties": {
        "a": {
          "type": "string"
        }
      }
    }

What I being generated currently:

"X": {
      "type": "object",
      "properties": {
        "y": {
          "type": "object",
          "properties": {
            "a": {
              "type": "string"
            }
          }
        }
      },
      "xml": {
        "name": "X"
      }
    }

How to document body parameters?

Thank you for providing this library! It's very clean.

How would I describe a Body parameter, and what the acceptable values are for it?

            body<ExampleRequest> {
                required = true
            }

Lets say that ExampleRequest has a parameter limit that has a max value of 100. Or if I wanted to document the acceptable formats for a Date String that was sent. Is that possible currently?

Parameter rootHostPath not pass to requests

My server hostet on some domain and some path
For example http://<some_domain>/<some_path>
I setup rootHostPath parameter as "/<some_path>"

Swager UI oppends up correctly on URL http://<some_domain>/<some_path>/swagger/index.html
But when I try to send some request URL do not contains rootHostPath in request

For example if I have routing get /health
Full correct path is http://<some_domain>/<some_path>/health

But if I "try it out" in Swager UI
full path is http://<some_domain>/health without rootHostPath parameter

`securitySchemeName` not working for applications with external authentication

It seems that the securitySchemeName on a specific route is only applied when the route is authenticated in Ktor. However, in our context the Ktor application itself is unauthenticated, but is behind a gateway which performs the authentication (this may even be route-specific, so some routes may be authenticated, others may be unauthenticated).

I see that you're also using RouteMeta.isProtected for deciding whether to add the defaultUnauthorizedResponse -- that might be a similarly problematic case.

Maybe it would be possible to give a hint, that the route is protected externally?
I'm open to implement it myself and create a PR, but I'm not sure where the preferred place would be to put that information.
The OpenApiRoute might be a good place, but so far it only contains stuff which is really OpenAPI-specific and does not have such "meta-information".

Disable logging

It would be nice to be able to disable logging for swagger ui.

Maybe it is already possible but I cannot find it in the docs.

OneOf use case for request/response body

Hey! Loving the library, but running into a a problem.

One of my backend's return types can be a list containing one of 3 different parameterized types (List<Wrap<A>>, List<Wrap<B>>, ...). From my understanding the final OpenAPI type would be something like:

"ResponseObjectName": {
  "oneOf": [
    { "type": "array", "$ref": "#/components/schemas/Wrap(A)" },
    { "type": "array", "$ref": "#/components/schemas/Wrap(B)" },
    { "type": "array", "$ref": "#/components/schemas/Wrap(C)" }
  ]
}

I'm having trouble defining that reasonably with the library.

I've tried a bunch of stuff, but right now I'm trying to define using the CustomSchemas config. I'm self-creating the list as a OpenAPI Schema object fine, and I can set the reference. But I can't figure out how to establish the definitions for Wrap<T>. That object isn't used anywhere else, so it doesn't get auto-populated by the generator. If I add the definitions to the CustomSchemas config, they're not directly referenced by a request/response so it seems like they don't get populated because it's assumed that custom schemas are self-contained.

Here's roughly what I'm doing now:

  // This tries to use the builtin SchemaBuilder to build the objects and register them as CustomSchemas.
  val oneOfSchemaTypeNames =
    listOf(
      getSchemaType<Wrap<A>>(),
      getSchemaType<Wrap<B>>(),
      getSchemaType<Wrap<C>>()
    ).map { schemaType ->
      Pair(schemaType.getSimpleTypeName(), schemaBuilder.create(schemaType))
    }.map { (schemaName, schema) ->
      val root = schema.root as Schema<Any>
      schema.definitions.map {
        openApi(it.key) { it.value as Schema<Any> }
      }
      // From debugging, this seems to register the custom type, but it never gets written because it's not used in a route def.
      openApi(schemaName) { root }
      schemaName
    }
  // Create the list of oneOf possible return types.
  // This is the part that is actually working.
  openApi("oneOfResponse") {
    Schema<Any>().apply {
      oneOfSchemaTypeNames.map { schemaName ->
        addOneOfItem(
          ArraySchema().apply {
            items(
              Schema<Any>().apply {
                `$ref`(schemaName)
              },
            )
          },
        )
      }
    }
  }

The output I get. There are no entries in #/components/schemas for any Wrap objects.

"oneOfResponse" : {
        "oneOf" : [ {
          "type" : "array",
          "items" : {
            "$ref" : "#/components/schemas/Wrap(A)"
          }
        }, {
          "type" : "array",
          "items" : {
            "$ref" : "#/components/schemas/Wrap(B)"
          }
        }, {
          "type" : "array",
          "items" : {
            "$ref" : "#/components/schemas/Wrap(C)"
          }
        } ]
      }

Am I going about this all wrong? I don't see any way to force schemas to be instantiated, and I don't really want to have to build the whole type in the CustomSchema def or create dummy endpoints to have the objects recognized. Having the refs to the smaller objects is nice.


Also, I just noticed that body types generate different component paths depending on if they are in a list:

body<List<com.foo.Outer<com.bar.Inner>() -> #/components/schemas/Outer(Inner)
body<com.foo.Outer<com.bar.Inner>() ->  #/components/schemas/com.foo.Outer<com.bar.Inner>

Maybe due to the underlying Library?

Extract openapi contract during compilation

DSL allow to expose OpenAPI contract when application is being executed following "code first" approach.

However, I would like to build pipelines based on source code where "contract first" approach quite well, but in DSL case I don't have contract available.

One of scenarios I may want to implement is to create gradle task to extract openapi.json file into local file and run pipelines against that file (for example, can trigger vaildation and publish new openapi contract as artifact if only changes in contract detected).

Is there any way to achieve it?

PS: as one of improvements in that direction it is possible to create ktor-swagger-ui-gradle-plugin to extract openapi spec from ktor project/module and place it into resources folder during compilation instead of doing it in runtime. It will allow to avoid having extra dependencies in runtime.

Example in annotation

Hi! Now there is a functional of declaring an example for a swager through the creation of an object. But it adds a lot of template code to the routes.

Can we add our own @example annotation above the DTO fields? Or support swagger @content annotation, but I'm not sure if the json-schema generator supports it. It seems to me that it looks more appropriate there and doesn't overloads routes.

data class Person(
  @Example("Jack")
  val name: String,
)

Problem with a route dsl

Hi, I would like to use this library for my backend. I have a problem because I'm using the route dsl to define the route father.

This causes the dsl doesn't have the appropriate functions or work poorly. Is there any intention to give support for this function?

route("/users") {
        /* Registration: POST /api/users */
        post() {
            either<DomainError, UserWrapper<User>> {
                val (username, email, password) = receiveCatching<UserWrapper<NewUser>>().bind().user
                val token = userService.register(RegisterUser(username, email, password)).bind().value
                UserWrapper(User(email, token, username, "", ""))
            }.respond(HttpStatusCode.Created)
        }
        post("/login") {
            either<DomainError, UserWrapper<User>> {
                val (email, password) = receiveCatching<UserWrapper<LoginUser>>().bind().user
                val (token, info) = userService.login(Login(email, password)).bind()
                UserWrapper(User(email, token.value, info.username, info.bio, info.image))
            }.respond(HttpStatusCode.OK)
        }
    }

Thanks.

Is there any way to ignore path/route?

I would like to configure my service endpoint hidden from Swagger UI.

I would prefer to have same behavior as @ApiOperation(hidden=true) swagger annotation:

route("health",
  {  hidden = true  } // <- desired property
) {
       get("ready") { call.respond(HttpStatusCode.OK) }
}

Swagger UI breaks after changing sort method

Version: 1.0.1

Source code

fun Application.configureSwagger() {
    install(SwaggerUI) {
        swagger {
            swaggerUrl = "swagger"
            sort = SwaggerUiSort.HTTP_METHOD
        }
    }
}

Actual result
Swagger returns JavaScript exception:

Uncaught ReferenceError: method is not defined
    at window.onload

image

SPA route included in OpenAPI documentation

What is wrong?
Using singlePageApplication route to serve Vue application, but looks wrong that route is present in OpenAPI documentation.

Version: 1.0.1

Source code

fun Application.configureRouting() {
    routing {
        singlePageApplication {
            vue("ktor-playground-vue/dist")
        }

        route("api") {
            articleRoutes()
        }
    }
}

Actual result

image

2023-01-15 19:01:32.921 DEBUG --- [           main] i.g.s.k.specbuilder.OApiPathsBuilder    : Configure path: GET //{...}

Temporary fix

fun Application.configureSwagger() {
    install(SwaggerUI) {
        pathFilter = { _, url -> url.firstOrNull() == "api" }
    }
}

How to add a multipart documentation?

Hi.

I'm using this library to build a template in Ktor, I'm having a problem defining a multipart body.
I can't find any information apart from the media types.

Can you help me?

Thanks.

Example of how to document Sealed Classes?

Right now sealed classes returned by the documentation are just {}. Ideally, it would clearly document sealed classes for return types (most important), and also inputs.

Allowing examples to be set

Is it possible to allow example values to be set for parameters?

I believe there is a related bug here at this line. This makes it so that an example is set to true/false, but the purpose of the parameter is not that and it is explained on this line.

KtorDsl annotation for dsl methods

Ktor framework dsl methods marked with @KtorDsl annotation. Is there any profit to add that annotation to ktor-swagger-ui dsl methods?

I don't know actual benefits of having that, but only noticed Idea highlight dsl marked methods. Asking for comments.

Custom serialization of body objects

I have an endpoint which expects this body:

{
	"name": "entity name",
	"description": "entity description"
}

In the application, this is deserialized into

@Serializable
data class UpdateOrganization(
    val name: OptionalValue<String> = OptionalValue.Absent,
    val description: OptionalValue<String?> = OptionalValue.Absent
)

By using this custom serializer for kotlinx.serialization:

class OptionalValueSerializer<T>(private val valueSerializer: KSerializer<T>) : KSerializer<OptionalValue<T>> {
    override val descriptor: SerialDescriptor = valueSerializer.descriptor

    override fun deserialize(decoder: Decoder): OptionalValue<T> {
        val value = valueSerializer.deserialize(decoder)
        return OptionalValue.Present(value)
    }

    override fun serialize(encoder: Encoder, value: OptionalValue<T>) {
        when (value) {
            is OptionalValue.Absent -> {}
            is OptionalValue.Present -> valueSerializer.serialize(encoder, value.value)
        }
    }
}

The generated spec is displayed like this in the Swagger UI:

{
  "name": {
    "value": "entity name"
  },
  "description": {
    "value": "entity description"
  }
}

Is there a way to change the serialization for this object when generating the OpenApi spec?

Cannot specify body with collection of custom schema items

Hi! I may not have found the secret sauce for this if it exists ...

I was unable to specify a custom schema item by id in the schemas section of the plugin config and then use that for a response body that was a collection of that item, i.e. the equivalent of body<List<ABC>>() or something similar.

I was able to do it by defining a second schema that wrapped the first as an array item but that ended up replicating the base schema into the components section of the api.json with a simple array specifier.

Am I missing something? Or is this a limitation of the DSL for now?

TIA.

Unable to get oauth2 authorizationCode flow to work

I'm unable to get authentication to work using the oauth2 authorizationCode flow.
In Insomnia I'm configuring the authorization with the following parameters:
image

In my application, I tried to configure the Swagger UI like this for a local KeyCloak:

install(SwaggerUI) {
    defaultSecuritySchemeName = "token"
    defaultUnauthorizedResponse {
        description = "Token is invalid."
    }
    securityScheme("token") {
        type = AuthType.OAUTH2
        flows {
            authorizationCode {
                authorizationUrl = "http://localhost:8081/realms/master/protocol/openid-connect/auth"
                tokenUrl = "http://localhost:8081/realms/master/protocol/openid-connect/token"
            }
        }
    }
}

The routing is configured like this:

routing {
    route("api/v1") {
        authenticate("token") {
            get("hello") { // From io.github.smiley4.ktorswaggerui.dsl.get
                call.respond("Hello Auth.")
            }
        }
    }
}

The SwaggerUI shows the endpoint correctly as authenticated.
However, sending the request in SwaggerUI, does not open an authentication window, and results in 401.

I tried your Authentication example from here which was working, but for my application I do require Oauth2 authentication.

Can you give me a hint what I'm doing wrong?

KTOR Rate Limit Plugin Bug

When Using the Ktor Rate Limit Plugin, the routes are documented incorrectly, and show up with a prefix: / (RateLimit <rate limit name)/<your endpoint here>.

    install(RateLimit) {
        register(apiTokenRateLimit) {
            rateLimiter(limit = 100, refillPeriod = 60.seconds)
            requestKey { call ->
                // We've already checked and confirmed that the API Token exists.
                call.request.headers[ApiTokenValidator.API_TOKEN_HEADER]!!.trim()
            }
        }
    }

    routing {
        rateLimit(apiTokenRateLimit) {
            myRoutes()
        }
    }
image

Support for Rate Limiter

Here is the rate limiter: https://ktor.io/docs/rate-limit.html

I tried it below
routing { rateLimit { get("/something", { summary = "something Endpoint." response { ....

Result
image

URL paths are affected by the rateLimit function.

Are there any plans to support the rate limiter?

Use generics for documentation instead of class parameters

Hey,

what about the following:

            request {
                body(GetItemParams::class)
            }
            response {
                HttpStatusCode.OK to {
                    body(GetItemResponse::class)
                }
            }

replaced by this:

            request {
                body<GetItemParams>()
            }
            response {
                HttpStatusCode.OK to {
                    body<GetItemResponse>()
                }
            }

It is less to write and you can use generics:

            request {
                body<GetItemParams>()
            }
            response {
                HttpStatusCode.OK to {
                    body<GetItemResponse<FirstItem>>()
                }
            }

Using generics add whole canonical name in components

At the moment i am working on a small REST project.

When I try to prepare some routes to retrieve list and single items from a database table
GET /item
GET /item/XYZ

I want the first one to return a List of "Item", while the second one to return just "Item"

When I am using body<List<Item>> it automatically creates a component with full canonical name: Result in api.json

"responses" : {
  "200" : {
    "description" : "successful operation",
    "headers" : { },
    "content" : {
      "application/json" : {
        "schema" : {
          "type" : "array",
          "xml" : { },
          "items" : {
            "$ref" : "#/components/schemas/com.example.ktor.Item"
          }
        }
      }
    }
  }
}

When I try to create the body manually providing a custom schema for my Item:

body {
  mediaType(ContentType.Application.Json)
    ArraySchema().apply {
      items = ObjectSchema().apply {
      `$ref` = "Item"
    }
  }
}

The created api.json response is just empty

"responses" : {
  "200" : {
    "description" : "successful operation",
    "headers" : { },
    "content" : {
      "application/json" : { }
    }
  }
}

Do you have any idea how to get it working?

Can I hide a route?

I have some routes that aren't API endpoints; some are pages that generate HTML etc; I don't want them to be a part of the swagger docs. Is there a way to mark a particular route as hidden so it doesn't show up in the UI?

I could also see this as something that would be useful for endpoints that aren't yet public.

Map is not generating correctly

When we have a data class eg:

data class MyClass(val x: Map<String, String>)

This gets generated as:

"x": {
"type": "object"
},

Additional properties should be added. Otherwise the client generated by this open api json treats the field as String and not a map.

Something like this:

"x": {
"type": "object",
"additionalProperties": { "type": "string" }
},

index.html Not found

when trying to go to the swagger documentation the index.html is not found in the webjar.
Used version of the liberary: 1.1.0

2023-01-31 09:22:20.132 [main] INFO  Application - Responding at http://127.0.0.1:8080
2023-01-31 10:03:35.677 [eventLoopGroupProxy-4-2] TRACE io.ktor.server.sessions.Sessions - Sessions found for /swagger-ui/index.html: Session
2023-01-31 10:03:35.686 [eventLoopGroupProxy-4-2] TRACE io.ktor.routing.Routing - Trace for [swagger-ui, index.html]
/, segment:0 -> SUCCESS @ /
  /swagger-ui, segment:1 -> SUCCESS @ /swagger-ui
    /swagger-ui/(method:GET), segment:1 -> FAILURE "Not all segments matched" @ /swagger-ui/(method:GET)
    /swagger-ui/api.json, segment:1 -> FAILURE "Selector didn't match" @ /swagger-ui/api.json
    /swagger-ui/{filename}, segment:2 -> SUCCESS; Parameters [filename=[index.html]] @ /swagger-ui/{filename}
      /swagger-ui/{filename}/(method:GET), segment:2 -> SUCCESS @ /swagger-ui/{filename}/(method:GET)
  /api, segment:0 -> FAILURE "Selector didn't match" @ /api
  /{...}, segment:0 -> FAILURE "Better match was already found" @ /{...}
Matched routes:
  "" -> "swagger-ui" -> "{filename}" -> "(method:GET)"
Route resolve result:
  SUCCESS; Parameters [filename=[index.html]] @ /swagger-ui/{filename}/(method:GET)
2023-01-31 10:03:35.690 [eventLoopGroupProxy-4-2] TRACE io.ktor.server.sessions.Sessions - Sending session data for /swagger-ui/index.html: Session
2023-01-31 10:03:35.691 [eventLoopGroupProxy-4-2] TRACE i.k.s.p.c.ContentNegotiation - Skipping because the type is ignored.
2023-01-31 10:03:35.697 [eventLoopGroupProxy-4-2] TRACE i.k.s.p.compression.Compression - Skip compression because no suitable encoder found.
2023-01-31 10:03:35.698 [eventLoopGroupProxy-4-2] TRACE i.k.s.p.statuspages.StatusPages - No handler found for status code 404 Not Found for call: /swagger-ui/index.html
2023-01-31 10:03:35.832 [eventLoopGroupProxy-4-2] TRACE Application - 404 Not Found: GET - /swagger-ui/index.html

My configuration:

install(SwaggerUI){
        pathFilter = { _, url -> url.firstOrNull() == "api" }
        swagger {
            forwardRoot = false
            swaggerUrl = "swagger-ui"
            onlineSpecValidator()
            displayOperationId = true
            showTagFilterInput = true
            syntaxHighlight = SwaggerUiSyntaxHighlight.MONOKAI
        }

        info {
            title = "Ktor swagger"
            version = "latest"
            description = "Ktor swagger api documentation"
            contact {
                name = "Mike Dirven"
                url = "http://www.icsvertex.nl"
                email = "[email protected]"
            }
        }
    }

Is it possible to use SerialName in data class fields?

Is there any way to use a kotlinx.serialization or gson annotation on the fields of a data class in the version 1.6.1?

For example, I'm using the code below, but the generated example response is picking the data class field name and ignoring the annotation:

import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable

@Serializable
data class Pet(
   @SerialName("first_name") 
   val firstName: String
)

get("pet", {
    response {
        HttpStatusCode.Ok to {
            body<Pet>() {
               mediaType(ContentType.Application.Json)
               example(
                   name = "get pet name",
                   value = Pet("Max")
              )
            }
        }
    }
}) {
    // handle request...
}

But the generated example give me:

{
    "firstName": "Max"
}

instead

{
    "first_name": "Max"
}

I saw that in the 2.0.0 version will be possible to set a custom example encoding

Version 2.2.1 not published to maven

Hi, I don't think the latest version has been published to maven central. The previous one, 2.2.0, seems to be the latest available.

Nonetheless, great work, thank you for the library. It feels much cleaner compared to other approaches.

The use is complex and not intuitive enough,Suggestions

Can annotations be used to express interfaces and interface parameters? The current form feels too intrusive, and it is highly complex to use, and the second phase looks unclear. It is suggested to refer to the form of Java,js,python, and these swagger are written in the form of similar annotations.

Expose functionality for disabling Swagger validation

It would be nice to have functionality for disabling the default swagger validation that's visible on the landing page. Since in our case we are running all services in a Kubernetes cluster behind a VPN the callback validation always fails and give us an orange box in the right corner that says: INVALID.

Referenced schema dropped from output

Hello,
I'm facing the problem, that my referenced Schema is dropped from the generated swagger-ui components (missing in api.json file as well).

After providing some openapi schemas, they are only added to the final swagger components when they referenced a request or response as a body.

  • define openapi Schema.A and Schema.B
  • Schema.A has a property referencing Schema.B
  • Having a ktor route with Schema.A as response body only.
  • install SwaggerUI feature with schemasInComponentSection = true

In the resulting Swagger-UI Schema.B is missing as a component and in the response body description of previously defined route.

Is that an issue, or what can I do?

support webSocket route

Good day! Tell me if there is an opportunity to add websocket support?
And how can I turn off generation for static, file, resources

Thank you!

Add support for custom RouteSelector

Need for implement authorization and etc.

Suggestion:

// add abstract RouteSelector
abstract class TransparentRouteSelector : RouteSelector()

private fun getPath(route: Route): String {
        return when (route.selector) {
            is TrailingSlashRouteSelector -> "/"
            is RootRouteSelector -> ""
            is DocumentedRouteSelector -> route.parent?.let { getPath(it) } ?: ""
            is HttpMethodRouteSelector -> route.parent?.let { getPath(it) } ?: ""
            is AuthenticationRouteSelector -> route.parent?.let { getPath(it) } ?: ""
            is TransparentRouteSelector -> route.parent?.let { getPath(it) } ?: "" // this is new abstract class
            else -> (route.parent?.let { getPath(it) } ?: "") + "/" + route.selector.toString()
        }
    }

Incorrect Endpoint name provided to openTelemetry

Hi @SMILEY4 , thanks for that great extension.

Have next issue with exporting tracing data to Jaeger and see next endpoint there:

demo-project: /io.github.smiley4.ktorswaggerui.dsl.DocumentedRouteSelector@454d7e70/hello

While expect to see

demo-project: /hello

I use minimal demo configuration with OpenTelemetry and instrument with https://github.com/open-telemetry/opentelemetry-java-instrumentation/tree/main/instrumentation/ktor/ktor-2.0/library

Issue affect all endpoints defined with io.github.smiley4.ktorswaggerui.dsl.*

Problems to generate docs, schema o what else

Hi
I have the following problem when I call to a methods using Swagger UI

Curl

curl -X 'GET'
'http://localhost:6969/*'
-H 'accept: /'

Request URL
http://localhost:6969/*

Undocumented | Failed to fetch.Possible Reasons:
CORS
Network FailureURL scheme must be "http" or "https" for CORS request.

I don't have CORS configuration

I have the same problem with all endpoints an routes, this example is with a String

Here it is my conf

install(SwaggerUI) {
        swagger {
            swaggerUrl = "swagger-ui"
            forwardRoot = true
        }
        info {
            title = "Ktor Tenistas API REST"
            version = "latest"
            description = "Ejemplo de una API Rest usando Ktor y tecnologías Kotlin."
            contact {
                name = "Jose Luis González Sánchez"
                url = "https://github.com/joseluisgs"
            }
            license {
                name = "Creative Commons Attribution-ShareAlike 4.0 International License"
                url = "https://joseluisgs.dev/docs/license/"
            }
        }
        server {
            url = environment.config.property("server.baseUrl").getString()
            description = "Servidor de la API Rest usando Ktor y tecnologías Kotlin."
        }

        schemasInComponentSection = true
        examplesInComponentSection = true
        automaticTagGenerator = { url -> url.firstOrNull() }

    }

Could you help me?

Allow multiple security schemes for a route

OAS3 allows combining security requirements with logical operators (OR and AND). More details can be found in the documentation under Using Multiple Authentication Types, but the basic logic for documenting security of a route is as follow:

security:    # A OR B
  - A
  - B
security:    # A AND B
  - A
    B
security:    # (A AND B) OR (C AND D)
  - A
    B
  - C
    D

From my observation of this library, this should be doable by changing the OpenApiRoute.securitySchemeName (link) from a String? to something like a Collection<Collection<String>> (or just Collection<String> for start, to support the OR logical operator) and supporting the following change here.

Maven Central Publishing

Thanks a lot for providing this library! We love it!

Are there any plans to publish this library also to Maven Central? We would like to use it in some projects where we're (unfortunately) restricted to Maven Central.

header name value support

First of all, it is a great library thanks for your effort. But when I check the READ.me I didn't find any documentation for header parameter. There is a headerParameter in request block but I can not add any sample value to it. Can you also add sample to READ.me for headerParameter usage?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.