Spring Data RESTでMySQLにアクセス

# はじめに

Spring Data RESTを使って、MySQLにアクセスする最も簡単なREST APIを作成します。

# 参考

Accessing JPA Data with REST
https://spring.io/guides/gs/accessing-data-rest/

# 前提条件

下の記事の後の状態を前提にしています
[Spring BootとAngularUI UI-Routerを使ってみる](http://qiita.com/quwahara/items/658078100c2597cab30c)

MySQLを利用できること

# 環境

JVM:          1.8.0_45 (Oracle Corporation 25.45-b02)
OS:           Mac OS X 10.11.3 x86_64
MySQL:        Server version:		5.5.28 Source distribution

## Spring Tool Suite

Version: 3.7.3.RELEASE
Build Id: 201602250940
Platform: Eclipse Mars.2 (4.5.2)
(こちらから入れました https://spring.io/tools/sts/all)

Buildship: Eclipse Plug-ins for Gradle	1.0.13.v20160411-1723
(Help -> Eclipse marketplaceから入れました)

# 手順

## 依存するLibraryを追加する

Spring Data JPA、Spring Data REST、MySQL Connector/Jを使えるように、ビルドスクリプトの依存物として、// Addを追記します。

```groovy:build.gradle
dependencies {
	compile 'org.webjars:jquery:2.2.3'
	compile 'org.webjars:angularjs:1.5.3'
	compile 'org.webjars:angular-ui-router:0.2.18'
	compile 'org.webjars:bootstrap:3.3.6'

	// Add
	compile('org.springframework.boot:spring-boot-starter-data-jpa')
	// Add
	compile('org.springframework.boot:spring-boot-starter-data-rest')
	compile('org.springframework.boot:spring-boot-starter-web')
	testCompile('org.springframework.boot:spring-boot-starter-test')

	// Add
	compile('mysql:mysql-connector-java')
}
```

追記を反映するために、Package ExplorerでSSP37(プロジェクトルート)を選び右クリック、
Gradle -> Refresh Gradle Project
をクリックします。
Package ExplorerのProject and External Dependenciesに、追記したJarあるか確認します。

### 参考

Spring IO Platform Reference Guide
Appendix A. Dependency versions
http://docs.spring.io/platform/docs/2.0.3.RELEASE/reference/htmlsingle/#appendix
WebJars http://www.webjars.org/

## 設定する
JPAやMySQLを使うのに、必要最小限と思われる設定をします。

```properties:src/main/resources/application.properties
spring.data.rest.basePath=/api
spring.datasource.url=jdbc:mysql://localhost/test
spring.datasource.username=user
spring.datasource.password=password
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.jpa.database=MYSQL
spring.jpa.hibernate.ddl-auto=update
```

### spring.data.rest.basePath
REST APIのルートの設定です。変えたほうが分かり易いと思い変えました。

#### 参考
Spring Data REST - Reference Documentation
4.6.1. Changing the base URI
http://docs.spring.io/spring-data/rest/docs/2.4.4.RELEASE/reference/html/#getting-started.basic-settings

### spring.datasource.\*
MySQLへの接続文字列です。ご自分の環境に合わせて値を指定して下さい。
hibernateが自動で、テーブルの作成や項目の変更、破棄をしてくれたりするので、それらが行える権限を持つ、MySQLのユーザーを指定して下さい。

#### 参考
Spring Boot Reference Guide
29.1.2 Connection to a production database
https://docs.spring.io/spring-boot/docs/1.3.3.RELEASE/reference/htmlsingle/#boot-features-connect-to-production-database

### spring.jpa.database=MYSQL
自動で生成されるSQLやDDLが、MySQL向けになるように指示します。

### spring.jpa.hibernate.ddl-auto=update
Entityになるクラスを作ると、自動でテーブルの作成、項目変更をしてくれるようにします。



#### 参考
Spring Boot Reference Guide
73.5 Configure JPA properties
https://docs.spring.io/spring-boot/docs/1.3.3.RELEASE/reference/htmlsingle/#howto-configure-jpa-properties

Hibernate Reference Documentation
3.4. Optional configuration properties
Table 3.7. Miscellaneous Properties
> hibernate.hbm2ddl.auto
> Automatically validates or exports schema DDL to the database when the SessionFactory is created. With create-drop, the database schema will be dropped when the SessionFactory is closed explicitly.
e.g. validate | update | create | create-drop

http://docs.jboss.org/hibernate/orm/4.3/manual/en-US/html_single/#configuration-optional

## Entityを作る

簡単なEntityを作ってみます。
綴り(spelling)と好みか(favorite)を項目に持つ、単語(word)というEntityを作ってみました。

```java:src/main/java/com/example/domain/Word.java
package com.example.domain;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

@Entity
public class Word {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    @Column(nullable = false)
    private String spelling;

    @Column(nullable = false)
    private Boolean favorite;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getSpelling() {
        return spelling;
    }

    public void setSpelling(String spelling) {
        this.spelling = spelling;
    }

    public Boolean getFavorite() {
        return favorite;
    }

    public void setFavorite(Boolean favorite) {
        this.favorite = favorite;
    }
}
```

## Repositoryを作る

先ほどのWordを操作するRepositoryを作ります。
Spring Data RESTは、このようなRepositoryを作ると、そのEntityをCRUD操作できるAPIを自動で公開してくれます。

```java:src/main/java/com/example/domain/WordRepository.java
package com.example.domain;

import java.util.List;

import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.data.repository.query.Param;

public interface WordRepository extends PagingAndSortingRepository<Word, Long> {
    
    List<Word> findBySpellingLikeOrderBySpellingAsc(@Param("spelling") String spelling);

}
```

## APIを使ってみる

それでは[cURL](https://ja.wikipedia.org/wiki/CURL)で、APIを使ってみましょう。
まずはWebアプリケーションを[起動](http://qiita.com/quwahara/items/e3eac70425cee1b70454#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%E3%82%92%E8%B5%B7%E5%8B%95%E3%81%99%E3%82%8B)します。
Spring Data RESTが公開するAPIのPathは、設定したAPIのルートと、Repositoryを作ったEntityの名前を小文字にして、複数形のsを付け、連結したものになります。
今回は、APIのルートを/apiに設定し、EntityのWordはwordsになるので、Path名は/api/wordsとなります。
そのPathにcurlでアクセスします。

```bash
$ curl http://localhost:8080/api/words
```
下のような応答がありました。

```json
{
  "_embedded" : {
    "words" : [ ]
  },
  "_links" : {
    "self" : {
      "href" : "http://localhost:8080/api/words"
    },
    "profile" : {
      "href" : "http://localhost:8080/api/profile/words"
    },
    "search" : {
      "href" : "http://localhost:8080/api/words/search"
    }
  },
  "page" : {
    "size" : 20,
    "totalElements" : 0,
    "totalPages" : 0,
    "number" : 0
  }
}
```

### とりあえずレコードを一件登録してみます。

-dで指定するJSON部分に、idを除くEntityの全ての項目を指定し、先ほどのPathへPOSTすると登録できます。

```bash
$ curl -X POST -H "Content-Type:application/json" -d '{ "spelling": "APPLE", "favorite": true }' http://localhost:8080/api/words
```

id=13で登録できたようです。13は環境によって変わるので読み替えて下さい。

```json
{
  "spelling" : "APPLE",
  "favorite" : true,
  "_links" : {
    "self" : {
      "href" : "http://localhost:8080/api/words/13"
    },
    "word" : {
      "href" : "http://localhost:8080/api/words/13"
    }
  }
}
```

もう一度そのレコードを取得してみましょう。
Pathにidを連結すると、そのレコードにアクセスできます。

```bash
$ curl http://localhost:8080/api/words/13
```

```json
{
  "spelling" : "APPLE",
  "favorite" : true,
  "_links" : {
    "self" : {
      "href" : "http://localhost:8080/api/words/13"
    },
    "word" : {
      "href" : "http://localhost:8080/api/words/13"
    }
  }
}
```

### レコードを更新してみます。

-dで指定するJSON部分に、idを除くEntityの全ての項目を指定し、idを指定したPathへPUTすると更新できます。
下ではAPPLEからappleへ更新しました。

```bash
$ curl -X PUT -H "Content-Type:application/json" -d '{ "spelling": "apple", "favorite": false }' http://localhost:8080/api/words/13
{
  "spelling" : "apple",
  "favorite" : false,
  "_links" : {
    "self" : {
      "href" : "http://localhost:8080/api/words/13"
    },
    "word" : {
      "href" : "http://localhost:8080/api/words/13"
    }
  }
}
```

### レコードを削除してみます。

idを連結したPathへDELETEすると、削除できます。

```bash
$ curl -X DELETE http://localhost:8080/api/words/13
```

### 検索してみます。

とりあえず検索するために、レコードを3件登録します。

```bash
curl -X POST -H "Content-Type:application/json" -d '{ "spelling": "apple", "favorite": true }' http://localhost:8080/api/words
curl -X POST -H "Content-Type:application/json" -d '{ "spelling": "apricot", "favorite": true }' http://localhost:8080/api/words
curl -X POST -H "Content-Type:application/json" -d '{ "spelling": "pineapple", "favorite": false }' http://localhost:8080/api/words
```

検索してみます。
検索のPathはsearchにRepositoryのメソッド名を連結します。
検索キーは、クエリ文字列に連結します。
SQLのLike条件のワイルドカード文字に当たる%は%25にエンコードして指定します。
これでappleで終わるspellingのレコードを検索しています。

```bash
$ curl http://localhost:8080/api/words/search/findBySpellingLikeOrderBySpellingAsc?spelling=%25apple
{
  "_embedded" : {
    "words" : [ {
      "spelling" : "apple",
      "favorite" : true,
      "_links" : {
        "self" : {
          "href" : "http://localhost:8080/api/words/14"
        },
        "word" : {
          "href" : "http://localhost:8080/api/words/14"
        }
      }
    }, {
      "spelling" : "pineapple",
      "favorite" : false,
      "_links" : {
        "self" : {
          "href" : "http://localhost:8080/api/words/16"
        },
        "word" : {
          "href" : "http://localhost:8080/api/words/16"
        }
      }
    } ]
  },
  "_links" : {
    "self" : {
      "href" : "http://localhost:8080/api/words/search/findBySpellingLikeOrderBySpellingAsc?spelling=%25apple"
    }
  }
}
```

# 参考

Sample Repository
https://github.com/quwahara/SSP37/tree/600-rest