AWS Lambda(C#)でAPI Gatewayからパラメータを受け取る方法

1 はじめに

API GatewayからキックされるLambdaファンクションをC#で記述する場合に、パラメータを受け渡す方法について確認してみました。

作業には、Mac上で利用可能なAWS Lambda(C#)用テンプレートを使用しています。
Visual Studio for Mac で AWS Lambda(C#)を書くためのテンプレート
github [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形式で渡します。

004

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で定義したクラスで受け取れていることを確認できます。

002

CloudWatch Logsでは、ファンクション内で出力したログも確認できます。

003

デプロイして実際にアクセスしている様子です。

005

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; }
}

006

007

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; }
}

008

009

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; } 
}

010

011

しかし、ここで注意が必要なのは、無効な値がセットされた場合に、Amazon.Lambda.Serialization.Json.JsonSerializer自体が例外で落ちてしまいますので、ファンクション内でのエラー制御はできません。

ガチガチの入力以外では、とりあえずStringで受けておいて、内部で変換する方が安全かも知れません。

012

013

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
API Gateway + Lambda にFormからPOSTする時のマッピングテンプレートを作成しました