API Gateway から Lambda を呼ぶ際の設定、Lambda プロキシ統合 の使用有無時の実装などをメモ。
(2017/10月時点での話=.NET Core 1.0しかサポートしてない時点です)
Overview
1 開発環境の準備 (その1)
2 .NET Core 1.0 対応の .NET Standard 1.6 のクラスライブラリの作成(その1)
3 簡易なクラスライブラリー実装(その1)
4 Console プロジェクトの作成(その2)
5 Autofac の実装(その2)
6 AWS Labmda プロジェクトの作成(その2)
7 AWS Labmda の環境変数を読み込む
8 API Gateway から Lambda - プロキシ統合 の使用とか(←今回ココ)
9 AWS Lambda から AWS Lambda の呼び出し
10 AWS Lambda から CloudWatch Events の呼び出し
環境は、.NET Core1.0 と .NET Standard1.6 です(雑...)といっても今回は、API Gateway 利用時の Lambda へつなぐ前後の設定が中心。
こんなAPIつくるイメージです。
GET
メソッドで取得**/api/user/{id}
って感じのURLにアクセスしたら、なんらかの情報を返す(っぽいイメージ)。
API Gateway の作成
API Gateway は AWS マネジメントコンソールでさくっと作れるので細かい手順は省略します。 細かい手順はAWSのドキュメント(「Lambda 関数を公開するための API を作成する」)にて♪
「demo-api05」という名称で作って、
リソース: user
> リソース: {id}
> メソッド: GET
を作成しました。こんな画面にたどり着きます。
全てCORSを有効にしているので、OPTIONS
が自動で生成されています。
「Lambda プロキシ統合の使用」をチェックするかしないかで、Lambda 側の実装が結構かわります。
「Lambda プロキシ統合の使用」を使わないなら、
API Gateway 側で渡したい情報に対して手動でマッピングの設定をすることで、Lambda へ渡すことができます。必要な情報だけを渡してあげれば
Lambda 側で受け取る情報がシンプルになりますね。
「Lambda プロキシ統合の使用」を使うと、
API に来た情報(httpのヘッダーやbodyの情報とか諸々)を AWS Lambda へ渡してくれます。で、 Lambda 内で加工する感じですね。便利な感じですが、個人的には制約がちょっとうざく感じました。
どっちがいいかとかは用途次第ですね。両方試してみましょう。
統合リクエスト > Lambda プロキシ統合 を使わない場合
デモ用 Lambda
デモ用の Lambda として以下のプログラムをデプロイしておきました(デプロイ手順はここら辺な感じ...)
API Gateway から情報受け取るのに、InputModel
クラス型を定義しています。つまりこの定義に合わせて API Gateway 側でマッピングしてあげます。
出力には、OutputModel
クラスを定義して、jsonを返すようにしてます。BaseDemoModel
クラスを継承させて、キャメルケースでjsonを返すようにしました。
本文マッピングテンプレートの設定
API Gateway でマッピングの設定です。そもそもマッピングする元の情報について、詳しくはAWSのドキュメントを見た方がよいでしょう。
設定していきましょう。API Gateway で、対象のメソッドの「統合リクエスト」を選択します。
下の方にある「本文マッピングテンプレート」を開きます。
今回の例だと、 「Content-Type」で「application/json」と入力し、テンプレートを以下のように編集します。
Lambda が受け取る引数の型に合わせてテンプレートを書いています。今回だと URLの{id}
を InputModel
クラスの UserId
にマッピングさせるので、以下のようにすればOKです。
{ "userId": "$input.params('id')" }
あえてマッピングのJsonをキャメルケースで書きましたが、LambdaSerializerにはJSON.NETが使われているので、キャメルケースのJSON→パスカルケースのC#のクラスへのデシリアライズは良しなにやってくれます。
では、テストしてみましょう。API Gateway の今回のメソッドを選択して、「テスト」をクリックします。
{id}
には、「yoko」と入力して「テスト」ボタンをクリックすると、想定通りっぽい?レスポンスが返ってきてます。
エスケープシーケンス、ジャマい!
「ジャマい」ってなんだろうってのはさておき、エスケープシーケンスを排除します。API Gateway の今回のGETメソッドの「統合レスポンス」を開きます。
既存のレスポンスのステータスが200のやーつを開き、本文マッピングテンプレートの application/json
をクリックして、テンプレートを書きます。
書く内容はこれ。で、本文マッピングテンプレートを保存して、上の方の保存ボタンもクリックします。
$input.path("$")
では、テスト。これで想定通りのレスポンスを返すことができました。
統合リクエスト > Lambda プロキシ統合 を使う場合
ここはイマイチ正しいやり方を理解していない気がしますが...書いてきましょう。Lambda プロキシ統合を使う場合は、API Gateway を作るとき、または作った後「統合リクエスト」で「Lambda プロキシ統合の使用」にチェックを入れるだけです。
これを使う際に注意したいのは、Lambda が出力するレスポンスに制約があることです。
これにそわないと 502 のエラーになります。
プロキシ統合用 Lambda
レスポンスの制約を踏まえてこんなデモ用 Lambda を作りました。
ざっくり解説として、まず最後のレスポンスについてですが、制約に合わせて ProxyResponse
というクラスを作りました。
これをそのままレスポンスとして返してあげればOKです。
API Gateway からのリクエストですが、 Stream
で受け取って表示してみました。表示するためだけのサンプルです。CloudWatch でログで見ると具体的にみえます。
必要な情報を引っこ抜いたり必要なプロパティ持ったクラス作って、Desirializeして使えばよいですね。
テストした結果はこんな感じ。
上のコードでは適当に値を返していますが、bodyになんか入れたいならjsonの文字列にしてあげればよいです。プロキシ統合を使った場合は、エスケープシーケンスじゃまい問題は起きませんでした♪。
おわりに..
よくあったミスをメモ....
CORSの設定忘れ
API Gateway を作るたびに(チェックボックスポチるだけなのに)設定し忘れて、エラーを見るたびに「う...」ってなってました。ガチでしかもたくさん作るなら諸々をCLI使った方がしあわせですかね。
設定変更後のデプロイ忘れ
API Gateway の変更をステージに反映するには、デプロイ(「アクション」 の選択肢から 「APIのデプロイ」を選んでやるやつ)が必要です。ちなみにLambdaは、デプロイしてしまえばステージの方にも反映さます。なんか違和感ありますが...。
なんか事故ったときに、直したのに反映されないと これも単なる忘れごとなだけですが、「う...」ってなってました。
おしまい