HTTP メソッドとHTTP API設計１（GET、POST、PUT、PATCH、DELETE）

# はじめに
こんにちは。

WEBエンジニアのための、HTTP。２つ目の記事です。

この記事では、HTTPのメソッドについて説明をしたいと思います。

今後、作成するHTTP APIでも使える重要な内容になるため、各メソッドが持っている特徴と、それらの違いについてしっかり把握しておくことが大事だと思います。
 
# HTTP API 設計

各メソッドについて説明する前に、`HTTP API`を設計する次の例を見て、どのように設計するのがいいのかを一緒に考えてみましょう。

要求事項は次のようです。
> **会員情報を管理するAPIを設計**
> - **会員リスト参照**
> - **会員参照**
> - **会員登録**
> - **会員修正**
> - **会員削除**

### 設計１

API設計の経験がないエンジニアがいると、想定しましょう。
初級エンジニアはいろいろ工夫をしたうえで、各機能の名前を参考に次のようなAPIを作成しました。

- **会員リスト参照 /read-member-list**
- **会員参照 /read-member-by-id**
- **会員登録 /create-member**
- **会員修正 /update-member**
- **会員削除 /delete-member**

上記のように設計したURIを見ると、各URIがどのような作業を行うのかを一目で分かると思います。

しかし、このような設計がほんとにいい設計でしょうか？

`URI`とは**WEB上にある資源。つまり、リソースの位置を表す唯一の住所**です。

そのため、**APIを設計**するうえで、重要なのは**リソースを識別する**ことです。

### リソースの識別

どうすれば、各機能からリソースが識別できるのでしょうか？

まず、要求事項について考えてみましょう。

- 会員リスト参照
- 会員参照
- 会員登録
- 会員修正
- 会員削除

よく見ると、参照・登録修正・削除などの**行為が、会員を対象に行われている**ことが、分かります。

つまり、**リソースを識別する**ためには、機能から**リソースと、リソースを対象に行われる行為を分離**することが重要です。

今回の要求事項は次のように分離することができます。
- リソース：**会員**
- 行為：**参照**・**登録**・**修正**・**削除**

### 設計２

要求事項の中で、**会員**がリソースであることが分かったので、再びAPIを設計してみましょう。

設計２ではURIにリソースをマッピングし、設計をしてみましょう。

リソースを識別し、URIを階層構造で設計してみました。

- **会員リスト参照 /members**
- **会員参照 /members/{id}**
- **会員登録 /members/{id}**
- **会員修正 /members/{id}**
- **会員削除 /members/{id}**

上記のURIを見ると、会員リスト参照は`/members`、単一会員の参照・登録・修正・削除については、`/members`の後に、`/{id}`を付けて設計を行いました。

しかし、この設計も完璧な設計ではあります。

よく見ると、**参照・登録・修正・削除のURIが同一**であることが分かります。
すると、これらをどうやって**使い分ける**ことができますか？

このような状況で使うのが、**HTTP Method**です。

# HTTP Method


> - **GET：リソース参照**
> - **POST：リクエストのデータを処理　※主に登録で使用**
> - **PUT：リソースの置き換え　※リソースがない場合、リソースを生成**
> - **PATCH：リソースの部分的な変更**
> - **DELETE：リソース削除**

上記のメソッド以外にも、`HEAD` `OPTIONS` `CONNECT` `TRACE` 等もありますが、この記事では説明しません。

## GET

```:GET
GET /search?q=hello&hl=jp HTTP/1.1
Host: www.google.com
```

`GET`メソッド名前通り、**リソースを参照**するために、使われます。

検索を行うときに、サーバーに送信したいデータはクエリ（クエリパラメータ、クエリストリング）を通じて送ることができます。

GETはMessage Bodyを用いてデータを渡す方法もありますが、サポートしないサーバーもあるため、推奨はされていません。

このように**GETでリソースを参照するとき、検索条件などがある場合、クエリパラメータを作成**してリクエストを送ります。

