Spring JPA Data with REST と Lombokで恐ろしく簡単にREST APIを作成する。

#昨今のWebアプリケーションといえばREST
昨今、Webアプリケーションといえば、HTML+JavaScriptによるクライアント層ブラウザ上で動作し、サーバはREST APIでデータを配信するアーキテクチャを取ります。
本記事ではサーバのREST APIをJavaで恐ろしく簡単に作れるぞ、ということをご紹介します。

#Spring Boot + Lombok
[Spring Boot](https://projects.spring.io/spring-boot/) を使うと、簡単にWebアプリケーションを作成することができます。
また、Lombokを使うと、冗長なコードをJavaから排除することができます。
今回は、この２つを組み合わせることで、恐ろしく簡単にREST APIを作成します。
サンプルとして、TODOをRESTできるAPIを作成します。

#手順
1. SPRING INITIALIZR でアプリケーションのベースを作成する。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/25176/501248c3-2dc8-2586-e319-98f31ef77a18.png)
Selected Dependenciesには、
JPA, H2, Lombok, Rest Repositories
を指定します。
Generate Projectを押すとzipファイルがダウンロードできるので、解凍します。


2. データ定義とアプリケーションの作成
データ構造をJavaのクラスとして作成します。

```java
package com.ukiuni.easyrest.entity;

import java.util.Date;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;

import lombok.Data;

@Data
@Entity
public class Todo {
	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	private long id;

	private String title;
	private String description;
	private boolean done;
	@Temporal(TemporalType.TIMESTAMP)
	private Date deadline;
}
```
キモはクラスに付いているアノテーションの@Dataです。Lombokが定義するアノテーションで、アクセサメソッドを自動的に付与してくれます。これによりプログラマは冗長なgetter/setterを記述することなく、フィールドによるデータ定義に集中することができます。

このデータ構造をそのままREST　APIのCRUDの型構造にするためのクラスを定義します。

```java
package com.ukiuni.easyrest.repository;

import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;

import com.ukiuni.easyrest.entity.Todo;

@RepositoryRestResource(collectionResourceRel = "todos", path = "todos")
public interface TodoRepository extends PagingAndSortingRepository<Todo, Long> {
}
```
インターフェースを定義するのみです。中身の実装は不要です。

以上でソースコードの記述は終わりです。簡単。

# 起動と操作
起動します。アプリケーションのディレクトリで

```
gradle bootRun
```

で起動します。

操作してみましょう。
curlコマンドを使用します。

```
$ curl -i http://localhost:8080/todos
HTTP/1.1 200
Content-Type: application/hal+json;charset=UTF-8
Transfer-Encoding: chunked
Date: Thu, 16 Nov 2017 11:47:24 GMT

{
  "_embedded" : {
    "todos" : [ ]
  },
  "_links" : {
    "self" : {
      "href" : "http://localhost:8080/todos{?page,size,sort}",
      "templated" : true
    },
    "profile" : {
      "href" : "http://localhost:8080/profile/todos"
    }
  },
  "page" : {
    "size" : 20,
    "totalElements" : 0,
    "totalPages" : 0,
    "number" : 0
  }
}
```
"todos": [　]　と、空データが取得できているのがわかります。
さて、Todoを一件作成してみます。curlコマンドを利用します。

```
$　curl -i -X POST -H "Content-Type:application/json" -d "{  \"title\" : \"アドベントカレンダー\",  \"description\" : \"記事書かなきゃ。\", \"deadline\":\"2017-12-21T07:00:00.000Z\" }" http://localhost:8080/todos
{
  "title" : "アドベントカレンダー",
  "description" : "記事書かなきゃ。",
  "done" : false,
  "deadline" : "2017-12-21T07:00:00.000+0000",
  "_links" : {
    "self" : {
      "href" : "http://localhost:8080/todos/1"
    },
    "todo" : {
      "href" : "http://localhost:8080/todos/1"
    }
  }
}
```
1番が作成されたようです。確認してみます。

