Spring Boot + MySQLでシンプルなWeb REST APIサーバを実装する

# Outline
Spring BootをつかったREST APIサーバを0から実装する。
[YutaKase6/spring-api-sample](https://github.com/YutaKase6/spring-api-sample)


# Goal
## Entry Point
以下のようなエントリポイントを持ったAPIをつくる。  
<img width="512" src="https://qiita-image-store.s3.amazonaws.com/0/90526/cae5aca6-51f8-4595-1b7a-3badfecf39f5.png">

## table
| 物理名 | 論理名 |
| :--: | :--: |
| id | ユーザID | 
| value | ユーザ情報 |

# Steps...
## まずはプロジェクトの作成
[Spring BootプロジェクトをIntelliJ(Spring Initializr)を利用して作成する - Qiita](https://qiita.com/YutaKase6/items/1e7f1115580d6faad0f3)
![ij.jpeg](https://qiita-image-store.s3.amazonaws.com/0/90526/aa0ab6a0-dbad-6551-0232-01a72bbfabaf.jpeg)

## Gradleについて確認
[Gradleについてちょこっと調べて、Spring Initializrで生成されたbuild.gradleを読む - Qiita](https://qiita.com/YutaKase6/items/5c4595649995693c1226)
<img width=512 src="https://qiita-image-store.s3.amazonaws.com/0/90526/821fcc2a-e645-a895-ec7c-ab515b6399f8.png">

## 実装の前に、アーキテクチャ、クラス設計を考える
[Spring Bootで実装するWebAPIのアーキテクチャを考える - Qiita](https://qiita.com/YutaKase6/items/7d88fa23f81366905270)
<img width=512 src="https://qiita-image-store.s3.amazonaws.com/0/90526/d62889c1-9fe9-23a5-0060-47059df7909f.png">

## 実装していく
[Spring BootとJPAでREST APIを実装する(ドメイン層編) - Qiita](https://qiita.com/YutaKase6/items/d0a606c8688c63fd9874)
[Spring BootとJPAでREST APIを実装する(インフラ層編) - Qiita](https://qiita.com/YutaKase6/items/50661538166900146eeb)
[Spring BootとJPAでREST APIを実装する(アプリケーション層編) - Qiita](https://qiita.com/YutaKase6/items/487edfa9f6e39ac2f939)

## MySQL設定
### MySQL準備
**Install & Start**

```
% brew install mysql
% mysql.server start                                                                  
```

**テーブル作成**

```sql
CREATE TABLE test_users (
  id VARCHAR(18) PRIMARY KEY
  , value TEXT DEFAULT NULL
  , created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
  , updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8
;
```

```
mysql> desc test_users;
+------------+-------------+------+-----+-------------------+-----------------------------+
| Field      | Type        | Null | Key | Default           | Extra                       |
+------------+-------------+------+-----+-------------------+-----------------------------+
| id         | varchar(18) | NO   | PRI | NULL              |                             |
| value      | text        | YES  |     | NULL              |                             |
| created_at | timestamp   | NO   |     | CURRENT_TIMESTAMP |                             |
| updated_at | timestamp   | NO   |     | CURRENT_TIMESTAMP | on update CURRENT_TIMESTAMP |
+------------+-------------+------+-----+-------------------+-----------------------------+
4 rows in set (0.00 sec)
```

### Spring Boot設定
設定は`src/main/resources/application.properties`に書く。
ymlでも書けるのでymlで書く。
まずはリネーム。
<img width="354" src="https://qiita-image-store.s3.amazonaws.com/0/90526/f7967803-3f6c-5da0-1e23-0640c2d8bbe6.png">

MySQLとの接続設定を書く。

```application.yml
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/<SchemaName>
    username: root
    password:

  jpa:
    hibernate:
      ddl-auto: none
```

## 動作確認
### 実行
**IntelliJから実行(その1)**
mainメソッドの左の再生ボタンを押すことで実行できる。
<img width="512" src="https://qiita-image-store.s3.amazonaws.com/0/90526/331557c4-b372-5b61-fc58-cd52162930af.png">

**IntelliJから実行(その2)**
右上のプルダウンからmainクラスを選択し、右の再生ボタンで実行できる。
<img width="512" src="https://qiita-image-store.s3.amazonaws.com/0/90526/63f55172-4edd-a8ce-3eee-f453ac06132a.png">

**Gradleから実行**

```
% ./gradlew bootRun
```

**javaから実行**

```
% ./gradlew build
% java -jar build/libs/spring-api-0.0.1-SNAPSHOT.jar
```

### 正常確認

- 登録

```
% curl -X POST "http://localhost:8080/v1/users" -H "Content-Type: application/json" -d "{ \"id\": \"id\", \"value\": \"value\"}" -s -w '\nstatus code: %{http_code}\n'

{"id":"id","value":"value"}
status code: 201
```

- 参照

```
% curl "http://localhost:8080/v1/users/id" -s -w '\nstatus code: %{http_code}\n'

{"id":"id","value":"value"}
status code: 200
```

- 削除

```
% curl -X DELETE "http://localhost:8080/v1/users/id" -s -w '\nstatus code: %{http_code}\n'


status code: 204
```

### 異常確認(Spring Bootのデフォルト)

- 存在しないユーザ

```
% curl "http://localhost:8080/v1/users/hoge" -s -w '\nstatus code: %{http_code}\n'

{"timestamp":"2018-07-20T12:11:51.131+0000","status":500,"error":"Internal Server Error","message":"No message available","path":"/v1/users/hoge"}
status code: 500
```

- 定義していないメソッド

```
% curl "http://localhost:8080/v1/users" -s -w '\nstatus code: %{http_code}\n'

{"timestamp":"2018-07-20T12:14:08.013+0000","status":405,"error":"Method Not Allowed","message":"Request method 'GET' not supported","path":"/v1/users"}
status code: 405
```

- 定義していないパス

```
% curl "http://localhost:8080/v1/user" -s -w '\nstatus code: %{http_code}\n'

{"timestamp":"2018-07-20T12:14:14.668+0000","status":404,"error":"Not Found","message":"No message available","path":"/v1/user"}
status code: 404
```
他にもいろいろある。

## 異常時のレスポンスをカスタムする
[Spring Bootで作成したREST APIのエラーレスポンスをカスタムする - Qiita](https://qiita.com/YutaKase6/items/434d36901e3a3360e9b0)

## Swaggerを導入する
[Spring BootのREST APIにSwaggerを導入する - Qiita](https://qiita.com/YutaKase6/items/52ea048c5352c77330eb)
<img width=512 src="https://swagger.io/swagger/media/assets/images/swagger_logo.svg">


## 単体テストを作成する
[Spring Boot + JUnitで単体テストをやる - Qiita](https://qiita.com/YutaKase6/items/a8ef5e3954ff46283a7d)
<img src="https://junit.org/junit4/images/junit-logo.png">

[Spring Boot + JUnit + Mockitoで単体テストをやる - Qiita](https://qiita.com/YutaKase6/items/1f3ca15900b5146351de)
<img width=512 src="https://github.com/mockito/mockito.github.io/raw/master/img/logo%402x.png">

## 機能テストを作成する
[Spring Boot + JUnit + h2でスタンドアローンな機能テストをやる - Qiita](https://qiita.com/YutaKase6/items/4241e0573fc4e104ea1c)
<img src="http://www.h2database.com/html/images/h2-logo-2.png">

## ロガーを導入する
[Spring AOPを利用してSpring Boot アプリケーションのログを落とす - Qiita](https://qiita.com/YutaKase6/items/cf8a5cb64743ee5de17f)
![](https://www.slf4j.org/images/logos/slf4j-logo.jpg)

## カバレッジを計測する
TBA...