会社でKotlin dojo(第39回)を開催した

今週は第39回を開催しました。引き続きKotlin Hands-on編です!

 

前回の様子はコチラ↓

kdnakt.hatenablog.com

 

 

[第39回の様子]

2020/11/11に第39回を開催した。

 

参加メンバーは自分をいれて5名。先週までの安定のメンツ3名に加えて、久しぶりに参加してくれたメンバーが2名。ときどきでもこうして戻ってきて、教えてくれるのはありがたい。

 

勉強会本編の内容としては、前回からはじめたKotlin Hands-on

Creating HTTP APIs with Ktorを継続中。第3章のCustomer Routesの続きを、Returning a specific customerから章の終わりまで進めた。最後のところで、動作確認をしたければ第5章へ進んでもよいと書かれていたので、前回の予想は当たっていそうだ。実装したコードを早く実際に動かしてみたい!

 

今回も、Hands-on編に入って初めてのドライバーが担当してくれた。リポジトリのクローンや、IntelliJのセットアップを済ませておいてくれたので、スムーズに勉強会を始めることができた!

 

[学んだことや疑問点]

  • Creating HTTP APIs with Ktor: 3. Customer Routes
    • Returning a specific customer
    • パスパラメータでIDを指定したCustomerを取得するルーティングを実装する
    • パスパラメータからIDを取得する部分の実装は以下のようになっていた
get("{id}") {
    val id = call.parameters["id"] ?: return@get call.respondText(
        "Missing or malformed id",
        status = HttpStatusCode.BadRequest
    )
    val customer =
        customerStorage.find { it.id == id } ?: return@get call.respondText(
            "No customer with id $id",
            status = HttpStatusCode.NotFound
        )
    call.respond(customer)
}
    • ?:を使っている部分が記述量が少なくて良いなと感じた。Javaだとif (customer == null)とかが入って長くなりそう。
    • call.parameters["id"]の部分はktor/Parameters.ktの実装を見ると、StringList<String>のMapになっているようだった
    • return@getのラベル付きリターンは、get("{id}")の外側にある関数のreturnと区別するために必要っぽかった。本来なら一番最後のcall.respond(customer)の部分にもラベル付きリターンをつけてもよいが、関数の一番最後の場合はラベル付きリターンを省略できる、と解説してもらった。Kotlinのラベルはこの勉強会で何度か出てきたけど、まだ少し苦手意識が……実装例を見ずに実装しろと言われた場合に、アーリーリターンの部分でラベルをつけ忘れそうな気がする。
    • 前回も登場していたrespondTextの関数定義は以下のようになっている
public suspend fun ApplicationCall.respondText(text: String,
        contentType: ContentType? = null, status: HttpStatusCode? = null,
        configure: OutgoingContent.() -> Unit = {}) {
    val message = TextContent(text, defaultTextContentType(contentType), status)
        .apply(configure)
    respond(message)
}
    • 型はHttpStatusCodeと決まっていて同じ型の引数は他にないのだから、わざわざパラメータに名前つきでstatus = 〜の形で関数を呼び出すのがやや冗長な気がする。関数定義をオーバーロードしておいてくれればいいのに。
    • Creating a customer
    • Customerを登録する場合のAPIの実装例
    • KtorでリクエストボディのJsonをオブジェクトにシリアライズするときはcall.receive<T>()を使うようだ
    • マルチスレッドとか考慮してないサンプルだから気をつけてね、とエクスキュースが書かれていた。まあHands-onなのでそこまでは求めていない。雰囲気がわかればヨシ。
    • Deleting a customer
    • Customerを削除するAPIの実装。サイトの例ではつぎのようになっていた。特筆すべきポイントはなし。
delete("{id}") {
    val id = call.parameters["id"] ?: return@delete call.respond(HttpStatusCode.BadRequest)
    if (customerStorage.removeIf { it.id == id }) {
        call.respondText("Customer removed correctly", status = HttpStatusCode.Accepted)
    } else {
        call.respondText("Not Found", status = HttpStatusCode.NotFound)
    }
}
    • Registering the routes
    • ここまでで作成したルーティングを、アプリケーションに登録する必要がある
    • CustomerRoutes.kt内でApplicationの拡張関数を定義して、それをApplication.kt側でimportして利用する形式。
// CustomerRoutes.kt
fun Application.registerCustomerRoutes() {
    routing {
        customerRouting()
    }
}


fun Route.customerRouting() {
    // 省略
}

// Application.kt
// ここでインポート
import com.jetbrains.handson.httpapi.routes.registerCustomerRoutes

fun Application.module() {
    install(ContentNegotiation) {
        json()
    }
    // ここで利用
    registerCustomerRoutes()
}
    • Application.registerCustomerRoutesという拡張関数を作っているのに、インポートするときはApplicationの部分は不要らしい。学びだ……多分IDEのサポートを受けないでKotlinを実装することはないだろうから、そこまで気をつけなくても大丈夫なポイントだろうか。
    • そういえば前回やったcall.respondのimportも同じく拡張関数の関数名のみのインポートだった。そういうものらしいと覚えておこう。

 

[まとめ]

モブプログラミング・スタイルで、Kotlin Hands-onを継続している。

APIのルーティングの実装を通して、ラベルつきリターンや拡張関数のimport文などについて復習した。

実装したHTTP APIを実際に動かすのはいつになることやら……!

 

今週の進捗は以下のプルリクエストにまとまっている。

github.com