初心者がWeb APIについて学習する記事

Web API初心者による学習ノートです。

## 参考資料
- [Web を 支える 技術 HTTP、URI、HTML、そして REST](https://www.amazon.co.jp/dp/B07JK7FZH2/ref=cm_sw_r_tw_dp_t8WWFb7WM4VX9?_x_encoding=UTF8&psc=1 )
- [Re:ゼロから始める Web API 入門](https://youtu.be/GbHWlUs9AoE)
- [0 から REST API について調べてみた](https://qiita.com/masato44gm/items/dffb8281536ad321fb08)

## Web とは？

### Webの用途
**Webサイト**：情報の閲覧
**ユーザインターフェースとしてのWeb**：デバイスの設定画面やHTMLヘルプなど
**プログラム用APIとしてのWeb ( Web API )**：プログラム向けのインターフェース

### 基本的な用語

- **HTTP(Hypertext Transfer Protocol)**
  - 通信のためのルール（プロトコル）
- **URI(Uniform Resource Identifier)**
  - リソース識別子
  - URL は URI に含有され、「位置」を示している
- **HTML(Hypertext Markdown Language)**
  - Web で表示するための文書フォーマット

- **分散システム**
  - 複数のサーバーがシステムを動かす。
  - 現在は大体こっちが使われている。
- **集中システム**
  - つよつよサーバー（メインフレーム）がシステムを動かす。

## REST とは？

REST とは**Webのアーキテクチャスタイル**である

### 「アーキテクチャスタイル」とはなんぞや？
- **アーキテクチャスタイル**とは、具体的なアーキテクチャを設計する際の指針、作法、流儀のこと。
- 「この技術を使おう！」とか「こういうサーバ構成にしよう！」といった具体的な概念ではない。

| 用語                   | 抽象度 | 具体例                  | 
| :--------------------: | :----: | :---------------------: | 
| アーキテクチャスタイル | 高     | REST                    | 
| アーキテクチャ         | 中     | サーバー、ブラウザ etc. | 
| 実装                   | 低     | Apache、Chrome etc.     | 


### RESTにおける「リソース」を理解する

「リソース」とは、**Web上に存在する、名前を持った様々な情報**である。


**リソースの例**

- 横浜の天気予報
- 今読んでるQiita記事
- 子猫のフリー画像
  
#### 「リソースの名前」ってなんだ？

- **「リソースの名前」＝「URI」**
- 世界中にとんでもない数存在しているリソース達は、**それぞれURIで一意の名前を持っている。**
- URIを使うと、プログラムはリソースが表現する情報にアクセスできる。
- １つのリソースが複数のURIを持つこともある。

**リソースの名前の例**

- 横浜の天気予報
    - リソースの名前：https://weather.yahoo.co.jp/weather/jp/14/4610.html
- 今読んでるQiita記事
    - リソースの名前：https://qiita.com/masako5121/items/da313f407eefa9b504e6
- 子猫のフリー画像
    - リソースの名前：https://www.pakutaso.com/20200855241post-27529.html  

### RESTを構成する6つのアーキテクチャスタイル
- RESTは下記の表の6つのアーキテクチャスタイルを組み合わせたアーキテクチャスタイルである。
- いくつかのスタイルを除外しても良い。

| アーキテクチャスタイル | 概要                                                                         | 
| ---------------------- | ---------------------------------------------------------------------------- | 
| クライアント/サーバ    | UIと処理を分離する                                                           | 
| ステートレスサーバ     | クライアントのアプリケーション状態をサーバが管理しない                       | 
| キャッシュ             | サーバから取得したリソースを再利用し、クライアントとサーバの通信回数を減らす | 
| 統一インターフェース   | リソースに対する操作を、統一した限定的なインターフェースで行う               | 
| 階層化システム         | システムをいくつかの階層に分離する                                           | 
| コードオンデマンド     | プログラムコードをサーバからDLし、クライアント側で実行する                   | 


## URIの基本

### URIの構文

```:URIの例
http://user:pass@site.example.com:8000/article?id=99&category=diary#about
```

| 対応箇所               | 役割             | 概要                                                        | 
| ---------------------- | ---------------- | ----------------------------------------------------------- | 
| `http`                 | URIスキーム      | 通信プロトコルを表す（大体httpかhttps）                     | 
| `user:pass`            | ユーザ情報       | 「<ユーザ名>:<パスワード>」の形式                           | 
| `site.example.com`     | ホスト名         | ドメイン名またはIPアドレス                                  | 
| `8000`                 | ポート番号       | ホストにアクセスするときのプロトコルで用いるTCPポート番号   | 
| `/article`             | パス             | 階層を表し、一意なリソースを指している                      | 
| `id=99&category=diary` | クエリパラメータ | 検索する際などに、追加情報を「<名前>=<値>」の形式で記述する | 
| `#about`               | URIフラグメント  | リソース内部の更に細かい部分を特定するときに使う            | 

### 絶対URIと相対URI

URIのパスは、OSのファイルシステムと同じような階層構造を持っている。

| URIの種類 | 例                             | 概要                                 | 
| --------- | ------------------------------ | ------------------------------------ | 
| 絶対URI   | `http://example.com/hoge/piyo` | OSファイルシステムで言うところの「絶対パス」 | 
| 相対URI   | `/hoge/piyo`                   | OSファイルシステムで言うところの「相対パス」 | 
| ベースURI | `http://example.com/`          | 相対URIの起点を指定するURI           | 

### URIで使える文字

URIでは下記の文字が使える。

- **アルファベット**：`A-Z,a-z`
- **数字**：`0-9`
- **記号**：`-.~:@!$&'()`

また、日本語など上記の文字列以外をURIに入れる際は**「%エンコーディング」**でその文字をエンコードする必要がある。

## [クールなURI設計](https://www.kanzaki.com/docs/Style/URI.html)

> What makes a cool URI?
> A cool URI is one which does not change.
> What sorts of URI change?
> URIs don't change: people change them.
> （引用：https://www.w3.org/Provider/Style/URI.html）
>
> クールなURIとは？
> クールなURIとは変わらないもののこと。
> どんなURIが変わってしまう？
> URIは変わらない：人がそれを変更するのだ。
> （引用：https://www.kanzaki.com/docs/Style/URI.html）

上記からもわかるように、最強のURIとは「**変わらないURI**」である。

### 変わらないURIを設計するための四か条

#### 其の一：プログラミング言語に依存した拡張子やパスを含めない

```:悪い例
http://sample.com/cgi-bin/login.pl
http://sample.com/servlet/LoginServlet
```
特定言語などに依存した表記をしていると、将来的に言語を変更した際にURIも変えなければならない。

#### 其の二：メソッド名やセッションIDを含めない

```:悪い例
http://sample.com/Login.do?action=showLoginPage
http://sample.com/main.jsp?sessionid=9999
```
メソッドやセッションIDが変わるとURIも変わってしまう。

#### 其の三：URIには「リソースを指し示す名詞」を使う

```:悪い例
http://sample.com/user/show/999
```

動詞はHTTPメソッドで表現できるため、URIには名詞を用いる。


#### 其の四：できるだけシンプルかつ人間が理解できるものにする

```:悪い例
http://sample.com/posts/category/hobby/camera/999
```

URIはシンプルイズベストである。

### URIの変更方法
- どうしてもURIを変更したい場合は、できるだけ**リダイレクト(=古いURIを新しいURIに転送するHTTPの仕組み)**を行う。
- ページランクを引き継げるため、SEO的にもGOOD。

| Redirectの種類 | 概要              | 
| -------------- | ----------------- | 
| 301 Redirect   | 恒久的なURIの変更 | 
| 302 Redirect   | 一時的なURIの変更 | 


### URI設計のテクニック

#### バージョン番号を含める

```:有名サイトAPIのURI例
Twitter API | https://api.twitter.com/1.1/
Qiita API | https://qiita.com/api/v2/
```

将来的なAPI刷新時にバージョン番号を変更すれば良く、修正しやすい。

#### 拡張子でリソースの表現を分ける

```:拡張子で言語を指定する例
【日本語】http://sample.com/2020/01/01/press.ja
【英語】http://sample.com/2020/01/01/press.en
```
```:拡張子でフォーマットを指定する例
http://sample.com/sampledata/item.txt
http://sample.com/sampledata/item.json
```

1つのリソースが複数の表現を持つ場合、拡張子で各表現を分ける手法がある。

### URIの不透明性を保つ

**URIが不透明である状態とは？**

- **URIからリソースの構造が推測できない**
- **クライアント側でURIを構築しない**

**URIが不透明でないと・・・**

- URIに拡張子を含めると、その言語で操作される可能性
- API経由以外でサーバから情報を抜き出される可能性

## HTTPの基本

### TCP/IPの4階層モデル

HTTPは「**TCP/IP**」というネットワークプロトコルをベースとしているため、まずはこちらを理解する。

| 階層                           | 対応するもの | 説明                                           | 
| ------------------------------ | ------------ | ---------------------------------------------- | 
| アプリケーション層             | HTTP         | アプリケーション毎の通信プロトコルを決定する層 | 
| トランスポート層               | TCP          | データ転送の抜け漏れをチェックする層           | 
| インターネット層               | IP           | データを送るための層                           | 
| ネットワークインターフェース層 | Ethernet     | LANケーブルなどの物理的な層                    | 

### HTTPの歴史
HTTPは進化しており、割と最近になってから**HTTP2.0**が使われ始めた

| バージョン | 公開年 | 特徴                                                                   | 
| ---------- | ------ | ---------------------------------------------------------------------- | 
| HTTP 0.9   | 1991年 | GETメソッドのみ                                                        | 
| HTTP 1.0   | 1996年 | ステータスコードなどのレスポンスヘッダの追加<br>POSTメソッドなどの追加 | 
| HTTP 1.1   | 1999年 | 原則、1通信＝1リクエスト＝1レスポンス                                  | 
| HTTP 2.0   | 2015年 | ストリームの多重化による複数リクエストの同時通信                       | 

### リクエストとレスポンスの流れ

下記にWebページを表示する際のリクエストとレスポンスの流れを示す。

|       | クライアント側       | サーバ側            | 
| :---: | :------------------: | :-----------------: | 
| 1     | リクエストMSGの構築  | 待機                | 
| 2     | リクエストMSGの送信  | 待機                | 
| 3     | 待機                 | リクエストMSGの受信 | 
| 4     | 待機                 | リクエストMSGの解析 | 
| 5     | 待機                 | HTMLを取得          | 
| 6     | 待機                 | レスポンスMSGの構築 | 
| 7     | 待機                 | レスポンスMSGの送信 | 
| 8     | レスポンスMSGの受信  | 待機                | 
| 9     | レスポンスMSGの解析  | 待機                | 
| 10    | レンダリング等の処理 | 待機                | 


### HTTPメッセージ

- 前項でクライアントとサーバ間を飛び交っていた**リクエストメッセージ**と**レスポンスメッセージ**を、まとめて**HTTPメッセージ**と呼ぶ。
- HTTPメッセージは下記の３つの要素で構成されている
    1. **スタートライン**
        - リクエストの場合は「**リクエストライン**」
        - レスポンスの場合は「**ステータスライン**」
    1. **ヘッダ**
    1. **ボディ**

下記にリクエストとレスポンスそれぞれの構造を示す。

|                                            | リクエスト                                                                                             | レスポンス                                                                                               | 
| :----------------------------------------: | ------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------- | 
| **リクエストライン /<br>ステータスライン** | **メソッド**：(例) GET<br>**パス**：(例) /post/999<br>**プロトコルバージョン**：(例) HTTP/2            | **プロトコルバージョン**：(例) HTTP/2<br>**ステータスコード**：(例) 200<br>**テキストフレーズ**：(例) OK | 
| **ヘッダ<br>(メタデータ)**               | **accept**：要求するデータ形式<br>**Host**：リクエスト先のホスト名<br>**User-Agent**：リクエスト元情報 | **content-type**：返ってくるデータ形式                                                                   | 
| **ボディ<br>(実データ)**                   | ・POSTやPUTの際に使う<br>・作成するリソース情報等                                                      | ・サーバが返す実データ<br>・HTML, JSON etc.                                                              | 

**HTTPメッセージの中身をみてみる**
1. [このページ](https://httpbin.org/)でAPIをいろいろ叩く
2. Chrome開発者ツールや[Talend API Tester](https://chrome.google.com/webstore/detail/talend-api-tester-free-ed/aejoelaoggembcahagimdiliamlcdmfm)等でリクエストとレスポンスの中身を見てみよう

```HTTP:httpbin.orgへのリクエスト例
GET /json HTTP/1.1
Accept: application/json
Host: httpbin.org
```

```HTTP:httpbin.orgからのレスポンス例
HTTP/1.1 200
access-control-allow-credentials: true
access-control-allow-origin: *
content-length: 429
content-type: application/json
date: Sun, 00 Nov 2020 00:00:00 GMT
server: gunicorn/19.9.0
status: 200

{
  "slideshow": {
    "author": "Yours Truly", 
    "date": "date of publication", 
    "slides": [
      {
        "title": "Wake up to WonderWidgets!", 
        "type": "all"
      }, 
      {
        "items": [
          "Why <em>WonderWidgets</em> are great", 
          "Who <em>buys</em> WonderWidgets"
        ], 
        "title": "Overview", 
        "type": "all"
      }
    ], 
    "title": "Sample Slide Show"
  }
}
```

### HTTPの**ステートレス性**

「**ステートレス**」とは「**サーバがクライアントの状態を管理せずに通信する**」ことである。
実世界のやり取りを考えるとわかりやすい。

```:「ステートフル」をスタバで例える
客　「コーヒーをお願いします」
店員「ホットとアイスどちらにしますか？」
客　「ホットで！」
店員「サイズはどれになさいますか？」
客　「トールでお願いします」
店員「サイドメニューはよろしいですか？」
客　「クロワッサン１つください」
店員「以上でよろしいですか？」
客　「はい」
店員「かしこまりました」
```
**ステートフルの特徴**
ステートフルなやりとりは簡潔であるが、**サーバが常にクライアントのアプリケーション状態を覚えていなければならない**ため、接続先が多くなると管理しきれない。

```:「ステートレス」をスタバで例える
客　「コーヒーをお願いします」
店員「ホットとアイスどちらにしますか？」
客　「コーヒーをホットで！」
店員「サイズはどれになさいますか？」
客　「コーヒーをホットで、サイズはトールでお願いします」
店員「サイドメニューはよろしいですか？」
客　「コーヒーをホット、サイズはトールで、サイドメニューにクロワッサン１つください」
店員「以上でよろしいですか？」
客　「コーヒーをホット、サイズはトールで、サイドメニューにクロワッサン１つでお願いします。以上！」
店員「かしこまりました」
```

**ステートレスの特徴**
ステートレスなやりとりは冗長ではあるが、**サーバがクライアントのアプリケーション状態を覚えなくて良い。**
また、通信エラー時は処理が重複する可能性がある。

## HTTPメソッド

### HTTPメソッドの種類

- HTTPメソッドは8つ存在するが、主要なものは下表の6つである。
- 下表に示す4つのメソッドでCRUDを実装することが多い。

| メソッド    | CRUD               | 役割                                           | 
| :---------: | :----------------: | ---------------------------------------------- | 
| **GET**     | Read               | リソースの取得                                 | 
| **POST**    | Create             | 子リソースの作成<br>リソースへのデータ追加etc. | 
| **PUT**     | Update /<br>Create | リソースの更新<br>（存在しなければ作成）       | 
| **DELETE**  | Delete             | リソースの削除                                 | 
| **HEAD**    | -                  | リソースのヘッダ取得                           | 
| **OPTIONS** | -                  | リソースがサポートしているメソッドの取得       |  

### 各メソッドのべき等性と安全性

**べき等性**：ある操作を何回行っても結果が同じこと
**安全性**：操作対象のリソースの状態を変化させないこと

| メソッド    | べき等性 | 安全性 | 
| :---------: | :------: | :----: | 
| **GET**     | ○       | ○     | 
| **POST**    | ×        | ×      | 
| **PUT**     | ○       | ×      | 
| **DELETE**  | ○       | ×      | 
| **HEAD**    | ○       | ○     | 
| **OPTIONS** | ○       | ○     | 

## ステータスコード
レスポンスメッセージのステータスラインに記述された**ステータスコード**を見れば、
レスポンスの大まかな内容を把握することができる。

### N百番代ごとの大まかな分類

| ステータスコード | 意味               | 詳細                                                                                                 | 
| :--------------: | :----------------: | ---------------------------------------------------------------------------------------------------- | 
| 100-199              | 処理中             | ・処理が継続していることを示す<br>・クライアントがそのままリクエストを継続するか再送信するか等を判定 | 
| 200-299              | 成功               | リクエストが成功したことを示す                                                                       | 
| 300-399              | リダイレクト       | ・他のリソースへのリダイレクトを示す<br>・Locationヘッダを見て新しいリソースへ接続                   | 
| 400-499              | クライアントエラー | クライアントのリクエストが原因でエラーが発生したことを示す                                           | 
| 500-599              | サーバーエラー     | サーバー側の原因でエラーが発生したことを示す                                                         | 

### よく使うステータスコード（成功系）

| ステータスコード | テキストフレーズ  | 意味・特徴                                                                                                                                              | 
| :--------------: | :---------------: | ------------------------------------------------------------------------------------------------------------------------------------------------------- | 
| 200              | OK                | GET：取得したリソースがメッセージ本文で送信される<br>HEAD：ヘッダ情報がメッセージ本文で送信される<br>PUT / POST：操作の結果がメッセージ本文で送信される | 
| 201              | Created           | 新たなリソースが作成された<br>PUTまたはPOSTのレスポンス                                                                                                 | 
| 204              | No Content        | リクエストのレスポンスとして送信するコンテンツは無いが、<br>リクエストは成功                                                                                | 
| 301              | Moved Permanently | リソースの恒久的な移動                                                                                                                                  | 

### よく使うステータスコード（エラー系）

| ステータスコード | テキストフレーズ      | 意味・特徴                                     | 
| :--------------: | :-------------------: | ---------------------------------------------- | 
| 400              | Bad Request           | リクエストの構文やパラメータが間違っている     | 
| 403              | Forbidden             | コンテンツへのアクセス権が無い                 | 
| 404              | Not Found             | リソースが存在しない、URLを解釈できない etc.   | 
| 500              | Internal Server Error | サーバ側で処理できないエラーが発生             | 
| 502              | Bad Gateway           | ゲートウェイとなるサーバが正常に動作しない     | 
| 503              | Service Unavailable   | サーバがメンテナンスや過負荷等でダウンしている | 

> （参考）HTTP レスポンスステータスコード
> https://developer.mozilla.org/ja/docs/Web/HTTP/Status

## HTTPヘッダ

ヘッダでは、メッセージのボディに対する付加的な情報（メタデータ）を表現する。
ここでは、よく使うヘッダを挙げる。

### MINE(Multipurpose Internet Mail Extensions)メディアタイプの指定

- Content-Typeヘッダでメディアタイプを指定する。
- charsetパラメータは文字エンコーディングを指定する。

```:ヘッダ記述例
Content-Type: application/json; charset=utf-8
```

| 主要なType  | 意味                     | type/subtypeの例 | 
| :---------: | :----------------------: | :--------------: | 
| text        | 人が読んで直接理解できる | text/plain       | 
| image       | 画像データ               | image/jpeg       | 
| audio       | 音声データ               | audio/mpeg       | 
| video       | 動画データ               | video/mp4        | 
| Application | その他のデータ           | application/json | 

### HTTP認証のためのヘッダ

- リソースにアクセス制限がかかっている場合、認証が必要。
- Authorizationヘッダに認証情報を付与する。

```:ヘッダ記述例
Authorization: Basic TupRWRpQwLgEPVndgC==
```

| 認証方法   | 仕様                                                   | 特徴                                                          | 
| :--------: | :----------------------------------------------------- | :------------------------------------------------------------ | 
| Basic認証  | base64でエンコードされた<br>ユーザIDとパスワードを使用 | ・簡単にデコードできる<br>・HTTPSによる通信暗号化が必要       | 
| Digest認証 | デコードできない<br>ハッシュ化されたパスワードを使用   | ・メッセージは暗号化されない<br>・HTTPSによる通信暗号化が必要 | 
| Bearer認証 | 権限付きのトークンを取得して使用する                   | OAuth2.0で保護されたリソースなどの認証に使う                  | 

### キャッシュ

- キャッシュ＝リソースを再利用する仕組み
- Cache-Controlヘッダを使い、検証と再取得の条件を設定する

| 指定方法                          | 目的                               | 
| :-------------------------------- | :--------------------------------- | 
| `Cache-Control: no-store`         | キャッシュしない                   | 
| `Cache-Control: no-cache`         | キャッシュするが再検証する         | 
| `Cache-Control: max-age=86400`    | 相対的な有効期限[秒単位]を設定する | 
| `Cache-Control: must-revailidate` | 必ず検証する                       |