msksgm’s blog

msksgm’s blog

Webエンジニアです.日々の勉強,読書,映画観賞,美術観賞の記録を載せます.

SpringBootでwebAPIサーバーを作るハンズオン(Java)

最近,SpringBoot を学んだので CRUD ができる Web API サーバーを作りたいと思います. Qiitaにも投稿してみました. repository と service はインタフェースと実行クラスをわけています.
最終的なソースコードこちらディレクトリ構成は以下のようになる.

.
├── HELP.md
├── demo.iml
├── mvnw
├── mvnw.cmd
├── pom.xml
├── src
│   ├── main
│   │   ├── java
│   │   │   └── com
│   │   │       └── example
│   │   │           └── demo
│   │   │               ├── DemoApplication.java
│   │   │               ├── configuration
│   │   │               │   ├── DataSourceConfiguration.java
│   │   │               │   └── DataSourceConfigurationProperties.java
│   │   │               ├── controller
│   │   │               │   └── MovieRestController.java
│   │   │               ├── domain
│   │   │               │   ├── Director.java
│   │   │               │   ├── Movie.java
│   │   │               │   └── MovieList.java
│   │   │               ├── repository
│   │   │               │   ├── MovieRepository.java
│   │   │               │   ├── MovieRepositoryImpl.java
│   │   │               │   └── mybatis
│   │   │               │       ├── MovieMapper.java
│   │   │               │       └── MovieMapper.xml
│   │   │               └── service
│   │   │                   ├── MovieService.java
│   │   │                   └── MovieServiceImpl.java
│   │   └── resources
│   │       ├── application.yml
│   │       ├── static
│   │       └── templates
│   └── test
│       └── java
│           └── com
│               └── example
│                   └── demo
│                       └── DemoApplicationTests.java
└── target
    ├── classes
    │   ├── application.yml
    │   └── com
    │       └── example
    │           └── demo
    │               ├── DemoApplication.class
    │               ├── configuration
    │               │   ├── DataSourceConfiguration.class
    │               │   └── DataSourceConfigurationProperties.class
    │               ├── controller
    │               │   └── MovieRestController.class
    │               ├── domain
    │               │   ├── Director.class
    │               │   ├── Movie.class
    │               │   └── MovieList.class
    │               ├── repository
    │               │   ├── MovieRepository.class
    │               │   ├── MovieRepositoryImpl.class
    │               │   └── mybatis
    │               │       ├── MovieMapper.class
    │               │       └── MovieMapper.xml
    │               └── service
    │                   ├── MovieService.class
    │                   └── MovieServiceImpl.class
    ├── generated-sources
    │   └── annotations
    ├── generated-test-sources
    │   └── test-annotations
    └── test-classes
        └── com
            └── example
                └── demo
                    └── DemoApplicationTests.class

39 directories, 35 files

前準備

環境

フレームワーク作成

Spring Initializr を使用して demo.zip をダウンロードして適当な場所で解凍する
設定は以下

  • Project
  • Language
  • Spring Boot
    • 2.4.5
  • Project Metadata
    • Java 8
    • それ以外はデフォルトのまま
  • Dependencies
    • Spring Web
    • MySQL Driver
    • MyBatis Framework

MySQL の準備

以下の構成で作成

認証関係

  • ユーザー
    • root
  • パスワード
    • password

DB 関係

新しい DB を作成

CREATE DATABASE moviedb;

moviedb を選択

USE moviedb;

外部キーを持った table を作成

director table を作成

CREATE TABLE director
(director_id char(10) PRIMARY KEY ,
director_name varchar(20));

movie table を作成

CREATE TABLE movies
(movie_id CHAR(10) PRIMARY KEY,
movie_name VARCHAR(50),
director_id CHAR(10),
CONSTRAINT director_id_fk FOREIGN KEY (director_id) REFERENCES director(director_id));

tabel に値を挿入

director に挿入

INSERT INTO director VALUES('D01', '新海誠');
INSERT INTO director VALUES('D02', '藤井道人');
INSERT INTO director VALUES('D03', 'クリストファー・ノーラン');

movie に挿入

