🏝️

Kotlin/Nativeでシングルバイナリから起動するHTTP APIを作る

2023/02/17に公開

はじめに

最近話題(?)のKotlinを趣味で書いていますが、(Javaとの親和性はもちろん)モダンで簡潔な記法が多く、非常に書きやすい言語だと感じています。

上記のように魅力的な言語ですが、サーバーサイドKotlinというとJVMを使用するイメージが強く、運用の際にはどうしてもJVMの知識が必要です。

そこでKotlinコードから実行可能なシングルバイナリを吐けないかと考え、Kotlin Nativeという技術に関して調査してみました。

Kotlin Native とは

簡単にいうと、Kotlinのコードをネイティブバイナリにコンパイルする技術です。

https://kotlinlang.org/docs/native-overview.html

内部ではLLVMベースのコンパイラバックエンドが用いられ、出力されたバイナリの実行においてJVMは当然不要です。

想定される用途

Kotlin NativeはKotlin Multiplatform(クロスプラットフォーム間でのアプリ開発に使用される技術)に使用されており、想定される用途として、AndroidとiOS間の共通モジュール実装などが挙げられます。


Kotlin multplattformを使用したpjのアーキテクチャ概要

Web APIの構築は?

ではKotlin Nativeを用いて実行可能なシングルバイナリから起動するAPIを構築できないか?と調査したところ、下記の選定で目処がたったため実装しました。

種別 選定結果 (2023/2現在)
Web FW Ktor (100% Kotlinの軽量FW)
永続化 FW SQLDelight
DB SQLite

実装

ここでは本PJ特有の注意点に絞って解説します。

サーバーを起動するコード

以下の2点を満たす必要があります。

  • Ktor組み込みのembeddedServer関数でサーバーを起動
  • リクエスト処理にはCIO engineを使用する
条件を満たすMain.kt
fun main() {
    embeddedServer(CIO, port = 8080) {
        ...
    }.start(wait = true)
}

永続化FW(SQLDelight)の設定

ディレクトリ構成に注意点があります。

SQLDelightでは、発行されるクエリを.sqファイルに記述しますが、本PJではcommonMain/sqldelightディレクトリ以下に配置する必要があります。[1]

ビルド時の設定

SQLite用のライブラリをリンクする設定が必要です。[2]

build.gradle.kts
    apiTarget.apply {
        binaries {
            executable {
                entryPoint = "com.example.main"
                linkerOpts.add("-lsqlite3") // <- リンカに渡されるオプションを追加
            }
        }
    }

実装結果

これまでの調査から簡単なWeb APIを実装することができました。
レコードのCreate、Read、Deleteが可能ですが、排他制御に関しては考慮していません。

https://github.com/yasuaki640/impressive-ktor-native-api


動作イメージ

実装を通して感じたメリデメ

メリット

シングルバイナリの手軽さ

実行可能なシングルバイナリ形式でビルドされるため、追加でランタイムを整備する手間が省けます。
またアプリを起動する際、コンテナに出力されたバイナリを配置すれば、とりあえず起動できるため、コンテナを用いたアーキテクチャと特に親和性が高いと予想できます。

Java経験者に馴染みやすくモダンな文法

Javaでは互換性の問題から導入が見送られた機能等、モダンで簡潔な記法が使えるため、配列操作などをシュッと記述できます。

デメリット

動作するライブラリが少ない

まだまだ発展途上の技術のため、Kotlin on JVMには対応しているがKotlin Nativeでは動かないライブラリが大量に存在し、Ktor公式ですらKotlin Nativeに未対応のライブラリが存在しています。
今回の例として、リクエストログを出力する機構は自作しました。[3]

ビルド時間

手元のM2 MacBook Air環境でビルドしたところ、下記のような結果となり、(筆者は他の言語で比較できないですが)少なくとも早いとは感じませんでした。

初回ビルド
$ time ./gradlew apiMainBinaries
...
./gradlew apiMainBinaries  0.84s user 0.11s system 1% cpu 58.047 total
二回目ビルド
$ time ./gradlew apiMainBinaries
...
./gradlew apiMainBinaries  0.85s user 0.12s system 1% cpu 52.769 total

ネットに情報が少ない

日本語の情報は皆無で、英語ですら検索にヒットしない場合があります。

学習コスト

Java経験者に馴染みやすい文法とはいえ、KotlinとKotlin Native両方の知識が必要です。
※しかしKotlin以外の言語に移行する際でも、多かれ少なかれ学習コストは必要

まとめ

今回はKotlin Native + Ktor + SQLiteで簡単なAPIを作成しました。
まだまだ発展途上の技術ですが、今後のKotlinに期待できるような体験ができたため、趣味でも触っていきたいと思います。

以上。(※記事への指摘歓迎)

参考

https://kotlinlang.org/docs/native-overview.html

https://ktor.io/docs/creating-http-apis.html

https://betterprogramming.pub/create-a-kotlin-native-web-server-with-ktor-and-sqldelight-postgressql-44485267c340

脚注
  1. 参考としたブログ (公式ドキュメントではそのような言及は見つけられなかった) ↩︎

  2. https://github.com/cashapp/sqldelight/issues/1442#issuecomment-615991279 ↩︎

  3. https://github.com/yasuaki640/impressive-ktor-native-api/blob/main/src/apiMain/kotlin/com/example/plugins/RequestLogging.kt ↩︎

GitHubで編集を提案

Discussion