RESTAPI設計入門

[Web API: The Good Parts](https://www.amazon.co.jp/Web-API-Parts-%E6%B0%B4%E9%87%8E-%E8%B2%B4%E6%98%8E/dp/4873116864) を読んでRESTAPIの標準的な設計を学習したので備忘録として

URI設計の良い例/悪い例やHTTPの基礎をつらつらと書き起こします。




## URI

アンチパターンを挙げてその後に良い例を書いていきます。

#### URIの長さ

##### 悲しい例

``` https://api.hoge.com/api/service/users ``` 



* apiという文字が特に意味なく2つある
* serviceというあまり意味のない文字列

無駄に長いURIは覚えづらく、入力しづらいので避けるのが無難でしょう。

##### 嬉しい例

``` https://api.hoge.com/users ```

これで十分意図が伝わります。


### 意味を理解できない。

##### 悲しい例

``` https://api.hoge.com/us/1/frs/ ```

* usとfrsが何を意味するのか分からない
* 何を意味するのか分からないのでユーザにとって使いづらい

(特定のアプリケーションからしか呼び出さないなら略語でも良い気がしますが、新しいメンバーがすぐに理解できないのでやはり単語を略さない方が良さそうです。)

##### 嬉しい例

``` https://api.hoge.com/users/1/friends/ ```

このURIだと「ID1のユーザの友達一覧を取得する」ということが分かりやすいです。

### 拡張性

##### 悲しい例
ユーザ情報を取得するAPIが次のようだと悲しくなります。


|  ID  |  URI  |
| ---- | ---- |
|  1~15000  |  https://api.hoge.com/users/fizz/{id}  |
|  10001~20000  |  https://api.hoge.com/users/buzz/{id}   |
|20001~50000|https://api.hoge.com/users/foo/{id} |

* IDによってエンドポイントを分割しているらしいが、法則性が無い
* 今後ユーザ数が増えた時に新しいエンドポイントが必要になり、保守しづらい
* fizzやbuzzという文字列に意味がない

##### 嬉しい例

``` https://api.hoge.com/users/{id} ``` のようにシンプルなURIが望ましそうです。

仮にIDによってテーブルやモデルを分割する場合でも(それ自体が設計としてよくありませんが)、サーバ側で処理を行う方がユーザや開発者とって使いやすいものになるでしょう。

### 動詞の有無

##### 悲しい例

``` https://api.hoge.com/users/create ``` 

基本的にRESTAPIのURIに動詞を含めるのは推奨されていません。
「リソース + 動詞」でAPIの用途を示すのはベストプラクティスとは言えない手法です。

##### 嬉しい例

``` POST https://api.hoge.com/users/ ```

「リソース + HTTPメソッド」でAPIの用途を表現します。(※ POSTメソッドはサーバに新しいリソースを追加するのに用いる)


ただ、実際には「リソース + HTTPメソッド」では表現しきれないことも多く、例外的に「リソース + 動詞」からなるURIを認める場合もあるようです。

- リソース + 動詞を用いる例
  - 変換
  - 計算

※ 円からドルに変換するAPI
``` GET /convert?from=JPY&to=USD&amount=100 ``` 


### その他

URIでリソースを特定できないのもアンチパターンと言えるでしょう。
「ユーザの名前を更新するAPI」を例にして考えます。

##### 悲しい例

``` 
PATCH https://api.hoge.com/users 

// リクエストパラメータ
{
 "id": 1,
 "name": "fuga"
}
```

この例ではリクエストパラメータでidを指定しているのでURIでリソースを特定することができません。
これはRESTの原則に反しているので良い設計とは言えないでしょう。

また、idをURIに含めるのに比べるとリクエストパラメータでidを指定する方法はユーザが入力する文字数が多くなります。
使いやすさを考慮してもこの方式は避けたいです

##### 嬉しい例

``` 
PATCH https://api.hoge.com/users/1

// リクエストパラメータ
{
 "name" : "fuga"
}
```

## HTTPメソッド

HTML5のform属性ではGETとPOSTメソッドしか使えません。したがってリソースの一部のみを更新する場合でもPOSTメソッドを使っていました。

WebAPIではこの2つ以外のメソッドも利用することができます。

|メソッド|用途|ステータスコード|APIで返すレスポンスの中身|
|--|--|--|--|
|GET|リソースの取得|200|リソース|
|POST|リソースの新規作成|201|リソース|
|PUT|リソースの上書き|200 or 204|リソース|
|PATCH|リソースの更新|200 or 204|リソース|
|DELETE|リソースの削除|204|文言|

### GETメソッド

サーバからリソースを取得するメソッドです。
GETメソッドがリソースを返すのは当然のことですので特筆すべきことはありません。

### POSTメソッド

新しいリソースを作成するメソッドです。 リクエストが成功した場合はステータスコード201が返ります。これは"Created"という別名で呼ばれることもあります。

HTMLに触れているとPOST = サーバにデータを送信するメソッドと思いがちですが、本来はもう少し狭い用途のメソッドです。

また、基本的にPOSTメソッドのレスポンスでは作成したリソースを返すようにします。

SPAから呼び出す場合、リソースを作成→ 一覧画面に遷移 という処理になるのが自然なのでリソースを返す必要はないかもしれませんが、RESTAPIは不特定多数のシステムから呼び出されることを想定しておく方が良いでしょう。

>POST メソッドは、新しいリソースを作成すると、HTTP 状態コード 201 (Created) を返します。 新しいリソースの URI は、応答の Location ヘッダーに含まれています。 応答本文には、リソースの表現が含まれています。

(下記リンクより引用)
https://docs.microsoft.com/ja-jp/azure/architecture/best-practices/api-design#post-methods

### PUTメソッド

リソースを更新するメソッドです。対象のリソースがない場合は新たに作成します。
より厳密には「編集」というよりは「上書き」で、送信したデータでもとのリソースを置換します。

ユーザ情報の更新のような典型的な編集処理にPUTを用いるのはやや違和感があります。
同名ファイルのアップロードや他ユーザの投稿への「いいね」などに用いることが多いようです。

リクエストが成功した場合は200か204("No Content")をステータスコードとして返します。
どちらでもHTTPの仕様上は問題ありませんが、204だとユーザに提示する情報として意味が薄いという意見もあります。

ステータスコードは200で、レスポンスボディに更新後のリソースを入れて返すことがより一般的です。

### PATCHメソッド

リソースを更新するメソッドです。対象のリソースが存在しない場合はリクエストが失敗します。
PUTがリソースを上書きするのに対して、PATCHメソッドはリソースの一部を変更します。

サイズが大きいデータの一部だけを変更する場合や、ユーザ情報の一部(プロフィールやメールアドレス)を変更する場合などリソースの一部を更新する時に使うことが多いです。

PUTメソッドと同じく、リクエストが成功した場合は200か204("No Content")をステータスコードとして返します。

ステータスコードは200で、レスポンスボディに更新後のリソースを入れて返すことがより一般的です。

### DELETEメソッド

リソースを削除するメソッドです。対象のリソースが存在しない場合はリクエストが失敗します。

リクエストが成功した場合は204か200をステータスコードとして返します。
削除されたリソースをレスポンスとして返す意味はあまりないので、ステータスコードは204を返し、レスポンスボディにリソースを含めない方が良いでしょう。


#### PUTとPATCHの使い分け

* リソースの一部を更新する場合はPATCH
* リソースを丸ごと置き換える場合はPUT

という使い分けが良さそうです。
こうすることでそのAPIが何をするのかユーザや他の開発者が理解しやすくなると思いました。


## 参考資料

[Web API: The Good Parts](https://www.amazon.co.jp/Web-API-Parts-%E6%B0%B4%E9%87%8E-%E8%B2%B4%E6%98%8E/dp/4873116864)

[RESTful Web API の設計](https://docs.microsoft.com/ja-jp/azure/architecture/best-practices/api-design#post-methods)

[RESTful APIのPOSTやPUTのレスポンスで、なんで登録や更新した情報を返すの？](https://qiita.com/tubutubu_mustard/items/c1f4519841b61cb549a0)

[冪等性とは「同じ操作を何度繰り返しても、同じ結果が得られる性質」のこと](https://qiita.com/suin/items/316cb8aaf8dfcf11abae)