Git Product home page Git Product logo

ktor-docs-plugin's Introduction

Open API (Swagger) Plugin for Ktor

This plugin implements a plug and play solution for generating OpenAPI (Swagger) specification for your Ktor server with minimal effort - no need to modify your existing code, no special DSL wrappers etc. Just annotate your route(s) definitions with @GenerateOpenApi and openapi.yaml will be generated at build time.

How to apply the plugin

plugins {
    id("io.github.tabilzad.ktor-docs-plugin-gradle") version "0.6.0-alpha"
}

swagger {

    documentation {
        docsTitle = "Ktor Server Title"
        docsDescription = "Ktor Server Description"
        docsVersion = "1.0"
        generateRequestSchemas = true
        hideTransientFields = true
        hidePrivateAndInternalFields = true
        deriveFieldRequirementFromTypeNullability = true
    }

    pluginOptions {
        enabled = true // true by default
        saveInBuild = true// false by default
        format = "yaml" // or json
    }
}

Supported Features

Feature isSupported type
Path/Endpoint definitions Automatic
Request Schemas Automatic
Response Schemas Explicit
Endpoint/Scheme Descriptions Explicit
Endpoint Tagging Explicit

Plugin Configuration

Documentation options

Option Default Value Explanation
docsTitle "Open API Specification" Title for the API specification that is generated
docsDescription "Generated using Ktor Docs Plugin" A brief description for the generated API specification
docsVersion "1.0.0" Specifies the version for the generated API specification
generateRequestSchemas true Determines if request body schemas should
be automatically resolved and included
hideTransientFields true Controls whether fields marked with @Transient
are omitted in schema outputs
hidePrivateAndInternalFields true Opts to exclude fields with private or internal modifiers from schema outputs
deriveFieldRequirementFromTypeNullability true Automatically derive object fields' requirement from its type nullability

Plugin options

Option Default Value Explanation
enabled true Enable/Disables the plugin
saveInBuild false Decides if the generated specification file should
be saved in the build/ directory
format yaml The chosen format for the OpenAPI specification
(options: json/yaml)
filePath $modulePath/src/main/resources/openapi/ The designated absolute path for saving
the generated specification file

How to use the plugin

Generating endpoint specifications

Annotate the specific route definitions you want the OpenAPI specification to be generated for.

@GenerateOpenApi
fun Route.ordersRouting() {
    route("/v1") {
        post("/order1") {
            /*...*/
        }
    }
}

You could also annotate the entire Application module with multiple/nested route definitions. The plugin will recursively visit each Route. extension and generate its documentation.

@GenerateOpenApi
fun Application.ordersModule() {
    routing {
        routeOne()
        routeTwo()
    }
}

fun Route.routeOne() {
    route("/v1") { /*...*/ }
}

fun Route.routeTwo() {
    route("/v2") { /*...*/ }
    routeThree()
}

Endpoint and field descriptions

Describe endpoints or schema fields.

data class RequestSample(
    @KtorFieldDescription("this is a string")
    val string: String,
    val int: Int,
    val double: Double
)

@GenerateOpenApi
fun Route.ordersRouting() {
    route("/v1") {
        @KtorDescription(
            summary = "Create Order",
            description = "This endpoint will create an order",
        )
        post("/create") {
            call.receive<RequestSample>()
        }

        route("/orders") {
            @KtorDescription(
                summary = "All Orders",
                description = "This endpoint will return a list of all orders"
            )
            get { /*...*/ }
        }
    }
}

Responses

Defining response schemas and their corresponding HTTP status codes are done via @KtorResponds annotation on an endpoint.

@GenerateOpenApi
fun Route.ordersRouting() {
    route("/v1") {
        @KtorResponds(
               [
                   ResponseEntry("200", Order::class, description = "Created order"),
                   ResponseEntry("400", ErrorResponseSample::class, description = "Invalid order payload")
               ]
        )
        post("/create") { /*...*/ }
        @KtorResponds([ResponseEntry("200", Order::class, isCollection=true, description = "All orders")])
        get("/orders") { /*...*/ }
    }
}

Tagging

Using tags enables the categorization of individual endpoints into designated groups. Tags specified at the parent route will propogate down to all endpoints contained within it.

