複雑なサーバの構築

Estimated reading time: 1 minute

サーバーのコードの複雑さ次第で、なんらかの方法でコードを構造化する必要があるかもしれません。 このページでは、進化に適応しコードをシンプルに保てるような複雑度に応じたコード構造化戦略をいくつか提案します。

目次:

Hello World

Ktorで始めるためには、シンプルにmain関数内でembeddedServerを起動すればいいです。

fun main(args: Array<String>) {
    embeddedServer(Netty, port = 8080) {
        routing {
            get("/") {
                call.respondText("Hello World!")
            }
        }
    }.start(wait = true)
}

Ktorがどのように動くのかを理解したり、アプリケーションコードをひと目で確認できるという意味では良い方法です。

moduleの定義

サーバーを設定するためのコードを拡張関数として抽出することもできます。 これはKtor moduleと呼ばれます:

fun main(args: Array<String>) {
    embeddedServer(Netty, port = 8080, module = Application::mainModule).start(wait = true)
}

fun Application.mainModule() {
    routing {
        get("/") {
            call.respondText("Hello World!")
        }
    }
}

routeの切り出し

コードが成長し始め、より多くのrouteを定義し始めると、main関数をずっと成長させ続けるかわりにコードを分割したいと思うかもしれません。

分割するためのシンプルな方法は、routeをRoutingクラスをレシーバとした拡張関数に切り出すことです。

サイズに応じて、同じファイル内に定義するか、別ファイルに移動するかを選択できます:

fun main(args: Array<String>) {
    embeddedServer(Netty, port = 8080, module = Application::mainModule).start(wait = true)
}

fun Application.mainModule() {
    routing {
        root()
    }
}

// Extracted route
fun Routing.root() {
    get("/") {
        call.respondText("Hello World!")
    }
}

routing { ... }ブロック内では、暗黙的にthisがthis: Routingになっています。 そのためrootメソッドを直接呼び出すことができます。 this.root()を呼び出すのと同じ結果になります。

デプロイとapplication.conf

一度サーバーをデプロイしたあとに、再コンパイルすることなくサーバーの設定を外から追加・変更したいかもしれません。

Ktorライブラリはresourceのapplication.confファイルまたは外部ファイルを読み込むいくつかのエントリーポイントを公開しています。 ファイル内ではアプリケーションのエントリーポイントであったり、利用するportであったり、ssl設定であったり、その他任意の設定を定義できます。

設定ページで、application.confの使い方についてより詳しく見ることができます。

ヘルスチェック

アプリケーション次第で、ヘルスチェックの方法は色々異なる方法を使いたいかもしれません。 最も簡単な方法はHTTP 200 OKを返す/health_checkといった感じのエンドポイントを有効にしておき、必要に応じて依存サービスを検証することです。 全てはあなた次第です。

exceptionをハンドルするためにステータスページ機能を利用することもできます。

install(StatusPages){
    exception<Throwable> { cause ->
        call.respond(HttpStatusCode.InternalServerError)
    }
}
routing {
    get("/health_check") {
        // Check databases/other services.
        call.respondText("OK")
    }
}