LoginSignup
7
6

More than 5 years have passed since last update.

Ktor+Gradle Kotlin DSL+ MoshiでAPIを書いてみた

Last updated at Posted at 2018-11-23

Ktorとは

Ktor is a framework for building asynchronous servers and clients in connected systems using the powerful Kotlin programming language. This website provides a complete reference to the Ktor application structure and programming interface. And how to approach particular tasks.

「Kotlin製の軽量なWebアプリケーションフレームワーク」とのことで今回1.0.0正式版がでたのでHow to create an API using ktorを参考に簡単に触って見ました

ちなみに読み方は「ケイター」らしいです

kay-tor
What is the proper way to pronounce ktor?

プロジェクトの作成

Setting up the projectの「Open the pre-configured generator form」からプロジェクトを自動生成し、できたプロジェクトのsetting.gradleをIDE(IntelliJ)で読み込みます
build.gradleは以下のような定義になっているはずです

buildscript {
    repositories {
        jcenter()
    }

    dependencies {
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
    }
}

apply plugin: 'kotlin'
apply plugin: 'application'

group 'api-example'
version '0.0.1-SNAPSHOT'
mainClassName = "io.ktor.server.netty.EngineMain"

sourceSets {
    main.kotlin.srcDirs = main.java.srcDirs = ['src']
    test.kotlin.srcDirs = test.java.srcDirs = ['test']
    main.resources.srcDirs = ['resources']
    test.resources.srcDirs = ['testresources']
}

repositories {
    mavenLocal()
    jcenter()
    maven { url 'https://kotlin.bintray.com/ktor' }
}

dependencies {
    compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
    compile "io.ktor:ktor-server-netty:$ktor_version"
    compile "ch.qos.logback:logback-classic:$logback_version"
    compile "io.ktor:ktor-server-core:$ktor_version"
    compile "io.ktor:ktor-auth:$ktor_version"
    compile "io.ktor:ktor-auth-jwt:$ktor_version"
    compile "io.ktor:ktor-jackson:$ktor_version"
    testCompile "io.ktor:ktor-server-tests:$ktor_version"
}

ビルドスクリプトの書き換え

生成されるビルドスクリプトが色々古いので書き換えていきます

Gradleのバージョンアップ

自分がプロジェクトを生成した時はwrapperにv4.8が指定されていましたが最新はv4.10.2なのでアップデートします

./gradlew wrapper --gradle-version=4.10.2 --distribution-type=bin

compileをimplementationに書き換える

compileは非推奨なのでimplementationに書き換えます
参考:Dependency configurations

dependencies {
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
    implementation "io.ktor:ktor-server-netty:$ktor_version"
    implementation "ch.qos.logback:logback-classic:$logback_version"
    implementation "io.ktor:ktor-server-core:$ktor_version"
    implementation "io.ktor:ktor-auth:$ktor_version"
    implementation "io.ktor:ktor-auth-jwt:$ktor_version"
    testImplementation "io.ktor:ktor-jackson:$ktor_version"
}

GroovyをKotlinに書き換える

Gradle 5.0RCから正式版になるKotlin Gradle DSLに書き換えます(現在はRC版です)

build.gradlebuild.gradle.kts
setting.gradlesetting.gradle.kts
にそれぞれ変更した後以下のようにコードを書き換えます
refs:
Migrating build logic from Groovy to Kotlin
gradle/kotlin-dsl-samples
SourceSets - Groovy -> Kotlin DSL #443

build.gradle.kts

import org.jetbrains.kotlin.cli.jvm.main
import org.jetbrains.kotlin.config.KotlinCompilerVersion

buildscript {
    repositories {
        jcenter()
    }

    dependencies {
        val kotlin_version: String by project
        classpath(kotlin("gradle-plugin", version = kotlin_version))
    }
}

plugins {
    application
    kotlin("jvm") version "1.3.10"
}

group = "triplan-api"
version = "1.0.0-SNAPSHOT"

application {
    mainClassName = "io.ktor.server.netty.EngineMain"
}

