【AWS公式ドキュメントを噛み砕く】Amazon API Gateway とは?

# はじめに
案件で触れるから、学習がてらアウトプットしてみるよ。（本は無いし、AWSの公式ドキュメントは読みにくいし・・・）
個人の理解メモなので、正しい情報はAWSの公式ドキュメント見てくださいね。
（そして誤りあれば指摘してもらえると嬉しいです）

# 概要
「[ここ](https://aws.amazon.com/jp/api-gateway/)」の話

## 利点
なんか、文章を箇条書きに変えただけになった。

**低コストで効率的**

- Amazon API Gateway では、API に対する呼び出しと、送出されるデータに対してのみ料金が発生します。

**どのようなスケールにも対応するパフォーマンス**

- スロットリングによるトラフィック管理が可能なので、バックエンドの動作はトラフィックの激増にも耐えられます。
- API 呼び出しに対する出力をキャッシュし、バックエンドシステムへの不要な呼び出しを避けられる。

**API アクティビティの容易な監視**

- サービスの呼び出しを視覚的にモニタリングできるダッシュボードが表示される

**合理的な API 開発**

- バージョンの異なる同じ API を同時に実行できる
    - 新しいバージョンをスピーディーに反復し、テストし、リリースすることが可能になる

**柔軟なセキュリティ管理**

- IAMやCognito といった AWS の管理ツールやセキュリティツールを使用して、API に対するアクセス認証を実施できます。
- 署名付き API アクセスを検証できます。
- Lambda連携で、OAuth トークンや他の認証メカニズムで検証可能。

**サーバーなしで API を実行する**

- Lambdaとか使えば、完全にサーバーレスの API を作成することが可能。

**既存のサービスの RESTFUL API エンドポイントを作成する**

- 目的とするサービスに必要な言語でリクエストを生成できます。
- バックエンドインフラストラクチャの負荷が過大にならないようなスロットリングルールを設定することによって、既存のサービスを保護できます。

スロットリングの話、2回でてきてますけど・・・

# 特徴
「[ここ](https://aws.amazon.com/jp/api-gateway/features/)」の話。

- **API の構築、デプロイ、管理**
    - Lambda使えばめっちゃ便利やで
- **回復性**
    - 1 秒間あたりのリクエスト数に基づき、API の各 HTTP メソッドに対するスロットリングルールを設定可能
        - バックエンドシステムへのトラフィック管理に役立つ
    - キャッシュでレスポンス返せるよ！
- **API ライフサイクルの管理**
    - 最新バージョンの公開後であっても、アプリケーションから以前のバージョンの API を呼び出すことができます。
    - それぞれのバージョンの API について、アルファ版、ベータ版、製品版といった複数のリリースステージを管理することもできます。
    - 各 API ステージは、API セットアップに基づいてさまざまなバックエンドエンドポイントでやり取りするように設定できます。
- **SDK の世代**
    - いくつかのプラットフォーム向けのクライアント SDK を生成できます。
        - SDK 配布を、迅速に実施できます。
- **API 動作のモニタリング**
    - ダッシュボードによってサービスの呼び出しを視覚的にモニタリングできます
- **AWS 認証**
    - Identity and Access Management (IAM)、およびお客様の API やその他の AWS リソースすべてに対するアクセスを認証するためのアクセスポリシーを使用できます。
    - AWS Lambda 関数を使用して、JWT トークンや SAML アサーションなどのベアラートークンを検証および承認できます。
- **サードパーティ開発者用の API キー**
    - API キーにきめ細かいアクセス権限を設定して配布することで、サードパーティ開発者をお客様の API にアクセスさせることができます。

# 開発者ガイド

## Amazon API Gateway とは?
「[ここ](https://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/welcome.html)」の話

**AWS クラウドへのゲートウェイ**
仲介して、AWSサービスにつなげるよ！

IFは、API-Gatewayの外と内で少し異なる。
API-Gatewayより外側では、「[メソッドリクエスト](https://docs.aws.amazon.com/apigateway/api-reference/resource/method/)」と「[メソッドレスポンス](https://docs.aws.amazon.com/apigateway/api-reference/resource/method-response/)」。
API-Gatewayの内側では、「[統合リクエスト](https://docs.aws.amazon.com/apigateway/api-reference/resource/integration/)」と「[統合レスポンス](https://docs.aws.amazon.com/apigateway/api-reference/resource/integration-response/)」。

**開発者エクスペリエンス**
【認証】
「API開発者（API-Gatewayの設定と、その内側を開発する人）」と「アプリ開発者（API-Gatewayにアクセスするアプリを作る人）」が居る。
API 開発者は、API を所有する AWS アカウントの IAM ユーザーである必要があります。
アプリ開発者には、AWS アカウントは必要ではない。「[Amazon Congnito](https://docs.aws.amazon.com/ja_jp/cognito/latest/developerguide/cognito-identity.html)」を使えば、FacebookIDとかでも認証できるよ。
※もちろん、アプリ開発者の認証にIAMを使うことも可能。

【用語】

|用語|説明|具体例|
|---|---|---|
|リソース|論理エンティティ|収益データ|
|リソースパス|論理エンティティにアクセスできるURL|`/incomes`|
|オペレーション|HTTP 動詞|GET、POST、PUT、PATCH、DELETE など|
|メソッド|リソースパスとオペレーションを組み合わせた状態のモノ|GET で `/incomes` にアクセス|

【APIを呼び出す】
`execute-api` という API Gateway サービスコンポーネントを使用する。
それ以外にも、認証データを作成するためのコンポーネントとかもあるので、適宜使い分けましょう。とのこと。

**API Gateway のメリット**
上述の「利点」を繰り返しているだけなので、割愛。

**Amazon API Gateway の概念**
「[ここ](https://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/api-gateway-basic-concept.html)」の話

用語説明だけ。
用語もなんとなく推測できるものばかりなので、割愛。

**API料金表**
「[これ](https://aws.amazon.com/jp/api-gateway/pricing/)」見ろってさ。
前提表現を省略しているので、詳細気になる人はちゃんと見てください。

- AWS 無料利用枠の対象ではありません。
- 認証および承認失敗で課金されることはありません。
- API キーが不足しているまたは無効であれば、課金されません。
- リクエストレートまたはバーストレートが事前設定された制限を超えても、課金されません。
- レート制限またはクォータが事前設定された制限を超えても課金されません。

## APIの作成
「[ここ](https://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/how-to-create-api.html)」の話

|用語|説明|
|---|---|
|リソースエンティティ|「メソッドリソース」と「統合リソース」を紐付けるモノ|
|メソッドリソース|アプリ開発者から見た時の、URLとhttpメソッドの組み合わせ|
|統合リソース|統合エンドポイントのURL|
|統合エンドポイント|受け取ったリクエストを転送する先。バックエンドポイントとも呼ばれる。|

レスポンスは、API-Gatewayが変換処理をするか、変換せずにそのまま返却するかを選べる。
変換前のレスポンスを「統合レスポンス」、変換後のレスポンスを「メソッドレスポンス」と呼び分けたりする。

### エンドポイントの選択
APIエンドポイント（外から見たAPIのURLのこと）を決める必要がある。
3種類ある。

|パターン|説明|
|---|---|
|エッジ最適化|デフォルト。自動的に一番近いCloudFrontを利用してくれる。アクセス元が多数の場合はこちらが良い。|
|リージョン|勝手にCloudForntを利用することはない。CloudFront見極めのオーバーヘッドが無いので、アクセス元が少数の場合はこちらのが早い。|
|プライベート|VPC内からのみアクセスする場合。|

基本的に以下形式になる。

```:エンドポイントの形式
{rest-api-id}.execute-api.{region}.amazonaws.com
```
※{api-id} ：API Gateway に生成された API 識別子
※{region} ：API 作成時に選択した AWS リージョン (us-east-1 など) 

エッジ最適化の場合は、上記とは全然関係無い「カスタムドメイン」を利用する形になる。
エッジ最適化・リージョンAPIにおいて、「カスタムドメイン」を利用可能。（プライベートAPIではサポートされていない）

### セットアップの初期化
**セットアップ**
「[ここ](https://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/api-gateway-create-api-step-by-step.html)」を見よう。

**リージョン API を設定する**
「API リクエストが主に EC2 インスタンスまたは API と同じリージョン内のサービスから送られる場合」はこれを使うと良いらしい。（早くなる）

**プライベートAPIを設定する**
特定のVPCからしかアクセスできないAPIを作れる。
詳細は「[こちら](https://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/apigateway-private-apis.html)」。

### API メソッドのセットアップ
#### メソッドリクエスト
**APIリソース**
要は「URLを決定しよう」という話。

REST APIの考え方を述べているだけっぽいので基本は割愛。
「プロキシリソースを使用して API セットアップを効率化する」ってのだけ特殊。
プロキシリリースは、「全てを絶対パスで指定する必要はなくて、ある程度で後ろに投げれるよ」という話っぽい。

プロキシリリースにおいても、親の指定は可能。以下の様な感じ。
この場合の優先度としては、下から順に優先される。（一番詳細な指定が優先されるのであって、下に書いたのが優先される訳ではない）

```:できる
/{proxy+}
/parent/{proxy+}
/parent/{child}/{proxy+}
```

プロキシリリースにおいては、子の指定は不可。以下のようなのは出来ない。

```:できない
/{proxy+}/child
/parent/{proxy+}/{child}
/parent/{child}/{proxy+}/{grandchild+}
```

**HTTPメソッド**
上記で決めた「APIリソース（URL）」に対して「HTTPメソッド（GETとかPOSTとか）」を決める。
そうすると「APIメソッドリソース」と呼ばれる存在に昇格する。

「APIメソッドリソース」には「認証」を設定する必要があるが、詳細はもう少し下で触れる。（メソッドリクエスト認証）

**メソッドリクエストパラメーター**
「パスパラメーター」「ヘッダー」「クエリ文字列パラメーター」をまとめて、「メソッドリクエストパラメーター」と呼ぶらしい。

|用語|説明|
|---|---|
|パスパラメーター| `GET /pets/{petId}` の `{petId}` のこと|
|ヘッダー|HTTPヘッダーのこと|
|クエリ文字列パラメーター|`GET /pets?page=1&limit=10` の `page=1&limit=10` のこと|

どういうふうに受け取るかを指定しようという話。
それをどのように後ろに受け渡すかについては、別に説明があります。

**メソッドリクエストモデル**
要はpostとかputとかで連携されるjsonなどのデータ構造を定義する話。

**メソッドリクエスト認証**

- IAM：AWSでは一般的なIAMを用いて認証する
    - メリット
        - 閉域網でも利用可能
        - AWS推奨（セキュアさをAWSに依存させられる）
    - デメリット
        - 認証される側にAWSアカウントが必要
        - 認証後にアクセスする先のリージョンの指定が必要（DRとか考えると足かせになる）
- Cognito：CognitoというAWSサービスを用いて認証する
    - メリット
        - WEB-APIでは一般的なOpenID Connectという方式を実現できる
        - FacebookなどのIDで認証したい場合に良く使われるが、単独でも利用可能。
    - デメリット
        - Cognitoへのアクセスのためにインターネットアクセスが必要
- Lambdaオーソライザー（カスタムオーソライザー）：自分で認証を実装する
    - メリット
        - 自由度が高い
    - デメリット
        - 実装が大変

※Cognito単独で利用する際は、CognitoIDPoolと連携させないほうが楽かも。
参考：[ブログ記事 - Cognito ユーザープールを単独で API GateWay と共に使う](https://blog.mori-soft.com/entry/2017/09/24/212913)

**メソッドリクエスト検証**
先程のは認証。こちらは**検証**。
まぁ、簡単なバリデーションができるよってだけの話。

#### メソッドレスポンス
そもそも、APIGateway側で設定するのか、後ろで設定されてきたものをそのまま流すのか選択ができる。
以下は、APIGatewayで設定するなら・・・という話っぽい。

**メソッドレスポンスステータスコード**
200とか500とかそういう話。

**メソッドレスポンスパラメーター**
レスポンスヘッダーの定義。

**メソッドレスポンスモデル**
レスポンスのボディ部の話。jsonとかそういうのを設定しましょう。くらいの話。

### API 統合を設定する
「[ここ](https://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/how-to-integration-settings.html)」の話。
API-Gatewayが受け付けた後、どう後ろにつなげるかの話。
（正直細々見るよりも設定した方が早いと思うし、いっぱい記事あるっぽいので、ここは割愛）

### ゲートウェイレスポンスのセットアップ
「[ここ](https://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/customize-gateway-responses.html)」の話。
API-Gatewayに未定義のAPIにアクセスした場合のレスポンスは、デフォルトで用意されている。
でも、それだと分かりづらい場合もあるので、管理者がカスタマイズすることもできるらしい。
そういうデフォルトで用意されたゲートウェイ自体のレスポンスの話。

対象の一覧は「[こちら](https://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/supported-gateway-response-types.html)」

### API の更新と管理
「[ここ](https://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/updating-api.html)」の話。
APIの再デプロイが必要な対象とそうでない対象があるので、見ておくと良い。

APIのデプロイはもう少し下で話が出ます。


## API へのアクセスのコントロール
「[ここ](https://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/apigateway-control-access-to-api.html)」の話。

|コントロール方法|説明|
|---|---|
|リソースポリシー|特定のソース IP アドレスまたは VPC エンドポイントから API へのアクセスを許可または拒否する|
|標準 AWS IAM ロールとポリシー|API 全体または個々のメソッドに適用できる柔軟かつ強力なアクセスコントロール|
|Cross-Origin Resource Sharing (CORS) |クロスドメインのリソースリクエストへの API の応答を制御|
|Lambda オーソライザー|だいたいなんでもできる（自作なので）|
|Amazon Cognito ユーザープール|Cognitoのサービス内でのカスタマイズ可能な認証と認証のソリューション（IAMロールとかも使える？らしいのである程度柔軟に実現できる）|
|クライアント側 SSL 証明書|バックエンドシステムへの HTTP リクエストが API Gateway からのものであることを確認する|
|使用量プラン|各 API キーの API ステージとメソッドの使用状況を追跡および制限|

**良くわからんモノだけ補足**

CORS：個人的にはこちらの記事がわかりやすかった・・・[ブログ記事 - CORS (Cross-Origin Resource Sharing) ってなに？](https://aloerina01.github.io/blog/2016-10-13-1)
使用量プラン：次で説明する。

### 使用量プラン
「[ここ](https://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/api-gateway-api-usage-plans.html)」の話。

スロットリング（流量制御）は、APIメソッド×ステージ×APIキーで制御可能。
※ステージは後ろの方で説明がありますが、『「テストバージョン」「本番バージョン」みたいなカタチのバージョン管理（バージョン番号管理とは別）』を指します。

httpヘッダーの「x-api-key」にこちらから払い出したAPIキーを設定してもらう必要がある。
その上で、こういう制御ができる。

- 単位：最小・・・URL×APIキー単位、最大・・・APIキー単位
- 制御方法：クォータ・・・◯件/月。スロットリング・・・◯件/秒。

補足：

- 超過時のレスポンスはAWS仕様に準ずる
    - クォータ超過時のレスポンス：{"message":"Limit Exceeded"}
    - スロットリング超過時のレスポンス：{"message": "null"}

スロットリングの話は以下の記事がわかりやすかった。
[【新機能】Amazon API Gatewayに「使用量プラン」機能が追加。キーごとにスロットリングやリクエストの制限が可能に](https://dev.classmethod.jp/cloud/aws/usage-plan-for-api-gateway/)

以下、抜粋

バーストの話

>トークンバケットモデルではバケット（ばけつ）の中にトークンがまず入っています。リクエストがきたら１つのリクエストにトークンを合わせてネットワークに送り出します。つまり、バケットの中にあるトークンの数だけリクエストを送ることができ、なくなったら{"message": "null"}という形でレスポンスを返します。この「バケットに入る最大トークン量」が「バースト」です。

レートの話

>一方このバケットには一定単位でトークンが補充されていきます。ですのでバケットが空になっても補充された分のトークンは使えるようになるため、リクエスト自体は送れるようになりますが、バースト分のトークンを使いきった時はこの補充されたトークンのみを使えるようになるためつながりやすさは落ちます。この補充される割合を「レート」と言います。

**詳細な話**
同じドキュメントだけど、前段の「[こっち](https://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/api-gateway-request-throttling.html)」のが詳しい。ので、それベースで以下にまとめる。

例：レート・・・10,000 リクエスト/秒 (rps)。バースト (最大バケットサイズ)・・・5,000 リクエスト。

- 毎秒10,000リクエストが来た場合、全てが処理できる。（レートの話）
- 1秒間でさばける最大数は、レートとバーストを足し合わせた15,000リクエスト
    - 最初の 1 ミリ秒間で 10,000 リクエスト、以降999ミリ秒間はリクエストが来ない場合
        - 5000はすぐ対応。残りの5000は1秒間中に処理。（429エラーは返却しない）
    - 最初の 1 ミリ秒間で 5,000 リクエスト、その後、999ミリ秒内に5,000リクエスト（ミリ秒毎に5リクエスト）の場合
        - 全 10,000 リクエストを 1 秒間中に処理。（429エラーは返却しない）
    - 最初の 1 ミリ秒間で 5,000 リクエスト、そこから100ミリ秒後 5,000 リクエストの場合
        - 5000リクエストはバーストで処理。（最初の1ミリ秒）
        - 1000リクエストは、100ミリ秒の間にレートによって生成されているので即時処理。（100ミリ秒後の101ミリ秒目）
        - 残り4000リクエストは、レートが生成され次第処理（1秒間中に調整）（429エラーは返却しない）
    - 最初の 1 ミリ秒間で 5,000 リクエスト、そこから100 ミリ秒後に 1,000 リクエスト、その後899ミリ秒間に 4,000 リクエストの場合
        - 5000リクエストはバーストで処理。（最初の1ミリ秒）
        - 1000リクエストは、100ミリ秒の間にレートによって生成されているので即時処理。（100ミリ秒後の101ミリ秒目）
        - 残り4000リクエストは、レートが生成され次第処理（899ミリ秒間に調整して飛ばされるが、レートが処理できる範囲内）（429エラーは返却しない？）
            - 「4000リクエストは破棄する」みたいな表現もあるので、結局処理されるのかされないのかが全然わからん・・・

疑問：
どんな時に429エラーが発生するのか？

## APIのドキュメント化
「[ここ](https://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/api-gateway-documenting-api.html)」の話。

### API Gateway での API ドキュメントの表現
**ドキュメントパーツ**
ドキュメントパーツとは、「個々の API エンティティに適用されるドキュメントコンテンツが保存される JSON オブジェクト」のこと。

|フィールド/プロパティ|説明|
|---|---|
|properties|ドキュメントコンテンツがキー/値ペアのマップとして保存される。これはAPI開発者が定義できる。|
|location|関連付けられた API エンティティを識別する。決まった形は無くて、紐付け対象によって異なる。|

説明だけじゃ良くわからん。
以下にサンプルを示します。（公式より抜粋）

```:properties
{
    "location" : {
        "type" : "RESOURCE",
        "path": "/pets"
    },
    "properties" : {
        "summary" : "The /pets resource represents a collection of pets in PetStore.",
        "description": "... a child resource under the root...",
    }
}
```

propertiesに関しては、swaggerに準拠した形にしておくと、API エンティティ定義に伝達してくれるらしい。

疑問：
「propertiesに関しては、swaggerに準拠した形にしておくと、API エンティティ定義に伝達してくれる」ことの何が嬉しいかは、現時点ではわからん。


**より一般的な仕様の API エンティティからのコンテンツ継承**
locationに関しては、特殊な指定の仕方をすると、その記述を継承できるらしい。（これを「より一般的な仕様の API エンティティからのコンテンツ継承」と呼ぶらしい。）

400エラーレスポンスの場合：
何も定義しないと「Invalid request error.」と解釈される。
ただ、以下のように書くと「/pets リソースでのすべてのメソッドに対する 400 レスポンスに、説明 "Invalid petId specified" が代わりに挿入されます。」

```
{
    "location" : {
        "type" : "RESPONSE",
        "path": "/pets",
        "statusCode": "400"
    },
    "properties" : "{
        "description" : "Invalid petId specified."
    }"
}
```

**ドキュメンテーションバージョン**
この形式で記載する限り、API-Gatewayでバージョン管理してくれるらしい。


## APIのデプロイ
「[ここ](https://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/how-to-deploy-api.html)」の話。

|用語|説明|
|---|---|
|デプロイ|対象のAPIをユーザーが呼び出せるようにすること|
|ステージ|カスタムドメインじゃない場合は、URLの最後に付く。devとかprodっていう感じで、テスト中のバージョンをdev、stableになったらprodにするとかそんな感じで使う。|
|Canary（カナリア）リリース|「全体の20%を最新バージョンに振り分ける」みたいなリリース方式。割合指定のみ可能。|

```:デフォルトドメイン（カスタムドメインじゃない）場合のURL
https://{restapi-id}.execute-api.{region}.amazonaws.com/{stageName}
```

ただ、これだと一般的じゃないので、「カスタムドメインを使う」かつ「ベースパスにマッピングする」ことで、以下のようなURLにできる。

```:カスタムドメイン×ベースパス
https://{api.example.com}/{basePath}
```

**パフォーマンスの最適化**
スロットリングやAPIキャッシュを使うことで、パフォーマンスを最適化できる。

疑問：
そういえば、APIキャッシュの話出てきてないな。

**ステージができること**

* API 呼び出しのログを CloudTrail や CloudWatch に記録したり、バックエンドで API リクエストを認証するためのクライエント証明書を選択したりできる。
* ステージ固有の環境コンテキストを API 統合に渡すために、個々のメソッドのステージレベル設定をオーバーライドし、ステージ変数を定義することができる。

**Canaryリリース**
CloudWatch Logs ロググループにおいて、「本稼働ステージの実行ロググループの名前」と、「Canary リリースの実行ロググループの名前」は別モノになるらしい。（/Canary サフィックスが付加される）

**SDKの作成**
プラットフォームおよび言語に固有な方法で API を呼び出すには、プラットフォームおよび言語に固有な SDK を API 用に生成する必要があるらしい。
現在、API Gateway は、Java、JavaScript、Java for Android、iOS 用の Objective-C と Swift、Ruby で API の SDK の生成をサポートしている。

疑問：「言語に固有な方法でAPIを呼び出す」って何だ？普通にリクエスト叩くだけじゃないんか？そんなに特殊なんすか？

## APIの呼び出し
「[ここ](https://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/how-to-call-api.html)」の話。

「普通に対象URLにリクエスト投げればいいよ」って書いてある。
コンソールとかいろんな手段で投げれるので、その具体例がいくつか書いてある。

**SDK**
「SDK使うと、すっげぇシンプルになるよ」ってだけらしい。

疑問：

* 認証とかもカバーしてくれるんかな？
    * たぶんしてくれそう（見つけられなかったけど、それくらいはして欲しいという願いを多分に込めている。）
* SDKに変更があるたびに、API呼び出し側も変更しなきゃいけないってことになるよな？
    * 結局SDK変更するレベルなのは、URL変更レベルの話だから、どちらにせよ呼び出し側は修正は必要だな。

# さいごに
だいたい2～3日かけて読み終わった。
今まで読んだ中で、随一に分かりづらかった。。。

わかりづらいポイント

 - 一般的な話なのかAPI Gateway特有の話なのか、はたまた具体的な設定の話なのかが入り混じっていている
 - 日本語訳が雑なとこが多め（他に比べ）
 - サービスがカバーしている範囲が広くて、単純に情報量が多い


以上