🔥

Ktor Server で openapi.json を生成する

2023/12/04に公開

この記事は mob Advent Calendar 4日目の記事になります。

JVM系のバックエンドのフレームワークでは アノテーション などで API の仕様を書いて、 Gradle Task などで生成する方法が何かしらあることが多いです。

Ktor も同様なのかと思って開発を進めており、いざ openapi.yaml もしくは openapi.json を生成する方法を調べたのですが、自分が調べる限りはそのように Gradle Task で生成する方法を見つけることができませんでした。

openapi.yaml から ktor のプロジェクトを生成する方法 や ktor で openapi.yaml から Swagger-UI を表示する方法などは簡単に見つかりますが、肝心の openapi.yaml ないし openapi.json を生成する術が限られているようです。

この記事では、現状どうやって生成できるのかを紹介します。

https://ktor.io/docs/openapi.html

Intellij Idea の Ktor Plugin を使用する

まずは簡単な方法。

embeddedServer のところで、 option + enter を押すと、 Generate OpenAPI documentation for current module が表示されるので、それを実行すれば生成されます

https://www.jetbrains.com/help/idea/ktor.html#openapi

こんな感じのコードがあると、 Header に X-APIKEY があること、 クエリパラメータに page, limit, userId があることを理解してくれ、生成してくれます。頭が良い。

get("/items") {
  runCatching {
    if (!verify(call.request.headers["X-APIKEY"])) {
      call.respond(HttpStatusCode.Unauthorized, "unauthorized")
      return@get
    }
    val page = call.parameters["page"]!!.toInt()
    val limit = call.parameters["limit"]!!.toInt()
    val userId = call.parameters["userId"]!!
    val list = ...
    call.respond(HttpStatusCode.OK, list)
  }.onFailure {
    call.respond(HttpStatusCode.InternalServerError, it.message ?: "")
  }
}

と、このように簡単に生成できるのですがいくつか気をつけなければならない点があります。

  1. IntelliJ IDEA Ultimate でなければならない ( Community 版では使えない)
  2. description が空になったり content type が "/" になったりする
  3. Multipart 対応してない(?)

もしかしたら (2) と (3) は解決できるのかもしれませんが、 Ktor Plugin のこの機能に関する詳細なドキュメントがなく、また ソースコードも公開されていないので不明です。

なので、現状はシュッとたたきの openapi.yaml を生成して、手を入れて完成させるものなのかなと理解しています。

ktor-swagger-ui を使用する

API 仕様をコード内に記述して、 Swagger-UI を表示する機能を追加するライブラリです。

https://github.com/SMILEY4/ktor-swagger-ui

コードでこのように書いて、ローカルホストを立ち上げると localhost:8080/swagger-ui にアクセスすることで Swagger-UI にアクセスすることができます。

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"
    }
}
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!")
}

サーバーを立ち上げたタイミングで openapi.json を生成して、それを表示しているようです。

Swagger-UI のリンクからもいけるが http://localhost:8080/swagger-ui/api.json が openapi.json になるのでこれをダウンロードすればOK。

結論

ランタイムで生成されるのが面倒なので、Gralde Task で生成できるようになってほしいな。

Discussion