この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
1 はじめに
API GatewayからキックされるLambdaファンクションをC#で記述する場合に、パラメータを受け渡す方法について確認してみました。
作業には、Mac上で利用可能なAWS Lambda(C#)用テンプレートを使用しています。
Visual Studio for Mac で AWS Lambda(C#)を書くためのテンプレート
[GitHub] https://github.com/furuya02/AWSLambdaSample
上記のテンプレートをダウンロード(clone)して、Function.cs及びProgram.csを書き換えることで、検証を進めています。
2 LambdaSerializerAttribute
C#によるLambdaファンクションでは、下記のAssemby属性を指定することで、入力及び、戻り値のストリームで、.NETクラスとJSONの変換を行うことができます。(Assemby属性は、アセンブリレベル、若しくは、メソッドレベルで指定可能です。)
[assembly: LambdaSerializerAttribute(typeof(Amazon.Lambda.Serialization.Json.JsonSerializer))]
例えば、次ようなJSONデータは、下記のクラスに変換されます。
{"Name":"Taro","Age","25"}
public class Sample {
public string Name { get; set; }
public string Age { get; set; }
}
API Gatewayでは、Integration Requestで、各種のデータをマッピングすることが出来るので、ここでリクエストパラメータをJSON形式で渡します。
3 特定のパラメータ名の取得
それでは、最初に、パラメータとして指定される名前が、予め決まっている場合の取得を試してみます。
パラメータとしてname及びageの2つの値を受け取るとした場合、まずは、マッピングで次のように指定します。
{
"Name": "$input.params('name')",
"Age": "$input.params('age')"
}
そして、C#によるLambdaファンクションでは、下記のとおりです。
using Amazon.Lambda.Core;
[assembly: LambdaSerializerAttribute(typeof(Amazon.Lambda.Serialization.Json.JsonSerializer))]
namespace AWSLambdaSample {
public class Function {
public string FunctionHandler(Param param, ILambdaContext context) {
var str = $"Name={param.Name} Age={param.Age}";
context.Logger.LogLine(str);
return str;
}
}
public class Param {
public string Name { get; set; }
public string Age { get; set; }
}
}
API Gatewayでテストボタンを押すと、パラメータに設定した値が、Lambdaで定義したクラスで受け取れていることを確認できます。
CloudWatch Logsでは、ファンクション内で出力したログも確認できます。
デプロイして実際にアクセスしている様子です。
4 すべてのパラメータの取得
先の方法では、予め決まったパラメータ以外は、取得できません。そこで、すべてのパラメータをStringとして受けとってみます。
マッピングは、次のように指定します。
{
"Params": "$input.params().querystring"
}
.NETのクラス定義です。
public string FunctionHandler(Param param, ILambdaContext context) {
var str = $"Params={param.Params}";
context.Logger.LogLine(str);
return str;
}
public class Param {
public string Params { get; set; }
}
5 すべてのパラメータをDictionaryで取得
最後に、もう一歩進めて、すべてのパラメータをDictionaryで受け取る要領です。
マッピング
{
"Params": {
#foreach($param in $input.params().querystring.keySet())
"$param": "$util.escapeJavaScript($input.params().querystring.get($param))" #if($foreach.hasNext),#end
#end
}
}
.NETのクラス定義
public string FunctionHandler(Param param, ILambdaContext context) {
var result = new StringBuilder();
foreach (var d in param.Params) {
var str = $"Key={d.Key} Value={d.Value}";
context.Logger.LogLine(str);
result.Append(str);
}
return result.ToString();
}
public class Param {
public Dictionary<string,string> Params { get; set; }
}
6 String以外の型変換
実は、String以外の型でも変換は可能です。 次の例は、Int型及びDateTime型に変換して受け渡しを行っている例です。
マッピング
{
"Age": "$input.params('age')",
"Birthday": "$input.params('birthday')"
}
.NETのクラス定義
public string FunctionHandler(Param param, ILambdaContext context) {
var str = $"Age={param.Age} Birthday={param.Birthday.ToString("yyyy.MM.dd")}";
context.Logger.LogLine(str);
return str;
}
public class Param {
public int Age { get; set; }
public DateTime Birthday { get; set; }
}
しかし、ここで注意が必要なのは、無効な値がセットされた場合に、Amazon.Lambda.Serialization.Json.JsonSerializer自体が例外で落ちてしまいますので、ファンクション内でのエラー制御はできません。
ガチガチの入力以外では、とりあえずStringで受けておいて、内部で変換する方が安全かも知れません。
7 最後に
ここまで見てきたように、API Gateway側のマッピングで必要なデータをJSON形式にまとめれば、適切なクラスを設計することで、自由にデータの受け渡しが可能です。
今回は、クエリーパラメータのみをマッピングしてみましたが、この他にも、リクエストヘッダ($input.params().header)、リクエストボディ($input.body)、接続元アドレス($context.identity.sourceIp)、ユーザーエージェント($context.identity.userAgent)など各種のデータをマッピング可能です。
詳しくは、下記をご残照ください。
API Gateway API リクエストとレスポンスペイロードのマッピングテンプレートのリファレンス
8 参考資料
How to pass a querystring or route parameter to AWS Lambda from Amazon API Gateway