INSERT INTO movies VALUES('M01', '君の名は。', 'D01');
INSERT INTO movies VALUES('M02', '天気の子', 'D01');
INSERT INTO movies VALUES('M03', '言の葉の庭', 'D01');
INSERT INTO movies VALUES('M04', '新聞記者', 'D02');
INSERT INTO movies VALUES('M05', 'デイアンドナイト', 'D02');
INSERT INTO movies VALUES('M06', 'ダークナイト', 'D03');
INSERT INTO movies VALUES('M07', 'インセプション', 'D03');
INSERT INTO movies VALUES('M07', 'インセプション', 'D03');

手順

1. プロジェクトの新規作成

  1. Intellij -> ファイル -> 新規 -> 既存のソースからプロジェクト -> demo を選択して Open.
  2. "既存プロジェクトから作成する"をチェックして完了を押す.

2. pom.xml を編集

dependencies タグに以下を追加.

<dependency>
   <groupId>org.apache.commons</groupId>
   <artifactId>commons-dbcp2</artifactId>
</dependency>

また build タグに resources タグを追加.

<resources>
   <resource>
      <directory>src/main/java</directory>
      <includes>
         <include>**/*.xml</include>
      </includes>
   </resource>
   <resource>
      <directory>src/main/resources</directory>
   </resource>
</resources>

追加後,pom.xml を右クリック->Maven->"プロジェクトの再ロード"を選択

3. application.yml を作成

demo/src/main/java/resources/application.properties の名前を変更(右クリックして"リファクタリング"を選択)し,application.yml にする. 記述する設定は

  • JDBC の接続設定
    • ドライバー
    • MySQL
    • コネクションプール
      • 初期コネクション数,アイドル時間
  • MyBatis の設定
    • mapper-locations
      • MapperXML の場所を指定

ソースコード

# JDBCの接続設定
dbcp2.jdbc:
  driver-class-name: com.mysql.jdbc.Driver
  url: jdbc:mysql://localhost:3306/moviedb?characterEncoding=UTF-8
  username: root
  password: password
  initial-size: 1
  max-idle: 3
  min-idle: 1

# mybatisの設定
mybatis:
  mapper-locations: classpath:com/example/demo/repository/mybatis/*.xml

4. domain を作成

demo/src/main/java/com/example/demo/に domain パッケージを作成する.
domain パッケージ配下に Director クラス, Movie クラス, MovieList クラスを作成する.

Director クラス

package com.example.demo.domain;

public class Director {
    private String directorId;

    private String directorName;

    public Director() {
    }

    public Director(String directorId, String directorName) {
        this.directorId = directorId;
        this.directorName = directorName;
    }

    public String getDirectorId() {
        return directorId;
    }

    public void setDirectorId(String directorId) {
        this.directorId = directorId;
    }

    public String getDirectorName() {
        return directorName;
    }

    public void setDirectorName(String directorName) {
        this.directorName = directorName;
    }
}

Movie クラス

package com.example.demo.domain;

public class Movie {
    private String movieId;

    private String movieName;

    private Director director;

    public Movie() {
    }

    public Movie(String movieId, String movieName) {
        this.movieId = movieId;
        this.movieName = movieName;
    }

    public String getMovieId() {
        return movieId;
    }

    public void setMovieId(String movieId) {
        this.movieId = movieId;
    }

    public String getMovieName() {
        return movieName;
    }

    public void setMovieName(String movieName) {
        this.movieName = movieName;
    }

    public Director getDirector() {
        return director;
    }

    public void setDirector(Director director) {
        this.director = director;
    }
}

MoviesList

package com.example.demo.domain;

import java.util.List;

public class MovieList {
    private List<Movie> movieList;

    public List<Movie> getMovieList() {
        return movieList;
    }

    public void setMovieList(List<Movie> movieList) {
        this.movieList = movieList;
    }
}

5. Repository を作成

demo/src/main/java/com/example/demo/に repository パッケージを作成する.
repository と mybatis によって,mysqljava の接続ができるようになる.

5-1 Mapper.xml を作成

repository パッケージ配下に mybatis パッケージを作成する.
mybatis パッケージ配下に MyBatis の設定ファイルである,MoviesMapper.xml を作成する.
#{}は Java から渡された変数を表示する

タグの解説

  • mapper タグ
    • namespace="Mapper のパス"を指定する
  • resultMap タグ
    • MySQL のテーブルと Java クラスのフィールドを対応付ける
      • type=""で Java のオブジェクトとの関連付け
      • id タグの property で Java のフィールドを記述し,column で MySQL の列名を記述する
    • association タグで複数のテーブルとの関連付けをおこなう
  • SQL を記述するタグ(id の意味は後述)
    • select タグ
      • CRUD の READE に該当
    • insert タグ
      • CRUD の CREATE に該当
    • update タグ
      • CRUD の UPDATE に該当
    • delete タグ - CRUD の DELETE に該当

ソースコード

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC
        "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.demo.repository.mybatis.MovieMapper">
    <resultMap id="Director" type="com.example.demo.domain.Director">
        <id property="directorId" column="DIRECTOR_ID"/>
        <result property="directorName" column="DIRECTOR_NAME"/>
    </resultMap>

    <resultMap id="Movie" type="com.example.demo.domain.Movie">
        <id property="movieId" column="MOVIE_ID"/>
        <result property="movieName" column="MOVIE_NAME"/>
        <association property="director" resultMap="Director"/>
    </resultMap>

    <select id="find" resultMap="Movie">
        SELECT M.MOVIE_ID, M.MOVIE_NAME, D.DIRECTOR_ID, D.DIRECTOR_NAME
        FROM MOVIE M INNER JOIN DIRECTOR D USING (DIRECTOR_ID)
        <where>
            <if test="movieName != null">
                M.MOVIE_NAME LIKE CONCAT('%', #{movieName}, '%')
            </if>
            <if test="directorName != null">
                AND D.DIRECTOR_NAME LIKE CONCAT('%', #{directorName}, '%')
            </if>
        </where>
        ORDER BY M.MOVIE_ID ASC
    </select>

    <select id="get" resultMap="Movie">
        SELECT M.MOVIE_ID, M.MOVIE_NAME, D.DIRECTOR_ID, D.DIRECTOR_NAME
        FROM MOVIE M INNER JOIN DIRECTOR D USING (DIRECTOR_ID)
        WHERE MOVIE_ID = #{movieId}
    </select>

    <select id="lock" resultMap="Movie">
        SELECT M.MOVIE_ID, M.MOVIE_NAME, D.DIRECTOR_ID, D.DIRECTOR_NAME
        FROM MOVIE M INNER JOIN DIRECTOR D USING (DIRECTOR_ID)
        WHERE MOVIE_ID = #{movieId}
        FOR UPDATE
    </select>

    <insert id="add" parameterType="com.example.demo.domain.Movie" keyProperty="movieId">
        <!-- selectKeyによってmovieIdを新しく設定する -->
        <selectKey keyProperty="movieId" resultType="string" order="BEFORE">
            <!-- MOVIE_IDのAUTO INCREMENTを実装 -->
            SELECT COALESCE(CONCAT('M', LPAD(RIGHT(MAX(MOVIE_ID), 2) + 1, 2, '0')), 'M01') FROM MOVIE
        </selectKey>
        INSERT INTO MOVIE (MOVIE_ID , MOVIE_NAME, DIRECTOR_ID) VALUES (#{movieId}, #{movieName}, #{director.directorId});
    </insert>

    <update id="set" parameterType="com.example.demo.domain.Movie">
        UPDATE MOVIE
        <set>
            <if test="movieName != null">
                MOVIE_NAME = #{movieName},
            </if>
            <if test="director.directorId != null">
                DIRECTOR_ID = #{director.directorId},
            </if>
        </set>
        WHERE MOVIE_ID = #{movieId}
    </update>

    <delete id="remove" parameterType="com.example.demo.domain.Movie">
        DELETE FROM MOVIE
        WHERE MOVIE_ID = #{movieId}
    </delete>
</mapper>

5-2 Mapper インタフェースを作成

mybatis パッケージ配下に MoviesMapper インタフェースを作成する. 抽象メソッドを定義する.
メソッド名は MoviesMapper.xmlSQL を記述するタグの id="" で定義した名前になっている
@Param で MoviesMapper.xml の引数との関連付けをおこなう.

package com.example.demo.repository.mybatis;

import com.example.demo.domain.Movie;
import java.util.List;
import org.apache.ibatis.annotations.Param;

public interface MovieMapper {
    List<Movie> find(@Param("movieName") String movieName, @Param("directorName") String directorName);

    Movie get(@Param("movieId") String movieId);

    Movie lock(@Param("movieId") String movieId);

    int add(Movie movie);

    int set(Movie movie);

    int remove(Movie movie);
}

5-3 Repository インタフェースを作成

repository パッケージ配下に MoviesRepository インタフェースを作成する. 抽象メソッドを定義する.

package com.example.demo.repository;

import com.example.demo.domain.Movie;
import java.util.List;

public interface MovieRepository {
    List<Movie> findList(String movieName, String directorName);

    Movie findOne(String movieId);

    Movie lock(String movieId);

    void insert(Movie movie);

    void update(Movie movie);

    void delete(Movie movie);
}

5-4 RepositoryImpl クラスを作成

repository パッケージ配下に MoviesRepository インタフェースを実装した,実行クラスである RepositoryImpl クラスを作成する.
@Repository アノテーションによって,repository に DI をおこなう.
SqlSessionTemplate クラスによって,Mapper インタフェースを読み込み,MySQL を操作するメソッドを利用できる.

package com.example.demo.repository;

import com.example.demo.domain.Movie;
import com.example.demo.repository.mybatis.MovieMapper;
import java.util.List;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.stereotype.Repository;

@Repository
public class MovieRepositoryImpl implements MovieRepository {
    private final SqlSessionTemplate sqlSessionTemplate;

    public MovieRepositoryImpl(SqlSessionTemplate sqlSessionTemplate) {
        this.sqlSessionTemplate = sqlSessionTemplate;
    }

    @Override
    public List<Movie> findList(String movieName, String directorName) {
        List<Movie> movie = this.sqlSessionTemplate.getMapper(MovieMapper.class).find(movieName, directorName);
        return movie;
    }

    @Override
    public Movie findOne(String movieId) {
        Movie movie = this.sqlSessionTemplate.getMapper(MovieMapper.class).get(movieId);
        if (movie == null){
            throw new RuntimeException("movie not found");
        }
        return movie;
    }

    @Override
    public Movie lock(String movieId) {
        Movie movie = this.sqlSessionTemplate.getMapper(MovieMapper.class).lock(movieId);
        if (movie == null){
            throw new RuntimeException("movie not found");
        }
        return movie;
    }

    @Override
    public void insert(Movie movie) {
        this.sqlSessionTemplate.getMapper(MovieMapper.class).add(movie);
    }

    @Override
    public void update(Movie movie) {
        int affected = this.sqlSessionTemplate.getMapper(MovieMapper.class).set(movie);
        if (affected != 1){
            throw new RuntimeException("failed");
        }
    }

    @Override
    public void delete(Movie movie) {
        int affected = this.sqlSessionTemplate.getMapper(MovieMapper.class).remove(movie);
        if (affected != 1){
            throw new RuntimeException("failed");
        }
    }
}

6 Service を作成

demo/src/main/java/com/example/demo/配下に,service パッケージを作成する.
ビジネスロジックトランザクション管理をおこなう.

6-1 Service インタフェースを作成

service パッケージ配下に MovieService インタフェースを作成する.

package com.example.demo.service;

import com.example.demo.domain.Movie;
import com.example.demo.domain.MovieList;

public interface MovieService {
    MovieList find(String movieName, String directorName);

    Movie get(String movieId);

    void add(Movie movie);

    void set(Movie movie);

    void remove(String  movieId);
}

6-2 ServiceImpl クラスを作成

Service インタフェース(6-1)を実装したクラスを作成する.
@Service アノテーションによって DI をおこなう.
@Transactional アノテーションによって,DB 操作にエラーが発生したときにロールバックをおこなう.

package com.example.demo.service;

import com.example.demo.domain.Movie;
import com.example.demo.domain.MovieList;
import com.example.demo.repository.MovieRepository;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
public class MovieServiceImpl implements MovieService{
    private final MovieRepository repository;

    public MovieServiceImpl(MovieRepository repository) {
        this.repository = repository;
    }

    @Override
    public MovieList find(String movieName, String directorName) {
        MovieList movieList = new MovieList();
        movieList.setMovieList(this.repository.findList(movieName, directorName));
        return movieList;
    }

    @Override
    public Movie get(String movieId) {
        Movie movie = this.repository.findOne(movieId);
        return movie;
    }

    @Override
    @Transactional(rollbackFor = Throwable.class)
    public void add(Movie movie) {
        this.repository.insert(movie);
    }

    @Override
    @Transactional(rollbackFor = Throwable.class)
    public void set(Movie movie) {
        this.repository.lock(movie.getMovieId());
        this.repository.update(movie);
    }

    @Override
    @Transactional(rollbackFor = Throwable.class)
    public void remove(String movieId) {
        this.repository.delete(this.repository.findOne(movieId));
    }
}

7 RestController を作成

demo/src/main/java/com/example/demo/配下に,controller パッケージ作成する.

RestController を作成

controller パッケージ配下に MoviesRestController クラスを作成する.

アノテーションについて

Controller クラスに付与するアノテーション

  • @RestController
    • RestController の DI をおこなう
    • フロントエンドの@Controller とは異なり,戻り値をテキストコンテンツで返すために使用する
  • @RequestMapping
    • localhost:8080 以下に,/api/movie のパスを割り当てている.

メソッドに付与するアノテーション

  • @GetMapping
    • get メソッド時の動作を指定する
  • @PostMapping
    • post メソッド時の動作を指定する
  • @PatchMapping
    • patch メソッド時の動作を指定する
  • @DeleteMapping
    • delete メソッド時の動作を指定する

メソッド内の引数に付与するアノテーション

  • @RequestParam
    • HTTP リクエストパラメータを取得する
  • @RequestBody
  • @PathVariable
    • URI パスのパラメータを取得する
package com.example.demo.controller;

import com.example.demo.domain.Movie;
import com.example.demo.domain.MovieList;
import com.example.demo.service.MovieService;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("api/movie")
public class MovieRestController {
    private final MovieService service;

    public MovieRestController(MovieService service) {
        this.service = service;
    }

    @GetMapping(path = "", produces = "application/json")
    public MovieList find(@RequestParam(name = "movieName", required = false) String movieName,
                          @RequestParam(name = "directorName", required = false) String directorName){
        return this.service.find(movieName, directorName);
    }

    @GetMapping(path = "/{movieId}", produces = "application/json")
    public Movie get(@PathVariable String movieId){
        return this.service.get(movieId);
    }

    @PostMapping(path = "", produces = "application/json")
    public void add(@RequestBody Movie movie){
        this.service.add(movie);
    }

    @PatchMapping(path = "/{movieId}", produces = "application/json")
    public void update(@PathVariable String movieId, @RequestBody Movie movie){
        movie.setMovieId(movieId);
        this.service.set(movie);
    }

    @DeleteMapping(path = "/{movieId}", produces = "application/json")
    public void remove(@PathVariable String movieId){
        this.service.remove(movieId);
    }
}

8 configuration を作成

MySQL との接続設定を作成する. demo/src/main/java/com/example/demo/配下に,configuration パッケージ作成する.

DataSourceConfigurationProperties を作成

configuration パッケージ配下に DataSourceConfigurationProperties を作成する.
application.yml の読み込みをすることで,独自プロパティの設定をおこなう.

package com.example.demo.configuration;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.ConstructorBinding;

@ConstructorBinding
@ConfigurationProperties(prefix = "dbcp2.jdbc")
public class DataSourceConfigurationProperties {
    private final String url;

    private final String driverClassName;

    private final String username;

    private final String password;

    private final int initialSize;

    private final int maxIdle;

    private final int minIdle;

    public DataSourceConfigurationProperties(String url, String driverClassName, String username, String password,
                                             int initialSize, int maxIdle, int minIdle) {
        this.url = url;
        this.driverClassName = driverClassName;
        this.username = username;
        this.password = password;
        this.initialSize = initialSize;
        this.maxIdle = maxIdle;
        this.minIdle = minIdle;
    }

    public String getUrl() {
        return url;
    }

    public String getDriverClassName() {
        return driverClassName;
    }

    public String getUsername() {
        return username;
    }

    public String getPassword() {
        return password;
    }

    public int getInitialSize() {
        return initialSize;
    }

    public int getMaxIdle() {
        return maxIdle;
    }

    public int getMinIdle() {
        return minIdle;
    }
}

DataSourceConfiguration を作成

DataSourceConfigurationProperties の読み込みをおこない,設定の反映をする.

package com.example.demo.configuration;

import javax.sql.DataSource;
import org.apache.commons.dbcp2.BasicDataSource;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
@EnableConfigurationProperties(DataSourceConfigurationProperties.class)
public class DataSourceConfiguration {
    private final DataSourceConfigurationProperties properties;

    public DataSourceConfiguration(DataSourceConfigurationProperties properties) {
        this.properties = properties;
    }

    @Bean
    public DataSource dataSource(){
        BasicDataSource dataSource = new BasicDataSource();

        dataSource.setDriverClassName(this.properties.getDriverClassName());

        dataSource.setUrl(this.properties.getUrl());
        dataSource.setUsername(this.properties.getUsername());
        dataSource.setPassword(this.properties.getPassword());
        dataSource.setInitialSize(this.properties.getInitialSize());
        dataSource.setMaxIdle(this.properties.getMaxIdle());
        dataSource.setMinIdle(this.properties.getMinIdle());
        return dataSource;
    }
}

以上で完成です

動作確認

起動

demo/src/main/java/com/example/demo/配下の実行クラス,DemoApplication クラスを Intellij を使って実行する.

http://localhost:8080/api/movie にアクセスして mysql に格納されているデータが表示されたら成功.

CRUD

curl コマンドを用いて動作確認をします

READ(get)

単一検索

入力

curl -H "Content-Type: application/json" "localhost:8080/api/movie/M01"

出力

{
  "movieId": "M01",
  "movieName": "君の名は。",
  "director": { "directorId": "D01", "directorName": "新海誠" }
}

全検索

入力

curl -H "Content-Type: application/json" "localhost:8080/api/movie"

出力

{
  "movieList": [
    {
      "movieId": "M01",
      "movieName": "君の名は。",
      "director": { "directorId": "D01", "directorName": "新海誠" }
    },
    {
      "movieId": "M02",
      "movieName": "天気の子",
      "director": { "directorId": "D01", "directorName": "新海誠" }
    },
    {
      "movieId": "M03",
      "movieName": "言の葉の庭",
      "director": { "directorId": "D01", "directorName": "新海誠" }
    },
    {
      "movieId": "M04",
      "movieName": "新聞記 者",
      "director": { "directorId": "D02", "directorName": "藤井道人" }
    },
    {
      "movieId": "M05",
      "movieName": "デイアンドナイト",
      "director": { "directorId": "D02", "directorName": "藤井道人" }
    },
    {
      "movieId": "M06",
      "movieName": "ダークナイト",
      "director": {
        "directorId": "D03",
        "directorName": "クリストファー・ノーラン"
      }
    },
    {
      "movieId": "M07",
      "movieName": "インセプション",
      "director": {
        "directorId": "D03",
        "directorName": "クリストファー・ノーラン"
      }
    }
  ]
}

CREATE(post)

映画を追加する

入力

curl -X POST \
-H "Content-Type: application/json" "localhost:8080/api/movie" \
-d '{"movieName":"テネット", "director": {"directorId":"D03"}}'

確認

curl -H "Content-Type: application/json" "localhost:8080/api/movie/M08"

結果

{
  "movieId": "M08",
  "movieName": "テネット",
  "director": {
    "directorId": "D03",
    "directorName": "クリストファー・ノーラン"
  }
}

UPDATE(patch)

映画を更新する

入力

curl -X PATCH \
-H "Content-Type: application/json" "localhost:8080/api/movie/M08" \
-d '{"movieName":"秒速5センチメートル", "director": {"directorId":"D01"}}'

確認

curl -H "Content-Type: application/json" "localhost:8080/api/movie/M08"

結果

{
  "movieId": "M08",
  "movieName": "秒速5センチメートル",
  "director": { "directorId": "D01", "directorName": "新海誠" }
}

DELETE(delete)

映画を削除する

入力

curl -X DELETE -H "Content-Type: application/json" "localhost:8080/api/movie/M08"

確認

curl -H "Content-Type: application/json" "localhost:8080/api/movie/M08"

出力

{
  "timestamp": "2021-05-02T22:17:32.490+00:00",
  "status": 500,
  "error": "Internal Server Error",
  "message": "",
  "path": "/api/movie/M08"
}