Spring Boot/KotlinでCRUD操作のできるAPIを作成する方法

Spring BootとKotlinを使ってCRUD操作のできるAPIを作成します。

## 環境
Docker: 18.09.2
Springboot: 2.1.5
Kotlin: 1.3.31
MySQL: 5.7.26

# プロジェクトの作成
まずはSpring Bootのプロジェクトを作成しましょう。

1.[Sprin Initializr](https://start.spring.io/)にアクセスします。
2.ProjectはMavenかGradleかお好みで、LanguageはKotlin、Spring Bootのバージョンは2.X以降のものを選びましょう。
3.Project Metadataは必要に応じて変更してください。今回はArtifactを`sample_qiita`にしています。
4.Dependenciesは`Web`,`JPA`,`MySQL`を選択します。
5.最後にGenerate Projectをクリックして設定の終わったプロジェクトをダウンロードし、ローカルで開きます。

![スクリーンショット 2019-06-05 12.16.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/391127/225763c6-9f20-a859-fcb9-d814232ba436.png)

ローカルのIDEなどで開くとディレクトリ構造は次のようになっていると思います。

```
sample_qiita
　├ .idea
　├ .gradle
　├ src
　│　├ main
　│　│　├ kotlin
　│　│　│  └ com.example.sample_qiita
　│　│　│     └ SampleQiitaAppllication.kt
　│　│　└ resources
　│　│     ├ static　
　│　│　  　├ templates
　│　│     └ application.properties
　│　└ test
　│　　　└ kotlin
　│　　　　　└ com.example.sampleqiita
　│　　　　　　　└ SampleQiitaAppllicationTests
　├ .gitignore
　├ build.gradle.kt
　・
　・
　・
　└ External Libraries
```


# MySQLの接続設定
今回はDockerコンテナを立てて、その中のMySQLを使用したいので、[こちらの記事](https://qiita.com/dddEn/items/3fc8a583586ee838afd9)を参考に`sample_qiita`直下に`docker-compose.yml`を作成します。

```:docker-compose.yml
db:
  image: mysql:5.7
  ports:
    - "3306:3306"
  environment:
    MYSQL_DATABASE: sample_qiita_db
    MYSQL_ROOT_USER: root
    MYSQL_ROOT_PASSWORD: root
```

次にSpring Bootがデータソースを作成できるようにMySQLのURL、ユーザー名、パスワードを設定する必要があります。
`src/main/resources/application.properties`を編集します。

```:application.properties
## Spring DATASOURCE (DataSourceAutoConfiguration & DataSourceProperties)
spring.datasource.url = jdbc:mysql://127.0.0.1:3306/sample_qiita_db?autoReconnect=true&useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true&useSSL=false
spring.datasource.username = root
spring.datasource.password = root

## Hibernate Properties

# The SQL dialect makes Hibernate generate better SQL for the chosen database
spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5InnoDBDialect

# Hibernate ddl auto (create, create-drop, validate, update)
spring.jpa.hibernate.ddl-auto = update
```

これでDockerコンテナ上のMySQLと接続できるようになりました。

# Modelの作成
Entityを作成していきましょう。
`com.example.sample_qiita`内に`model`というパッケージを作成し、その中に`Qiita.kt`というファイルを作成しましょう。

```kotlin:Qiita.kt
package com.example.sample_qiita.model

import javax.persistence.Entity
import javax.persistence.GeneratedValue
import javax.persistence.GenerationType
import javax.persistence.Id
import javax.validation.constraints.NotBlank

@Entity
data class Qiita (
        @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
        val id: Long = 0,

        @get: NotBlank
        val title: String = "",

        @get: NotBlank
        val content: String = ""
)

```

今回はQiitaクラスの全てのフィールドにデフォルト値を設定しています。
これはHibernateが引数のないコンストラクタを持つEntityを必要とするためです。

全てのフィールドにデフォルト値を割り当てると、Hibernateは引数を渡さずにQiitaをインスタンス化できるようになります。

# Repositoryの作成
`con.example.sample_qiita`内に`repository`パッケージを作成し、その中に`QiitaRepository.kt`を作成しましょう。

```kotlin:QiitaRepository
package com.example.sample_qiita.repository

import com.example.sample_qiita.model.Qiita
import org.springframework.data.jpa.repository.JpaRepository
import org.springframework.stereotype.Repository

@Repository
interface QiitaRepository: JpaRepository<Qiita, Long>
```

これにより`JpaRepository`から`QiitaRepository`を拡張したので、Qiitaエンティティを用いた全てのCRUDメソッドが使えるようになりました。

# Controllerの作成
最後にQiitaエンティティに対するCRUD操作をするためのコントローラを作成します。

`com.example.sample_qiita`パッケージ内に`controller`というパッケージを作成し、その中に`QiitaController.kt`を作成します。

```kotlin:QiitaController.kt
package com.example.sample_qiita.controller

import com.example.sample_qiita.model.Qiita
import com.example.sample_qiita.repository.QiitaRepository
import org.springframework.http.HttpStatus
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.*
import javax.validation.Valid

@RestController
@RequestMapping("/api")
class QiitaController(private val qiitaRepository: QiitaRepository) {

    @GetMapping("/qiitas")
    fun getAllQiitas(): List<Qiita> =
            qiitaRepository.findAll()

    @PostMapping("/qiitas")
    fun createNewQiita(@Valid @RequestBody qiita: Qiita): Qiita =
            qiitaRepository.save(qiita)

    @GetMapping("/qiitas/{id}")
    fun getQiitaBiId(@PathVariable(value = "id") qiitaed: Long): ResponseEntity<Qiita> {
        return qiitaRepository.findById(qiitaed).map { qiita ->
            ResponseEntity.ok(qiita)
        }.orElse(ResponseEntity.notFound().build())
    }

    @PutMapping("/qiitas/{id}")
    fun updateQiitaById(@PathVariable(value = "id") qiitaed: Long,
                          @Valid @RequestBody newQiita: Qiita): ResponseEntity<Qiita> {

        return qiitaRepository.findById(qiitaed).map { existingQiita ->
            val updateQiita: Qiita = existingQiita
                    .copy(title = newQiita.title, content = newQiita.content)
            ResponseEntity.ok().body(qiitaRepository.save(updateQiita))
        }.orElse(ResponseEntity.notFound().build())

    }

    @DeleteMapping("/qiitas/{id}")
    fun deleteQiitaById(@PathVariable(value = "id") qiitaed: Long): ResponseEntity<Void> {

        return qiitaRepository.findById(qiitaed).map { qiita ->
            qiitaRepository.delete(qiita)
            ResponseEntity<Void>(HttpStatus.OK)
        }.orElse(ResponseEntity.notFound().build())
    }
}
```

以上でアプリは完成したので、早速動かしてみましょう。

## 起動方法
まずはDockerkコンテナを立ち上げます。

```
$ docker-compose up -d
```

次に作成したsample_qiitaをRunしましょう。

[http://localhost:8080/api/qiitas](http://localhost:8080/api/qiitas)にアクセスして、`[]`が表示されていたら成功です。

# Rest APIの動作確認
`curl`コマンドを使って正しい反応が返ってくるか試してみましょう。

## Qiitaの作成
`/api/articles`へPOSTして送信して新しく`Qiita`が作成されるかの確認をします。
以下の内容をコマンドラインで叩いてみましょう。

```
curl -i -H "Content-Type: application/json" -X POST \
-d '{"title": "Create API by Spring Boot and Kotlin", "content": "Text of creating API"}' \
http://localhost:8080/api/qiitas
```
これを実行すると、以下のように反応が返ってくると思います。

```
HTTP/1.1 200 
Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked
Date: Wed, 05 Jun 2019 06:21:52 GMT

{"id":1,"title":"Create API by Spring Boot and Kotlin","content":"Text of creating API"}
```

これで新しくデータベースにQiitaデータが保存されました。
確認するには[http://localhost:8080/api/qiitas](http://localhost:8080/api/qiitas)にアクセスするか、次の方法を試してみましょう。

## 全データを取得する。
さっそく次の１行目のコマンドを打ってみましょう。

```
curl -i -H 'Accept: application/json' http://localhost:8080/api/qiitas

HTTP/1.1 200 
Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked
Date: Fri, 06 Oct 2017 03:25:29 GMT

{"id":1,"title":"Create API by Spring Boot and Kotlin","content":"Text of creating API"}
```

ちゃんと返ってきていますね！
作成したQiitaデータが全て返ってくると思います。

## Idで指定したQiitaを取得する。
指定したIdのデータだけを取得するコマンドになります。

```
curl -i -H 'Accept: application/json' http://localhost:8080/api/qiitas/1

HTTP/1.1 200 
Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked
Date: Wed, 05 Jun 2019 06:33:27 GMT

{"id":1,"title":"Create API by Spring Boot and Kotlin","content":"Text of creating API"}
```
URL(`localhost:8080/api/qiitas/{id}`)の最後に指定した数字と同じIDのQiitaデータを取得します。
もちろん、存在しないIDの番号を指定すると404エラーが返ってくるので注意しましょう。

## 作成したQiitaデータの更新
既に登録してあるデータの更新を行うには`PUT`メソッドを使用します。

```
curl -i -H "Content-Type: application/json" -X PUT \
-d '{"title": "How to learn Spring boot and Kotlin", "content": "Resources to learn Spring boot and Kotlin"}' \
http://localhost:8080/api/qiitas/1

HTTP/1.1 200 
Content-Type: application/json;charset=UTF-8
Transfer-Encoding: chunked
Date: Wed, 05 Jun 2019 06:45:18 GMT

{"id":1,"title":"How to learn Spring boot and Kotlin","content":"Resources to learn Spring boot and Kotlin"}
```

## Qiitaデータの削除
削除するには`DELETE`メソッドを使用します。

```
curl -i -X DELETE http://localhost:8080/api/qiitas/1

HTTP/1.1 200 
Content-Length: 0
Date: Wed, 05 Jun 2019 06:47:21 GMT
```



## 参考文献
[Building Restful APIs with Kotlin, Spring Boot, Mysql, JPA and Hibernate](https://www.callicoder.com/kotlin-spring-boot-mysql-jpa-hibernate-rest-api-tutorial/)
[Kotlin × Spring Boot で REST API サンプルアプリケーション作ってみた。](https://qiita.com/yusuke_dev/items/79c980ff7002d68f9aa5)
[Dockerを使ったSpringboot/KotlinとMySQLの一番シンプルな接続方法](https://qiita.com/dddEn/items/3fc8a583586ee838afd9)
[Kotlin Webアプリケーション 新しいサーバサイドプログラミング](https://www.amazon.co.jp/Kotlin-Web%E3%82%A2%E3%83%97%E3%83%AA%E3%82%B1%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3-%E6%96%B0%E3%81%97%E3%81%84%E3%82%B5%E3%83%BC%E3%83%90%E3%82%B5%E3%82%A4%E3%83%89%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0-%E9%95%B7%E6%BE%A4-%E5%A4%AA%E9%83%8E/dp/4865940669/ref=tmm_pap_swatch_0?_encoding=UTF8&qid=&sr=)