sourceSets {
    getByName("main").java.srcDirs("src")
    getByName("test").java.srcDirs("test")
    getByName("main").resources.srcDirs("resources")
    getByName("test").resources.srcDirs("testresources")

}

repositories {
    mavenLocal()
    jcenter()
    maven { url = uri("https://kotlin.bintray.com/ktor") }
}

dependencies {
    val ktor_version: String by project
    val logback_version: String by project

    implementation(kotlin("stdlib-jdk8", KotlinCompilerVersion.VERSION))
    implementation("io.ktor:ktor-server-netty:$ktor_version")
    implementation("ch.qos.logback:logback-classic:$logback_version")
    implementation("io.ktor:ktor-server-core:$ktor_version")
    implementation("io.ktor:ktor-auth:$ktor_version")
    implementation("io.ktor:ktor-auth-jwt:$ktor_version")
    implementation("io.ktor:ktor-jackson:$ktor_version")
    testImplementation("io.ktor:ktor-server-tests:$ktor_version")
}

Jsonコンバーターの設定

デフォルトだとJacksonもしくはGsonを選択できますがKotlinと相性がよくないのでMoshiを利用したいと思います。
PRは出ているので、将来的にはサポートされるのかな..
Moshi content negotiation support for servers #551
上記のPRのMoshiConverter.ktだけ拝借します。Kotlinのバージョンが古く単純に取り込んでも動かないので、コルーチンをexperimental→正式版にあげます

MoshiConverter.kt
-import kotlinx.coroutines.experimental.io.ByteReadChannel
-import kotlinx.coroutines.experimental.io.jvm.javaio.toInputStream 
+import kotlinx.coroutines.io.ByteReadChannel
+import kotlinx.coroutines.io.jvm.javaio.toInputStream

Moshiはランタイム時にリフレクションでJsonAdapterを生成する方法とMoshi Codegenというコンパイル時にkaptで事前にJsonAdapterのコードを自動生成する方法の2つがありますが、今回は後者を利用します

build.gradle.kts/kaptの有効化
plugins {
kotlin("jvm") version "1.3.10"
+kotlin("kapt") version "1.3.10"
application
}
依存ライブラリの追加
    implementation("com.squareup.moshi:moshi:$moshi_version")
    implementation("com.squareup.moshi:moshi-kotlin:$moshi_version")
    kapt("com.squareup.moshi:moshi-kotlin-codegen:$moshi_version")
レスポンスクラス
@JsonClass(generateAdapter = true)
data class Snippet(val text: String)

ここで一旦コマンドから./gradlew buildを実行します。そうするとbuild/generated/source/kaptKotlin/main/[packagename]SnippetJsonAdapterが生成されると思います。
※AndroidStudioだとIDE上からbuildすればkaptは自動実行されますが、IntelliJだとgradleメニューからbuildを実行しても生成されませんでした。。

Application.kt
install(ContentNegotiation) {
    moshi()
}

KtorではContent NegotiationでContent-TypeとAcceptに応じたカスタムの処理を定義することができます。
カスタムコンバーターを定義したい場合はContentConverterを実装してリクエスト/レスポンス時のコンバート処理を定義することができます。
すでに組み込まれているGsonConverter/JacksonConverter、そして今回PRから拝借したMoshiConverterも上記インターフェースを実装しています

リクエスト

Routingでリクエストの処理を定義します

val snippets = Collections.synchronizedList(
    mutableListOf(
        Snippet("hello"),
        Snippet("world")
    )
)
~~
    routing {
        get("/snippets") {
            call.respond(mapOf("snippets" to synchronized(snippets) { snippets.toList() }))
        }
    }
~~

結果

無事取得できました

# GET localhost:8080/snippets

{
    "snippets": [
        {
            "text": "hello"
        },
        {
            "text": "world"
        }
    ]
}

最後に

Ktor自体というよりかはGradleやMoshiの話中心になってしましたが以上になります。
最後まで見ていただきありがとうございました。
今回のコードは全部下記にあります
https://github.com/aya2453/triplan-api

7
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
6