```
$ curl -i http://localhost:8080/todos
HTTP/1.1 200
Content-Type: application/hal+json;charset=UTF-8
Transfer-Encoding: chunked
Date: Thu, 16 Nov 2017 11:50:57 GMT

{
  "_embedded" : {
    "todos" : [ {
      "title" : "アドベントカレンダー",
      "description" : "記事書かなきゃ。",
      "done" : false,
      "deadline" : "2017-12-21T07:00:00.000+0000",
      "_links" : {
        "self" : {
          "href" : "http://localhost:8080/todos/1"
        },
        "todo" : {
          "href" : "http://localhost:8080/todos/1"
        }
      }
    } ]
  },
  "_links" : {
    "self" : {
      "href" : "http://localhost:8080/todos{?page,size,sort}",
      "templated" : true
    },
    "profile" : {
      "href" : "http://localhost:8080/profile/todos"
    }
  },
  "page" : {
    "size" : 20,
    "totalElements" : 1,
    "totalPages" : 1,
    "number" : 0
  }
}
```
作成したものが取得できてますね。
PUTでUPDATEしてみます。

```
$curl -i -X PUT -H "Content-Type:application/json" -d "{  \"title\" : \"アドベントカレンダー\",  \"description\" : \"記事書かなきゃ。頑張ろう。\", \"deadline\":\"2017-12-21T07:00:00.000Z\" }" http://localhost:8080/todos/1
HTTP/1.1 200
Location: http://localhost:8080/todos/1
Content-Type: application/hal+json;charset=UTF-8
Transfer-Encoding: chunked
Date: Thu, 16 Nov 2017 11:43:30 GMT

{
  "title" : "アドベントカレンダー",
  "description" : "記事書かなきゃ。頑張ろう。",
  "done" : false,
  "deadline" : "2017-12-21T07:00:00.000+0000",
  "_links" : {
    "self" : {
      "href" : "http://localhost:8080/todos/1"
    },
    "todo" : {
      "href" : "http://localhost:8080/todos/1"
    }
  }
}
```

確認してみます。

```
$ curl -i http://localhost:8080/todos
HTTP/1.1 200
Content-Type: application/hal+json;charset=UTF-8
Transfer-Encoding: chunked
Date: Thu, 16 Nov 2017 11:51:55 GMT

{
  "_embedded" : {
    "todos" : [ {
      "title" : "アドベントカレンダー",
      "description" : "記事書かなきゃ。頑張ろう。",
      "done" : false,
      "deadline" : "2017-12-21T07:00:00.000+0000",
      "_links" : {
        "self" : {
          "href" : "http://localhost:8080/todos/1"
        },
        "todo" : {
          "href" : "http://localhost:8080/todos/1"
        }
      }
    } ]
  },
  "_links" : {
    "self" : {
      "href" : "http://localhost:8080/todos{?page,size,sort}",
      "templated" : true
    },
    "profile" : {
      "href" : "http://localhost:8080/profile/todos"
    }
  },
  "page" : {
    "size" : 20,
    "totalElements" : 1,
    "totalPages" : 1,
    "number" : 0
  }
}
```

アップデートされてますね。

最後、Deleteします。

```
$ curl -i -X DELETE http://localhost:8080/todos/1
HTTP/1.1 204
Date: Thu, 16 Nov 2017 11:45:45 GMT
```

消えたことを確認します。

```
$ curl -i http://localhost:8080/todos
HTTP/1.1 200
Content-Type: application/hal+json;charset=UTF-8
Transfer-Encoding: chunked
Date: Thu, 16 Nov 2017 11:47:24 GMT

{
  "_embedded" : {
    "todos" : [ ]
  },
  "_links" : {
    "self" : {
      "href" : "http://localhost:8080/todos{?page,size,sort}",
      "templated" : true
    },
    "profile" : {
      "href" : "http://localhost:8080/profile/todos"
    }
  },
  "page" : {
    "size" : 20,
    "totalElements" : 0,
    "totalPages" : 0,
    "number" : 0
  }
}
```

 "todos" : [ ]　消えてますね。

# どうです？恐ろしく簡単でしょう？
データ構造と公開するためのRepositoryクラスを作成するだけでREST　APIを作成することができました。
Javaの型定義の強さとアノテーション機能を使うことでこんなに簡単にREST APIを作成することができます。
どうですか？最近毛嫌いされがちなJavaですが、見直しました？
みなさんもエレガントにJavaを使いこなしてください。

サンプルコードは[こちら](https://github.com/ukiuni/easyrest)においておきます。

現場からは以上です。