GETを用いた会員参照機能の流れについて確認してみましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/678234/fcc5986f-e427-a99e-3b69-bc4906540005.png)


クライアントからGETメソッドとURIで100番会員の情報をサーバーに要求しています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/678234/62f5f0e6-902f-db5a-cec1-3617b52d6b6b.png)

サーバーはメッセージを受け取った後、メッセージに該当するリソースをDBから取り出します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/678234/b1319c51-80ce-9a0f-605d-1ddc86fca826.png)

その後、取り出した、100番会員のリソースをBodyに入れて、レスポンスを作成し、クライアントに送ります。

今回の例では`JSON`を使いましたが、リソースタイプは`HTML` `IMAGE`　`XML`も使えます。

## POST

次は、POSTメソッドです。

```
POST /members HTTP/1.1
Content-Type: application/json

{
    "userName":"hello",
    "age":20
}
```

`POST`メソッドはクライアントがサーバーにデータを送信して、その**データに対する処理を要求する**際に使います。
つまり、Message Bodyにデータを入れて送信すると、サーバーはMessage Bodyを通じて**送信されてデータを処理するすべての機能**を行います。

:::note info
サーバーで行われる**処理**はクライアントとサーバーが**事前に定義した作業**を意味し、主にリソースの登録やプロセスの処理を意味します。
:::

上記のHTTPメッセージを見ると、POSTメソッドと、`/members`を定義し、Bodyにデータが格納されていることが分かります。

**事前に**`POST`**に対しての作業を会員登録と定義**した場合、これは、クライアントが送信した、「Bodyのでーたを新規登録してほしい」という要求になります。


次の例で確認してみましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/678234/4d0cbdd2-7106-1fd9-cba0-7ee23b330004.png)

クライアントはBodyにデータを入れてサーバーに送ります。
この時、`/members`にPOSTメソッドでリクエストが送られたら、新規登録する行うと定義されていれば、サーバーはBodyのデータをもとに新規会員を登録するはずです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/678234/98925ade-e002-54a4-f64d-7c827eafdacc.png)

サーバーはBodyの**データをDBに保存した後に、新規ID(識別子)を生成**します。

ここで、IDが100の会員が作成されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/678234/2f4f8ae9-2e48-e88c-7a21-acf53fb6c907.png)

会員を登録した後、サーバーはPOST処理の結果をレスポンセに入れてクライアントに返します。

### POSTのデータ処理について

> **`POST`のデータに対する処理は、特に決まっていません。各リソースごとに定義しないといけません。**

`POST`は**クライアントとサーバーがリソースに対して、事前に定義した作業**を行います。

つまり、POSTはリソースを登録する作業のみ、行われるわけではありません。

例えば、HTMLのFormタグに入力されたデータで会員登録・商品の注文、ブログやニュースのような記事の作成にも使われます。

また、新規のリソース作成し、既存のリソースにデータを追加する作業にも使うことができます。

**POSTが使われるケース**について簡単に説明すると次のようです。

- **新規リソース生成(登録)**
  - サーバーでまだ、識別していない新規リソース生成
- **リクエストデータ処理**
  - プロセスを処理する場合
- **ほかのHTTPメソッドで処理が困難である場合**
  - JSONデータを送信するとき、GETメソッドを使えない場合
  - まず、HTTPめっそどの選択が難しい場合、POSTを使う


> - **サーバー内部的にプロセスの変更がある場合**
 [注文画面から決済完了 -> 配達開始 -> 配達完了]
>
> 上記のように単純にリソースの生成だけでなく、プロセスの状態が変更するときにも使えます。
 このケースは、POSTの結果で新規リソースが生成されない場合もあります。
 例) POST /orders/{orderId}/start-delivery

実際に、**リソースだけでURIを設計することは難しくて、最後に動詞を加えてURIを設計**する方法もあります。このようなURIを`Control URI`といいます。

## PUT