@Tag(["Orders"])
fun Route.ordersRouting() {
    route("/v1") {
        post("/create") { /*...*/ }
        get("/orders") { /*...*/ }
    }
    route("/v2") {
        post("/create") { /*...*/ }
        get("/orders") { /*...*/ }
    }
}

On the other hand, if the tags are specified with @KtorDescription or @Tag annotation on an endpoint, they are associated exclusively with that particular endpoint.

@GenerateOpenApi
fun Route.ordersRouting() {
    route("/v1") {
        @KtorDescription(tags = ["Order Operations"])
        post("/order") { /*...*/ }
        @Tag(["Cart Operations"])
        get("/cart") { /*...*/ }
    }
}

Planned Features

  • Automatic Response resolution
  • Support for polymorphic types
  • Support ktor resources
  • Option for an automatic tag resolution from module/route function declaration
  • Tag descriptions

Sample Specification

sample

ktor-docs-plugin's People

Contributors

tabilzad 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

Watchers

 avatar  avatar

ktor-docs-plugin's Issues

Doesn't seem to detect resource routes

If you download the ktor starter with the resources plugin and modify it so that it looks like this

fun Application.configureRouting() {
    install(Resources)
    routing {
        misc()
        articles()
    }
}

@Serializable
@Resource("/articles")
class Articles(val sort: String? = "new")

fun Route.misc() {
    get("/") {
        call.respondText("Hello World!")
    }
}

fun Route.articles() {
    get<Articles> { article ->
        // Get all articles ...
        call.respond("List of articles sorted starting from ${article.sort}")
    }
}

annotating the module() function like this

@GenerateOpenApi
fun Application.module() {
    configureHTTP()
    configureRouting()
}

does not produce yaml for Route.articles()

---
openapi: "3.1.0"
info:
  title: "Example"
  description: "Some description here!"
  version: "0.0.1"
paths:
  /:
    get: {}
components:
  schemas: {}

config looks like this

swagger {
    documentation {
        docsTitle = "Example"
        docsDescription = "Some description here!"
        docsVersion = version.toString()
        generateRequestSchemas = true
        hideTransientFields = true
        hidePrivateAndInternalFields = true
        deriveFieldRequirementFromTypeNullability = true
    }

    pluginOptions {
        format = "yaml"
        saveInBuild = true
    }
}

Issues deploying to app engine

Locally i can run the client and everything works perfectly.
When deploying to google app engine, i'm getting the following error message and hoping you could help.

./gradlew appengineDeploy
Starting a Gradle Daemon, 1 incompatible Daemon could not be reused, use --status for details

FAILURE: Build failed with an exception.

* What went wrong:
A problem occurred configuring root project 'wampex'.
> Could not resolve all files for configuration ':classpath'.
   > Could not resolve io.github.tabilzad:ktor-docs-plugin-gradle:0.6.0-alpha.
     Required by:
         project : > io.github.tabilzad.ktor-docs-plugin-gradle:io.github.tabilzad.ktor-docs-plugin-gradle.gradle.plugin:0.6.0-alpha
      > No matching variant of io.github.tabilzad:ktor-docs-plugin-gradle:0.6.0-alpha was found. The consumer was configured to find a library for use during runtime, compatible with Java 8, packaged as a jar, and its dependencies declared externally, as well as attribute 'org.gradle.plugin.api-version' with value '8.4' but:
          - Variant 'apiElements' capability io.github.tabilzad:ktor-docs-plugin-gradle:0.6.0-alpha declares a library, packaged as a jar, and its dependencies declared externally:
              - Incompatible because this component declares a component for use during compile-time, compatible with Java 11 and the consumer needed a component for use during runtime, compatible with Java 8
              - Other compatible attribute:
                  - Doesn't say anything about org.gradle.plugin.api-version (required '8.4')
          - Variant 'runtimeElements' capability io.github.tabilzad:ktor-docs-plugin-gradle:0.6.0-alpha declares a library for use during runtime, packaged as a jar, and its dependencies declared externally:
              - Incompatible because this component declares a component, compatible with Java 11 and the consumer needed a component, compatible with Java 8
              - Other compatible attribute:
                  - Doesn't say anything about org.gradle.plugin.api-version (required '8.4')
          - Variant 'sourcesElements' capability io.github.tabilzad:ktor-docs-plugin-gradle:0.6.0-alpha declares a component for use during runtime, and its dependencies declared externally:
              - Incompatible because this component declares documentation and the consumer needed a library
              - Other compatible attributes:
                  - Doesn't say anything about its target Java version (required compatibility with Java 8)
                  - Doesn't say anything about its elements (required them packaged as a jar)
                  - Doesn't say anything about org.gradle.plugin.api-version (required '8.4')

