RESTについて改めて復習をする

# API とは

そもそもAPIとは何でしょうか？

- API（Application Programming Interface） ・・・　機能やデータを外部から呼び出して利用できるように定めた規約
    - リソースごとにURLを定義
    - メソッドでリソースに対する処理を定義
    - JSONでデータをやり取りする

では、APIはWebサービスとどのような関係にあるのでしょうか？（WebサービスにとってAPIとはどのような存在なのでしょうか？）

以前、Webの仕組みについては解説しました。
https://qiita.com/Umeda-East45/items/948cf9a226b216e99c8d


- Webサービス ・・・ユーザーが抱える課題を解決する。ユーザーはサービスに対して情報を保存・引き出す・情報を変更するような操作を能動的に実施する

- WebAPI・・・上記Webサービスで提供している機能やデータをプログラムが読み取りやすい形で利用できるように定めたもの。具体的なAPI：無料でも様々なAPIがインターネット上に公開されています。
https://qiita.com/kazuki_tachikawa/items/7b2fead2a9698d1c15e8


APIにも複数の種類があり、現在のWebサービスで一般的に使用されている代表的なAPIには以下の３種類があります。

1. REST API
1. GraphQL
1. gRPC・・・・厳密にはAPIではなくフレームワークですが、今回はWeb技術の入門者向けの記事のためAPIとしてあえて区分しています。

今回は、上記の中で最も使用されているAPIである`REST API`について解説をしたいと思います。

# REST API

REST(REpresentational State Transfer)の文章での定義は以下になります。
**分散型システムにおける設計原則群（設計ルール）**

まだWebサービスを開発した経験のない入門者の場合、以下の文章だけでは非常に抽象的でわかりにくいです。しかし、実際にWebサービスを開発する際には、現場で自然と守られている原則であり「当たり前」だと感じる概念になります。

1. **クライアント/サーバー**
画面側(UI/クライアント)とデータ（サーバー）で関心事を分離させる

1. **ステートレス**
[こちらのURL](https://qiita.com/Umeda-East45/items/948cf9a226b216e99c8d#%E3%82%B9%E3%83%86%E3%83%BC%E3%83%88%E3%83%AC%E3%82%B9:~:text=%E5%8C%96%E3%81%95%E3%82%8C%E3%82%8B%EF%BC%89-,%E3%82%B9%E3%83%86%E3%83%BC%E3%83%88%E3%83%AC%E3%82%B9,-%E3%81%93%E3%81%93%E3%81%8B%E3%82%89%E3%81%AF
)にてまとめてあります。

1. **キャッシュ制御**
クライアント側でレスポンスをキャッシュできるようする制約

1. **統一インターフェース**
あらかじめ定義・共有された方法でやり取りされること。

1. **階層化システム**
多層アーキテクチャ構成。一つのサーバーをコンポーネントとして独立（カプセル化）させること

1. **コードオンデマンド**
クライアントがサーバーから実行可能なコードをダウンロードし、ローカルで実行することができる概念

*RESTful API*という呼び方もありますが広義の意味ではほぼ同じで実際の業務では同義語として認識して問題ないです。

# REST WebAPI サービス設計について

## URIの設計のポイント

1. 短く入力しやすい
シンプルで覚えやすいものにすることで入力ミスを防ぐ
【NG】　GET http://test.sample.com/service/api/search
【OK】　GET http://test.sample.com/search

1. 人間が読んで理解できる (省略しない)
国や文化が変わっても不変な表記にする
プロジェクトのみでしか通じない省略記号などは使わない
【NG】　GET http://test.sample.com/sv/m
【OK】　GET http://test.sample.com/movies

1. 大文字・小文字が混在していない (全て小文字)
統一するなら一般的に小文字
【NG】　http://test.sample.com/Users
【OK】　http://test.sample.com/users

1. 単語を連結する場合
単語はハイフンで繋げる（アンダースコアは使わない）
**単語の連結をする必要がある場合は、URIを見直すことを考える必要がある**

1. 単語は複数形を利用する
URIで表現しているのは「リソースの集合」
※ 以下の場合「countries」がリソースになる
http://test.sample.com/countries/japan

1. エンコードを必要とする文字を使わない
URIから意味を理解できない
http://test.sample.com/テスト
「テスト」をエンコードすると以下になる。
http://test.sample.com/%E3%83%86%E3%82%B9%E3%83%88
**このような場合　パット見て意味を推測することができない→好ましくない**

1. サーバーサイドの内容がわかるような記述はしない
悪意あるユーザーに脆弱性を突かれる危険性がある
【NG】　GET : http://test.sample.com/cgi-bin/get_user.php?id=12345
**phpやcgiなどサーバー側の情報がURIの中に見えてしまっている**
【OK】　GET : http://test.sample.com/users/12345