次は`PUT`メソッドです。

```
PUT /members/100 HTTP/1.1
Content-Type: application/json

{
    "userName":"hello",
    "age":20
}
```

PUTは**リソースを置き換える**作業を行います。
つまり、**リソースが存在すれば、Bodyのデータで既存のデータを置き換え、リソースが存在しなければ、新規リソースを作成**します。

ファイルをコピペするときを思い出すと理解がつくと思います。
同じファイルがある場合は、そのファイルを置き換えて、なければペーストを行います。

:::note warn
PUTはリソースの**部分的な修正ができない。**
:::
PUTメソッドはリソースをそのまま置き換えるため、既存リソースの**部分的な修正のため、PUTを使うと、Bodyの入っているデータ以外のデータは削除**されます。

そのため、PUTメソッドで部分的な修正を行いたい場合は、リソースのすべてのデータを作成してから送信しなければなりません。

また、PUTとPOSTの違いは、クライアントがリソースの識別子を知っているところです。

以前のPOSTの例では`/members`でリソースの住所を指定してます。
一方、PUTは`/members/100`で会員の識別子を知っていることが分かります。

では、次の例を通じてPUTについて説明します。

### リソースが存在する場合
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/678234/83ac75d1-8b18-4f59-b773-45d8f7170e6f.png)

クライアントはリソースの住所を指定し、JSONデータをBodyに入れて送信しました。
既に、サーバーには100番会員のリソースが存在しています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/678234/1fe9bafb-1234-2dca-bfb4-b6ace7237165.png)

この場合、既存リソースは新しいデータで置き換えます。

:::note warn
注意！！リソースが置き換えます。
:::
もし、何かの間違いで、クライアントから`{"age":20}`のデータのみ送信されたら、usernameは削除され、ageのみ保存されるようになります。

### リソースが存在しない場合

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/678234/57927fbf-7b06-5b06-c388-80de62743fc4.png)

クライアントがデータをサーバーに送信しました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/678234/6f34d9d4-513e-6221-df8b-69d912aa3e64.png)

サーバーには100番の会員が存在しないため、Bodyで送信されたデータをもとに新規リソースが作成されます。

## PATCH

そうすると、リソースの部分的な修正が必要な場合はどうすればいいでしょうか？

この場合、`PATCH`メソッドを使えます。

```
PATCH /members/100 HTTP/1.1
Content-Type: application/json

{
    "age":50
}
```

`PATCH`はリソースの部分的な修正が必要な場合使えるメソッドです。
修正したいデータをBodyでサーバーに送信すると、**送信されたデータのみ修正され、他のデータは保持**できます。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/678234/30af32c9-91a8-bc08-4a46-ae108e47c0fe.png)

クライアントからURIを指定し、修正したいデータをBodyに入れてサーバーに送信します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/678234/185f638f-e253-7956-8d0e-162ae8d109ab.png)

サーバーは100番会員のageをBodyのデータで修正を行います。

**データを部分的に修正**したい場合は、PUTより**PATCHを使う**のが、もっと修正に近い意味を伝えることができます。

しかし、PATCHをサポートしていない、サーバーも存在するはずです。
その場合はPOSTを使ってデータを修正することができます。

## DELETE

最後に`DELETE`メソッドについて説明します。

```
DELETE /members/100 HTTP/1.1
Host: localhost:8080
```

`DELETE`メソッドは名前通り、**リソースを削除**する機能を行います。

では、次の例を見てみましょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/678234/5a753699-d5d8-d434-c60f-2f38a72f844e.png)

クライアントは削除したいリソースの識別子を加えて、サーバーに送信します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/678234/475bc02b-3c16-594e-1b3d-e1a795debce6.png)

サーバーは送信されたリソースの識別子をもとに、リソースの削除を行います。


# 参考サイト
https://www.inflearn.com/course/http-%EC%9B%B9-%EB%84%A4%ED%8A%B8%EC%9B%8C%ED%81%AC