plugin not compatible with kotlin 2

if you use it with lang v 2.0.0 on you get this message

There are some plugins incompatible with language version 2.0:
  io.github.tabilzad.ktor.KtorMetaPluginRegistrar
Please use language version 1.9 or below

Showing error in build.gradle.kts

Where will I add given code in build.gradle.kts? it shows an error. Please add documentation for build.gradle.kts

swagger {
title = "Ktor Server"
description = "Ktor Server Description"
version = "1.0"
requestFeature = true
}

Route path extraction

Route definitions could be extracted at runtime with the native api

fun Application.getAllRoutes(): List<Route> {
    val root = plugin(Routing)
    val allRoutes = allRoutes(root)
    return allRoutes.filter { it.selector is HttpMethodRouteSelector }
}

fun allRoutes(root: Route): List<Route> {
    return listOf(root) + root.children.flatMap { allRoutes(it) }
}

Reference: https://youtrack.jetbrains.com/issue/KTOR-581

Plugin [id: 'io.github.tabilzad.ktor-docs-plugin-gradle'] was not found in any of the following sources:

Just cloned the repo to try out the use-plugin example, but without changing anything, the build.gradle gives me this error:

FAILURE: Build failed with an exception.

* Where:
Build file '/home/tobias/Downloads/ktor-docs-plugin-master/use-plugin/build.gradle' line: 3

* What went wrong:
Plugin [id: 'io.github.tabilzad.ktor-docs-plugin-gradle'] was not found in any of the following sources:

- Gradle Core Plugins (plugin is not in 'org.gradle' namespace)
- Plugin Repositories (plugin dependency must include a version number for this source)

* Try:
> Run with --stacktrace option to get the stack trace.
> Run with --info or --debug option to get more log output.
> Run with --scan to get full insights.

* Get more help at https://help.gradle.org

CONFIGURE FAILED in 482ms

As already said, this is the cloned repo and it gave me this error while intellij was busy loading the gradle script.

Gradle Task to generate openapi.yml

Hi, first of all: Thank you for this amazing generator. It works perfectly for me. I was wondering if there's a specific gradle task that's only generating the docs. I need it in my automated pipeline, where I first want to generate the newest openapi.yml file and then generate code from it for my frontend.

gradle task order compatibility issue

I have a single @KtorDocs annotation on my app like this

@KtorDocs
fun Application.topLevelRoutes() {
    routing {
        base()
        articles()
    }
}

i serve the swagger UI as described in the ktor docs like this

        swaggerUI(path = "openapi", swaggerFile = "openapi.yaml") {
            version = "5.17.2"
        }

the first time i use run or runshadow the server fails to launch because the openapi file has yet to be generated

Exception in thread "main" java.io.FileNotFoundException: Swagger file not found: /home/ixtli/Public/project/kt/stavvy-sample-webserver/openapi.yaml
	at io.ktor.server.plugins.swagger.SwaggerKt.swaggerUI(Swagger.kt:44)
	at io.ktor.server.plugins.swagger.SwaggerKt.swaggerUI(Swagger.kt:36)
...

subsequent runs work fine, once the openapi yaml is present in the build dir

my gradle configuration relevant to this issue is

swagger {
    documentation {
        docsTitle = "Stavvy Example Ktor Server"
        docsDescription = "Server Description Here!"
        docsVersion = "1.0"
        generateRequestSchemas = true
        hideTransientFields = true
        hidePrivateAndInternalFields = true
    }

    pluginOptions {
        enabled = true
        saveInBuild = true
        format = "yaml"
    }
}

sourceSets {
    kotlin {
        main {
            resources {
                srcDir(layout.buildDirectory.dir("openapi"))
            }
        }
    }
}

it seems obvious to me that the task graph is wrong. perhaps the generation is a dependency of kotlin compilation where instead the AP should be run as an assembly dependency?

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.