Kotlin(Spring Boot)の API を OpenAPI Generator で自動生成
概要
本記事では OpenAPI Generator を用いて openapi.yaml から Kotlin(Spring Boot)のソースコードを自動生成する方法を紹介します。
以下の構成にしたがって進めていきます。
- 「OpenAPI Generator について」
- 「Kotlin(Spring Boot)に導入」
- 「ソースコードの自動生成」
- 「REST API の作成」
- 「まとめ」
本記事で作成したサンプルコードは以下に載せています。
OpenAPI Generator について
OpenAPI Generator とは、OpenAPI Specification(以下、OpenAPI)をもとに、ソースコードを自動生成するツールです。
OpenAPI Generator を利用することで、スキーマ駆動開発を実現しやすくなります。
OpenAPI ベースでソースコードを生成できるため、以下のメリットがあります。
- フロントエンドとバックエンド間でAPI スキーマの認識を一致させながら並行して開発可能
- API の設計書とソースーコードが乖離しない
- API のコントローラ部分が自動生成されるので、開発者はドメインロジックに注力可能
OpenAPI と OpenAPI Generator についてほかにも特徴がありますが、以下の記事を参考にしたので、詳細なことは以下を参考にしてください。
また、記事に引用されていた以下の資料は、OpenAPI Generator の Contributer の方が作成されたものです。
OpenAPI の歴史と OpenAPI Generator が制作された経緯を紹介しており、非常に興味深かったのでぜひ一読してください。
Kotlin(Spring Boot)に導入
Kotlin に導入する際には、build.gradle.kts 記述が必要なため本項目で解説します。
Kotlin で導入すると、Controller に使用する interface と data class が生成されます。interface はエンドポイントのルーティング、メソッド、ステータスコードなどが定義されます。同様に、data class はリクエストとレスポンスの型が定義されています。
openapi.generator プラグインを導入するほかに、前提として以下のように設定します。
概要 | 内容 |
---|---|
生成される interface のエンドポイントのまとめ方は、OpenAPI の tags 準拠 | デフォルトだと API のパスをパースするため |
生成されたソースコードは、Git で管理しない | build/ 配下に生成して、builld.gradle.kts の設定で import できるようにする |
compile するたびにソースコードを自動生成する | 意図しない変更があったときに、ビルドを停止するため |
build.gradle.kts
具体的に build.gradle.kts に何を記述するのか解説します。
長くなったので、項目(plugins、dependencies、task、そのた)ごとに分割しました。
plugins
まず、OpenAPI Generator が提供している、openapi.generator
を記述します。
// 略
plugins {
// 中略
/**
* openapi.generator
*/
id("org.openapi.generator") version "6.2.0"
}
dependencies
生成したソースコード内で利用されているライブラリを記述します。
src/から参照したり、ビルド時にも参照するため、記述しないとビルドが落ちます。
dependencies {
// 中略
/**
* Swagger Annotations
* Swagger Models
* Jakarta Annotations API
*/
compileOnly("io.swagger.core.v3:swagger-annotations:2.2.4")
compileOnly("io.swagger.core.v3:swagger-models:2.2.4")
compileOnly("jakarta.annotation:jakarta.annotation-api:2.1.1")
/**
* Spring Boot Starter Validation
*/
implementation("org.springframework.boot:spring-boot-starter-validation")
}
task
./gradlew に task を追加します。
追加するタスクは以下の表の通りです。
タスク | 内容 |
---|---|
generateApiDoc | openapi.yaml から API スキーマのドキュメントを生成する |
generateApiServer | openapi.yaml からソースコードを生成する(tags 準拠で生成できるようにする) |
また、task の追加設定で、コンパイル時にgenerateApiServer
の実行するように設定します。
task<GenerateTask>("generateApiServer")
に記述してある、apiPackage.set
とmodlePackage.set
のパスは各自のパスを指定してください。main/kotlin
からパスを指定します。
import org.openapitools.generator.gradle.plugin.tasks.GenerateTask // GenerateTask のオプションのために、import が必要。あらかじめ、build して依存ファイルがないと import できない
// 略
/**
* OpenAPI Generator を使って API ドキュメント生成
*/
task<GenerateTask>("generateApiDoc") {
generatorName.set("html2")
inputSpec.set("$projectDir/openapi.yaml")
outputDir.set("$buildDir/openapi/doc/")
}
/**
* OpenAPI Generator を使ってコード生成
*/
task<GenerateTask>("generateApiServer") {
generatorName.set("kotlin-spring")
inputSpec.set("$projectDir/openapi.yaml")
outputDir.set("$buildDir/openapi/server-code/") // .gitignoreされているので注意(わざとここにあります)
apiPackage.set("com.example.yourapp.openapi.generated.controller") // 各自のアプリケーションに合わせてパス名を変更する
modelPackage.set("com.example.yourapp.openapi.generated.model") // 各自のアプリケーションに合わせてパス名を変更する
configOptions.set(
mapOf(
"interfaceOnly" to "true",
)
)
/**
* true にすると tags 準拠で、API の interface を生成する
*/
additionalProperties.set(
mapOf(
"useTags" to "true"
)
)
}
/**
* Kotlinをコンパイルする前に、generateApiServerタスクを実行
* 必ずスキーマファイルから最新のコードが生成され、もし変更があったらコンパイル時に失敗して気付けるため
*/
tasks.compileKotlin {
dependsOn("generateApiServer")
}
その他
build されたソースコードを import できるようにする設定も、build.gradle.kts に記述します。
/**
* OpenAPI Generator によって生成されたコードを import できるようにする
*/
kotlin.sourceSets.main {
kotlin.srcDir("$buildDir/openapi/server-code/src/main")
}
以上で導入完了です。
ソースコードの自動生成
導入したので、どのようにして自動生成するのか確認します。
OpenAPI の作成
ソースコードの生成もとになる、OpenAPI を作成します。本記事では v3.0.2 で作成しました。
メタ情報(openapi、info、servers)、エンドポイント(paths)、コンポーネント(components)から構成されます。
具体的な記述方法について触れませんので、公式ドキュメントを参照してください。
本記事で作成した OpenAPI。
# OpenAPI Object: openapi
#
# type
# - string
# Required
# - true
#
openapi: "3.0.2"
#
# OpenAPI Object: Info
#
# type
# - InfoObject
# Required
# - true
#
info:
title: OpenAPI Generator Kotlin Sample
description: OpenAPI Generator を用いた自動生成のサンプルコードです
license:
name: MIT License
url: https://opensource.org/licenses/MIT
version: "1.0"
#
# OpenAPI Object: servers
#
# type
# - [Server Object]
# Required
# - false
#
servers:
- url: /api
#
# OpenAPI Object: paths
#
# type
# - Paths Object
# Required
# - true
#
paths:
#
# Paths Object
#
# 概要
# - エンドポイントへの相対パスを記述する
# - フィールド名はスラッシュから始まる
#
/customers:
#
# Method: get/put/post/delete/options/head/patch/trace
#
get:
#
# Paths Object: tags
#
# type
# - [string]
# Required
# - false
#
tags:
- Customer
#
# Paths Object: Summary
#
# type
# - string
# Required
# - false
#
summary: カスタマーの一覧取得
#
# Paths Object: description
#
# type
# - string
# Required
# - false
#
description: DB に登録されているカスタマーを全て取得する
#
# Paths Object: operationId
#
# type
# - string
# Required
# - false
#
operationId: List
#
# Paths Object: responses
#
# type
# - Responses Object
# Required
# - true
#
responses:
'200':
description: OK
content:
application/json:
schema:
$ref: '#/components/schemas/MultipleCustomersResponse'
#
# OpenAPI Object: components
#
# type
# - Component Object
# Required
# - No
#
components:
#
# Components Object: schemas
#
# type
# - Map[string, Schema Object | Reference Object]
# - Key
# - String
# - Value
# - Schema Object | Reference Object
# Required
# - false
#
schemas:
#
# Schema Object
#
# 入力データ型の定義で利用
# JSON Schema の拡張サブセット
# 基本は JSON Schema に準拠
#
Customer:
#
# Schema Object: required
#
# type
# - [string]
# Required
# - false
#
required:
- first_name
- last_name
#
# Schema Object: type
#
# type
# - string
# - | null
# - | boolean
# - | object
# - | array
# - | number
# - | string
#
# Required
# - true
#
type: object
properties:
first_name:
type: string
last_name:
type: string
MultipleCustomersResponse:
required:
- customers
type: object
properties:
customers:
type: array
items:
$ref: '#/components/schemas/Customer'
コマンドの実行
以下のコマンド(または、intellij の gradle タブ->other->generateApiServer)でソースコードを自動生成できます。
生成されたソースコードは、build/openapi/server-code/src
配下に存在します。
./gradlew generateApiServer
生成されたソースコード
中身を確認すると、以下になっています。
OpenAPI がソースコードに反映されたことがわかりました。
/**
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech) (6.2.0).
* https://openapi-generator.tech
* Do not edit the class manually.
*/
// 中略
@Validated
@RequestMapping("\${api.base-path:/api}")
interface CustomerApi {
@Operation(
summary = "カスタマーの一覧取得",
operationId = "list",
description = "DB に登録されているカスタマーを全て取得する",
responses = [
ApiResponse(responseCode = "200", description = "OK", content = [Content(schema = Schema(implementation = MultipleCustomersResponse::class))])
]
)
@RequestMapping(
method = [RequestMethod.GET],
value = ["/customers"],
produces = ["application/json"]
)
fun list(): ResponseEntity<MultipleCustomersResponse> {
return ResponseEntity(HttpStatus.NOT_IMPLEMENTED)
}
}
また、以下のコマンドによって、API ドキュメントの生成も可能です。
./gradlew generateApiDoc
生成された API ドキュメント ./build/openapi/doc/index.html 。
生成された API ドキュメント
REST API の作成
生成した interface を実装することで、REST API を作成します。
interface の実装
生成した interface の実装方法は以下になります。
build.gradle.kts の設定によりbuild/
配下のファイルを import 可能なことがわかります。
非常に簡潔な実装になり、開発者が実装する部分はほとんどないことがわかります。
package com.example.openapigeneratorsample.controller
import com.example.realworldkotlinspringbootjdbc.openapi.generated.controller.CustomerApi // 自動生成されたソースコード
import com.example.realworldkotlinspringbootjdbc.openapi.generated.model.Customer // 自動生成されたソースコード
import com.example.realworldkotlinspringbootjdbc.openapi.generated.model.MultipleCustomersResponse // 自動生成されたソースコード
import org.springframework.http.HttpStatus
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.RestController
@RestController
class CustomerController : CustomerApi {
override fun list(): ResponseEntity<MultipleCustomersResponse> {
// 本来なら DB から値を取得する処理がある
// 今回は簡略
return ResponseEntity(
MultipleCustomersResponse(
customers = listOf(Customer("Alice", "example01"), Customer("Bob", "example02")),
),
HttpStatus.OK
)
}
}
動作確認
一応動作確認します。
./gradlew bootRun
以下のコマンドでレスポンスが戻ってくることが確認できたら完了です。
curl -X GET \
-H "Accept: application/json" \
"http://localhost:8080/api/customers"
# {"customers":[{"first_name":"Alice","last_name":"example01"},{"first_name":"Bob","last_name":"example02"}]}
まとめ
本記事では OpenAPI Generator を利用して、Kotlin(Spring Boot)で API のソースコードを自動生成する方法を紹介しました。
OpenAPI Generator によってスキーマ駆動開発による並行開発や開発者が注力する領域をドメインに限定できます。
さまざまな言語で利用できるため、新規開発で新しい言語を導入する敷居も下がるので、ぜひ利用してみてください。
参考
Discussion