Java
Lombok
spring-boot

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

More than 1 year has passed since last update.

昨今のWebアプリケーションといえばREST

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

Spring Boot + Lombok

Spring Boot を使うと、簡単にWebアプリケーションを作成することができます。
また、Lombokを使うと、冗長なコードをJavaから排除することができます。
今回は、この2つを組み合わせることで、恐ろしく簡単にREST APIを作成します。
サンプルとして、TODOをRESTできるAPIを作成します。

手順

  1. SPRING INITIALIZR でアプリケーションのベースを作成する。
    image.png
    Selected Dependenciesには、
    JPA, H2, Lombok, Rest Repositories
    を指定します。
    Generate Projectを押すとzipファイルがダウンロードできるので、解凍します。

  2. データ定義とアプリケーションの作成
    データ構造を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の型構造にするためのクラスを定義します。

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を使いこなしてください。

サンプルコードはこちらにおいておきます。

現場からは以上です。