1. 改造しやすい
システム依存の設計や、不規則なID、ユーザー固有のトークンやセッション情報を含むURIだと意味が理解できない
【NG】　GET : http://test.sample.com/server-a/12345
【OK】　GET : http://test.sample.com/products/12345

1. ルールが統一されている
`パスパラメータ-`を使うのか`クエリパラメーター`を使うのかなどを予め決めておく
※2つの使い分けについては別途記述

## HTTPメソッドの種類について

| HTTP method | 意味 |
| ---- | ---- |
| GET | リソースの取得 |
| POST | リソースの新規作成 |
| DELETE | リソースの削除 |
| PUT | リソースの更新 |


# クエリパラメーターとパスパラメーターの使い分け

`クエリパラメーター`
URIの末尾にある?につづくキーバリューのこと
省略が可能
GET http://test.sample.com/users?page=3
※検索条件（絞り込み条件）はパスに含めない

`パスパラメーター`
URL中に埋め込まれるパラメータのこと
一意なリソースを表すのに必要
GET http://test.sample.com/users/123


# REST APIの実際の定義と実装例

movieをリソースとしたCRUD操作のURI、HTTPメソッドの定義


**REST でないAPIの場合**
HTTPでGETとPOSTのみを使用してパスを変えて「作成」「削除」「更新」などの処理を変えます。一つ一つのHTTPメソッドに対してURIをそれぞれ作成する必要があります。
| URI | HTTP method | メモ |
| ---- | ---- | ---- |
| movie/get-movies | GET | 取得 |
| movie/get-movie/:id | GET | 取得 |
| movie/create-movie/:id | POST | 作成 |
| movie/delete-movie/:id | POST | 削除 |
| movie/update-movie/:id | POST | 更新 |

**REST APIの場合**
パスは変えずに、HTTPの`GET`/`POST`/`PUT`/`DELETE`を使用します。

| URI | HTTP method | メモ |
| ---- | ---- | ---- |
| movie/movies | GET | 取得 |
| movie/movie/:id | GET | 取得 |
| movie/movie/:id | POST | 作成 |
| movie/movie/:id | DELETE | 削除 |
| movie/movie/:id | PUT | 更新 |


**まとめ**

このようにREST APIの場合は、URIを大幅に減らすことができます。
| APIの種類| URIの数 |
| ---- | ---- |
| RESTでない API | 5 |
| REST API | 2 |


参考までに、非常に入門的なコードになりますが
Express（Node.js）での実装の違いのサンプルは以下になります。

**REST　APIでない場合**

```js

// GETリクエスト - 全データの取得
// app.getにてHTTPのGET指定
app.get('/get-movies', (req, res) => {
  // 一覧を取得する処理を記載
});

// GETリクエスト - 特定のアイテムの取得
// app.getにてHTTPのGET指定
app.get('/get-movie/:id', (req, res) => {
  // 特定のIDの情報を取得する処理を記載
});

// POSTリクエスト - 新しいアイテムの作成
// app.postにてHTTPのPOST指定
app.post('/create-movie', (req, res) => {
  // 新しいmovieを登録する処理を記載
});

// PUTリクエスト - 特定のアイテムの更新
// app.postにてHTTPのPOST指定
app.post('/update-movie/:id', (req, res) => {
  // movieの情報を更新する処理を記載
});

// DELETEリクエスト - 特定のアイテムの削除
// app.postにてHTTPのPOST指定
app.post('/delete-movie/:id', (req, res) => {
  // movieの情報を削除する処理を記載
});

```



**REST　APIの場合**

```js

// GETリクエスト - 全データの取得
// app.getにてHTTPのGET指定
app.get('/movies', (req, res) => {
  // 一覧を取得する処理を記載
});

// GETリクエスト - 特定のアイテムの取得
// app.getにてHTTPのGET指定
app.get('/movie/:id', (req, res) => {
  // 特定のIDの情報を取得する処理を記載
});

// POSTリクエスト - 新しいアイテムの作成
// app.postにてHTTPのPOST指定
app.post('/movie', (req, res) => {
  // 新しいmovieを登録する処理を記載
});

// PUTリクエスト - 特定のアイテムの更新
// app.putにてHTTPのPUT指定
app.put('/movie/:id', (req, res) => {
  // movieの情報を更新する処理を記載
});

// DELETEリクエスト - 特定のアイテムの削除
// app.deleteにてHTTPのDELETE指定
app.delete('/movie/:id', (req, res) => {
  // movieの情報を削除する処理を記載
});

```