mmts1007’s diary

プログラミング関連の技術系ブログです。

Java Spring Boot その5

前回の続きで POST, PUT, DELETE メソッドを作成をします。

ソース

POST, PUT, DELETE を追加したソースは下記の通りです。
また、モックデータの作成方法を変更しました。

package hello;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.IntStream;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("api/tasks")
@EnableAutoConfiguration
public class RestSampleController {

    static class Task {
        public Task() {
        }

        public Task(Integer id, String context) {
            this.id = id;
            this.context = context;
        }

        public Integer id;
        public String context;
    }

    static Map<Integer, Task> tasks = new HashMap<>();

    @RequestMapping(method = RequestMethod.GET)
    List<Task> getTasks() {
        // GET api/tasks で実行されるメソッド
        return new ArrayList<>(tasks.values());
    }

    @RequestMapping(value = "{id}", method = RequestMethod.GET)
    Task getTask(@PathVariable Integer id) {
        // GET api/tasks/{id} で実行されるメソッド
        return tasks.get(id);
    }

    @RequestMapping(method = RequestMethod.POST)
    @ResponseStatus(HttpStatus.CREATED)
    Task createTask(@RequestBody Task task) {
        // POST api/tasks で実行されるメソッド
        int nextIndex = tasks.keySet().stream().max(Comparator.naturalOrder()).get() + 1;
        task.id = nextIndex;
        tasks.put(nextIndex, task);
        return task;
    }

    @RequestMapping(value = "{id}", method = RequestMethod.PUT)
    Task updateTask(@PathVariable Integer id, @RequestBody Task task) {
        // PUT api/tasks/{id} で実行されるメソッド
        Task targetTask = tasks.get(id);
        if (targetTask == null) {
            return null;
        }
        targetTask.context = task.context;
        tasks.put(id, targetTask);
        return targetTask;
    }

    @RequestMapping(value = "{id}", method = RequestMethod.DELETE)
    @ResponseStatus(HttpStatus.NO_CONTENT)
    void deleteTask(@PathVariable Integer id) {
        // DELETE api/tasks で実行されるメソッド
        tasks.remove(id);
    }

    public static void main(String[] args) {
        // モックデータ作成
        IntStream.range(0, 3).forEach(index -> tasks.put(index, new Task(index, String.format("sample%d", index))));
        SpringApplication.run(RestSampleController.class, args);
    }
}

解説

前回解説した通り、@RequestMapping で POST, PUT, DELETE 各メソッドマッピングする Javaメソッドを作成しました。

@RequestMapping

今回 @RequestMapping(value = "{id}", method = RequestMethod.GET) のように value 属性が登場しました。
value は相対パスを指定することができます。なので getTask メソッドは GET "api/tasks/{id}" とマッピングされます。 また value に指定した {id} はメソッドの引数で取得することができます。
取得するためには @PathVariable アノテーションを付与した 変数を定義します。

@ResponseStatus

ResponseStatus アノテーションは名前の通りですが、レスポンスのステータスを指定することができます。
アノテーションに指定できる値は HttpStatus 型の値です。
HttpStatus は enum となっているので、HttpStatus.CREATED など視覚的にわかりやすい形で指定できます。

@RequestBody

メソッドの引数に指定されている RequestBody アノテーションですが、
こちらも名前の通りリクエストボディの値をマッピングするためのアノテーションです。
今回、リクエストボディに設定される JSON を Task 型の値にマッピングするために使用しています。

結果

メソッドを実行した結果をまとめました。

GET api/tasks

$ curl -v http://localhost:8080/api/tasks -X GET
*   Trying ::1...
* Connected to localhost (::1) port 8080 (#0)
> GET /api/tasks HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.43.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Server: Apache-Coyote/1.1
< Content-Type: application/json;charset=UTF-8
< Transfer-Encoding: chunked
< Date: Sat, 10 Oct 2015 23:40:31 GMT
<
* Connection #0 to host localhost left intact
[{"id":0,"context":"sample0"},{"id":1,"context":"sample1"},{"id":2,"context":"sample2"}]

全てのタスクが返却されています。

GET api/tasks/{id}

$ curl -v http://localhost:8080/api/tasks/2 -X GET
*   Trying ::1...
* Connected to localhost (::1) port 8080 (#0)
> GET /api/tasks/2 HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.43.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Server: Apache-Coyote/1.1
< Content-Type: application/json;charset=UTF-8
< Transfer-Encoding: chunked
< Date: Sat, 10 Oct 2015 23:41:31 GMT
<
* Connection #0 to host localhost left intact
{"id":2,"context":"sample2"}

id で指定したデータが返却されています。

POST api/tasks

$ curl -v http://localhost:8080/api/tasks -X POST -H "Content-Type: application/json" -d "{\"context\" : \"create\"}"
*   Trying ::1...
* Connected to localhost (::1) port 8080 (#0)
> POST /api/tasks HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.43.0
> Accept: */*
> Content-Type: application/json
> Content-Length: 22
>
* upload completely sent off: 22 out of 22 bytes
< HTTP/1.1 201 Created
< Server: Apache-Coyote/1.1
< Content-Type: application/json;charset=UTF-8
< Transfer-Encoding: chunked
< Date: Sat, 10 Oct 2015 23:42:14 GMT
<
* Connection #0 to host localhost left intact
{"id":3,"context":"create"}

作成したデータが返却されています。
@ResponseStatus(HttpStatus.CREATED) を指定したのでレスポンスステータスが HTTP/1.1 201 Created に変化しています。

PUT api/tasks/{id}

$ curl -v http://localhost:8080/api/tasks/1 -X PUT -H "Content-Type: application/json" -d "{\"context\" : \"update\"}"
*   Trying ::1...
* Connected to localhost (::1) port 8080 (#0)
> PUT /api/tasks/1 HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.43.0
> Accept: */*
> Content-Type: application/json
> Content-Length: 22
>
* upload completely sent off: 22 out of 22 bytes
< HTTP/1.1 200 OK
< Server: Apache-Coyote/1.1
< Content-Type: application/json;charset=UTF-8
< Transfer-Encoding: chunked
< Date: Sat, 10 Oct 2015 23:42:40 GMT
<
* Connection #0 to host localhost left intact
{"id":1,"context":"update"}

id で指定した要素のデータが更新されています。

DELETE api/tasks/{id}

$ curl -v http://localhost:8080/api/tasks/1 -X DELETE
*   Trying ::1...
* Connected to localhost (::1) port 8080 (#0)
> DELETE /api/tasks/1 HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.43.0
> Accept: */*
>
< HTTP/1.1 204 No Content
< Server: Apache-Coyote/1.1
< Date: Sat, 10 Oct 2015 23:42:56 GMT
<
* Connection #0 to host localhost left intact

@ResponseStatus(HttpStatus.NO_CONTENT) を指定したので HTTP/1.1 204 No Content となり レスポンスもありません。

以上で REST API の作成は完了です。
次回はモック部分のデータを DB とやりとりするよう修正したいと思います。