サーバーサイドをKotlinではじめてみた

４年ほどPHPユーザーでしたが、ふと思い立ってKotlinにトライしてみようと思いました。
個人的メモも兼ねて。
ちなみに手元の環境は *MacBook Pro（2017年モデル/RAM16GB/High Sierra 10.13）* です。

## やりたいこと
- 開発環境の構築
- Hello World的な何か
- 最終的にはRESTfulなAPIを構築したい

## 環境構築
JDKとかエディタとか導入していきます。

### 1.エディタ
今までATOMとかVSCodeをゴリゴリ使っていましたが、IDE使いたいなぁと思ったので定番の**IntelliJ IDEA**を採用！
https://www.jetbrains.com/idea/download/ にアクセスするとUltimate版とCommunity版があります。DBツールとかJS/TSツールも導入されているUltimate版にしました。どうやら30日間の無料試用期間があるみたいなのでイマイチだったらそこでやめればいいかなぁと。

インストールは基本的に**Yes**連呼していれば良さげですが、**Tune IDEA to your tasks**の画面で下へスクロールすると、DBツールがDisableになっていたのでこれをEnableにしました。

### 2.JDK
他でJavaを扱う機会があったため、手元では既にJDK1.8を導入済みでした...。
[こちらの公式サイト](http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html)からダウンロードできます。

## Hello World的な何か
**Spring Boot**を用いて超簡単なAPIを立てます。

### 1.ひな形の作成
まず https://start.spring.io/ でひな形を作成します。
<img width="1184" alt="スクリーンショット 2018-08-17 17.44.49.png" src="https://qiita-image-store.s3.amazonaws.com/0/172185/aee6b9a7-05d6-b03c-5a2b-1041ea3842f4.png">
こんな感じで入力。（Project Metadataは自分に合わせた内容で。）
**Generate Project**を押すとZipファイルがDLされるのでこれを解凍します。

### 2.IntelliJ IDEAで読み込む
IntelliJ IDEAを早速起動します。
<img width="663" alt="スクリーンショット 2018-08-17 17.32.03.png" src="https://qiita-image-store.s3.amazonaws.com/0/172185/bd105b56-862c-0047-1045-c2d597eed041.png">
【Open】を選択し、先ほど解凍したディレクトリを選び、完了です！簡単。

### 3.Controllerの作成
<img width="354" alt="スクリーンショット 2018-08-17 17.52.57.png" src="https://qiita-image-store.s3.amazonaws.com/0/172185/1f9405f2-5a7d-b884-8bf7-5a500b88739d.png">
この位置にKotlin Class Fileを新規作成します。
<img width="344" alt="スクリーンショット 2018-08-17 17.52.43.png" src="https://qiita-image-store.s3.amazonaws.com/0/172185/7f7fea91-6301-f52e-1eec-2adc4c2881ca.png">
こんな感じ。

```WelcomeController.kt
package me.icetea.helloworld

import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RestController
import org.springframework.web.bind.annotation.RequestMapping

@RestController
@RequestMapping("hello")
class HelloController {
    @GetMapping("")
    fun index(): String {
        return "Hello World!!"
    }
}
```

- `@RestController`アノテーションは`@Controller`アノテーションと異なり、直接コンテンツを配信します。
- `@RequestMapping("hoge")`でルーティングを実装しています。`@GetMapping`はGETリクエスト限定のアノテーションで、可読性向上のために用いています。

### 4.Webサーバー起動
IntelliJ IDEAのTerminalで`./gradlew clean bootRun`を実行するとWebサーバーが起動します。`http://localhost:8080/hello`にアクセスして**Hello World!!**と表示されていれば成功です！！

## （RESTfulな）API
APIを構築するために、先ほどのControllerにJSONを返すメソッドを追加します。

### 1.Modelの作成
今回は要素として名前とメールアドレスを持つ**User**というModelを作成します。
<img width="295" alt="スクリーンショット 2018-08-17 18.42.38.png" src="https://qiita-image-store.s3.amazonaws.com/0/172185/c63a5efa-7acb-c733-d741-3c1eadbccfb0.png">

```User.kt
package me.icetea.helloworld.Model

import javax.validation.constraints.NotBlank

data class User(
        @field:NotBlank val name: String = "",
        @field:NotBlank val email: String = "",
        @field:NotBlank val registered: Boolean = (name.isNotEmpty() && email.isNotEmpty())
)
```
`@field`アノテーションでバリデーションを実装しています。

### 2.Controllerの修正

```WelcomeController.kt
package me.icetea.helloworld

import me.icetea.helloworld.Model.User
import org.springframework.http.MediaType
import org.springframework.web.bind.annotation.*

@RestController
@RequestMapping("/hello")
class HelloController {
    @GetMapping("")
    fun index() = "Hello World!!"

    @PostMapping("/post/user", consumes = [MediaType.APPLICATION_FORM_URLENCODED_VALUE])
    fun receiveUser(@RequestParam body: Map<String, String>) = User(body["name"] ?: "", body["email"] ?: "")
}
```
`@PostMapping("/post/user", consumes = [MediaType.APPLICATION_FORM_URLENCODED_VALUE])`とすることで、`/hello/post/user`にform-urlencodedでPOSTできるようになります。
またこのパラメータはMap型で受け取ります。

**【補足】**
Kotlinには三項演算子がない代わりにif文を式として扱えるので
`var hoge: String = (if(fmfm !== null) fmfm!! else "Text")`
のような書き方になっています。

KotlinではNullableな型に対してエルビス演算子`:?`でNullチェックを行うことができます。

### 4.Webサーバー起動＆テスト
`./gradlew clean bootRun`を再び実行してWebサーバーを再起動します。`http://localhost:8080/hello/post/user`にnameとemailをPOSTしてみましょう。
今回は[Postman](https://www.getpostman.com/)というソフトを利用しています。簡単にAPIが試せるので重宝します。

<img width="1027" alt="スクリーンショット 2018-08-17 18.59.15.png" src="https://qiita-image-store.s3.amazonaws.com/0/172185/14a93e66-1f19-ae09-1bea-85195c38d293.png">
このように表示されれば正しく実装できました！！