KtorをInteliJで起動してみた

Kotlin製のWebフレームワークであるKtorの開発環境を準備しました。

https://github.com/ktorio/ktor

**追記**
2019/10/26 Portの指定方法

## 環境
- windows10
- OpenJDK13(build 13.0.1+9)
- IntelliJ IDEA Community Edition 2019.2.3

## Ktor Projectの作成方法
InteliJ上でKtorの開発する際には、以下の2つの方法があります。

1.  IntelliJに`Ktorプラグイン`を追加し、Ktorプロジェクトを新規作成
2.  [Ktor Project Generator](https://start.ktor.io/)でKtorプロジェクトを新規作成


## InteliJでKtor Project作成
ここでは、下記要領でのKtor Projectの新規作成方法を記載します。

### 1.InteliJに開発用Plugin追加
InteliJ上で、デフォルトではKtorの開発環境は整っていません。
そのため、`Ktor Plugin`をインストールし、開発環境を整えていきます。

[設定] 選択 -> [プラグイン] 選択 -> 「`Ktor`」入力 -> [Install]押下
![キャプチャ-Ktor pulgin install.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/488212/1f9b6edf-f79b-00f3-f9c4-73ff3cd65a6e.png)


### 2.Ktor Project新規作成

[新規プロジェクト] 選択 -> [Ktor] 選択 -> 各種設定 -> [新規作成]押下
![キャプチャ-Create Ktro Project.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/488212/1b9108b4-41c2-4245-a323-8252935ddd6e.png)

各種入力 -> [次へ]
![キャプチャ-Create Ktro Project2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/488212/3cb230a8-1916-686f-bb7f-1367c3e906dd.png)

プロジェクト名とロケーションを指定 -> [完了]押下
![キャプチャ-Create Ktro Project3.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/488212/a49c63ea-11ac-1e44-3370-8bd6972ac376.png)

プロジェクトが作成されたことを確認
![キャプチャ-Create Ktro Project4.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/488212/5dfa67f5-5fa4-4097-e5c1-9b0e3e4ffbda.png)

### 3.起動確認

Mainクラスである、Application.ktを実行することでKtorアプリケーションが実行されます。
また、Gradleのコマンドからの実行も可能です。

- Application.kt(初期状態ママ)

```kotlin
package jp.co.musako

import io.ktor.application.*
import io.ktor.response.*
import io.ktor.request.*
import io.ktor.routing.*
import io.ktor.http.*
import io.ktor.html.*
import kotlinx.html.*
import kotlinx.css.*
import io.ktor.client.*
import io.ktor.client.engine.apache.*

fun main(args: Array<String>): Unit = io.ktor.server.netty.EngineMain.main(args)

@Suppress("unused") // Referenced in application.conf
@kotlin.jvm.JvmOverloads
fun Application.module(testing: Boolean = false) {
    val client = HttpClient(Apache) {
    }

    routing {
        get("/") {
            call.respondText("HELLO WORLD!", contentType = ContentType.Text.Plain)
        }

        get("/html-dsl") {
            call.respondHtml {
                body {
                    h1 { +"HTML" }
                    ul {
                        for (n in 1..10) {
                            li { +"$n" }
                        }
                    }
                }
            }
        }

        get("/styles.css") {
            call.respondCss {
                body {
                    backgroundColor = Color.red
                }
                p {
                    fontSize = 2.em
                }
                rule("p.myclass") {
                    color = Color.blue
                }
            }
        }
    }
}

fun FlowOrMetaDataContent.styleCss(builder: CSSBuilder.() -> Unit) {
    style(type = ContentType.Text.CSS.toString()) {
        +CSSBuilder().apply(builder).toString()
    }
}

fun CommonAttributeGroupFacade.style(builder: CSSBuilder.() -> Unit) {
    this.style = CSSBuilder().apply(builder).toString().trim()
}

suspend inline fun ApplicationCall.respondCss(builder: CSSBuilder.() -> Unit) {
    this.respondText(CSSBuilder().apply(builder).toString(), ContentType.Text.CSS)
}

```

Ktorアプリケーションを、Gradleコマンドを使用して起動します。

```
>cd {$project root}
>gradlew build run
```

- 起動ログ

```
Welcome to Gradle 4.10!

Here are the highlights of this release:
 - Incremental Java compilation by default
 - Periodic Gradle caches cleanup
 - Gradle Kotlin DSL 1.0-RC3
 - Nested included builds
 - SNAPSHOT plugin versions in the `plugins {}` block

For more details see https://docs.gradle.org/4.10/release-notes.html

Starting a Gradle Daemon (subsequent builds will be faster)

> Task :compileKotlin
w: C:\Users\hoge\Documents\workspace-kotlin\ktor-sample\src\Application.kt: (27, 24): Parameter 'testing' is never used
w: C:\Users\hoge\Documents\workspace-kotlin\ktor-sample\src\Application.kt: (54, 9): Variable 'client' is never used
w: C:\Users\hoge\Documents\workspace-kotlin\ktor-sample\src\Application.kt: (123, 9): 'unaryPlus(): Unit' is deprecated. This tag most likely doesn't support text content or requires uns
afe content (try unsafe {}

> Task :run
2019-10-25 19:31:34.844 [main] TRACE Application - {
    # application.conf @ file:/C:/Users/hoge/Documents/workspace-kotlin/ktor-sample/build/resources/main/application.conf: 6
    "application" : {
        # application.conf @ file:/C:/Users/hoge/Documents/workspace-kotlin/ktor-sample/build/resources/main/application.conf: 7
        "modules" : [
            # application.conf @ file:/C:/Users/hoge/Documents/workspace-kotlin/ktor-sample/build/resources/main/application.conf: 7
            "jp.co.musako.ApplicationKt.module"
        ]
    },
    # application.conf @ file:/C:/Users/hoge/Documents/workspace-kotlin/ktor-sample/build/resources/main/application.conf: 2
    "deployment" : {
        # application.conf @ file:/C:/Users/hoge/Documents/workspace-kotlin/ktor-sample/build/resources/main/application.conf: 3
        "port" : 8080
    },
    # Content hidden
    "security" : "***"
}

2019-10-25 19:31:35.415 [main] INFO  Application - No ktor.deployment.watch patterns specified, automatic reload is not active
2019-10-25 19:31:36.276 [main] INFO  Application - Responding at http://0.0.0.0:8080
```

- 動作確認

```
>curl localhost:8080
HELLO WORLD!
```

これで、Ktorアプリケーションが起動することを確認しました。

なお、Ktorプロジェクトの作成時の設定により、InteliJで生成されるデフォルトのMainクラスでは、Ktorアプリケーションの起動時にエラーとなり、[Ktor Project Generator]で生成したKtor Projectでも同様の事象が発生しています。

その差分は、把握している限りでは`HTTPClient Engine`に対して、`HttpClientEngine`のみを指定している場合です。これは、サーバの起動処理自体が、[io.ktor.client.engine.apache.ApacheEngine](https://github.com/ktorio/ktor/blob/master/ktor-client/ktor-client-apache/jvm/src/io/ktor/client/engine/apache/ApacheEngine.kt)などで実装されており、このようなサーバの起動をする処理を実装していないために発生するものです。
今回は`Apache HttpClient Engine`を指定してプロジェクトを作成していたのでエラーが発生しませんでした。

サーバーの種類を問わないのであれば、[quickstart](https://ktor.io/quickstart/)に記載があるように、独自でサーバを起動させる処理を書きましょう。

- Application.kt

```kotlin
import io.ktor.application.*
import io.ktor.http.*
import io.ktor.response.*
import io.ktor.routing.*
import io.ktor.server.engine.*
import io.ktor.server.netty.*

fun main(args: Array<String>) {
    val server = embeddedServer(Netty, port = 8080) {
        routing {
            get("/") {
                call.respondText("Hello World!", ContentType.Text.Plain)
            }
            get("/demo") {
                call.respondText("HELLO WORLD!")
            }
        }
    }
    server.start(wait = true)
}
```

なお、独自で`embeddedServer`で実装する際には、サーバーの設定も行えるので、詳細は[Configuring the embeddedServer](https://ktor.io/servers/configuration.html#embedded-server)を参照してください。


## Port番号の指定

起動したサーバーのPortは、resouce -> application.confで定義されています。


```conf
ktor {
    deployment {
        port = 8080
        port = ${?PORT}
    }
    application {
        modules = [ jp.co.musako.ApplicationKt.module ]
    }
}

```

[Configuring the Server](https://ktor.io/servers/configuration.html)

## ref

- forests-k/ソースコード：[ktor-sample](https://github.com/forests-k/ktor-sample)
- [GitHub - ktorio/ktor: Framework for quickly creating connected applications in Kotlin with minimal effort](https://github.com/ktorio/ktor)
- [Quick Start - Quick Start - Ktor](https://ktor.io/quickstart/)
- [Ktor Project Generator (1.2.4)](https://start.ktor.io/)