web-dev-qa-db-ja.com

AWS-API GatewayからLambdaへの投稿

シンプルなC#Aws Lambda関数があり、これはLambdaコンソールテストからのテストに成功しますが、API Gateway(Lambdaトリガーオプションから生成したもの)から呼び出された場合、およびpostmanを使用した場合に502(不良ゲートウェイ)で失敗します。 (この初期関数にはオープンアクセスがあります(セキュリティなし))

// request header
    Content-Type: application/json

//  request body
    {
        "userid":22,
        "files":["File1","File2","File3","File4"]
    }

ログで発生するエラーは次のとおりです。

Wed Feb 08 14:14:54 UTC 2017 : Endpoint response body before transformations: {
  "errorType": "NullReferenceException",
  "errorMessage": "Object reference not set to an instance of an object.",
  "stackTrace": [
    "at blahblahmynamespace.Function.FunctionHandler(ZipRequest input, ILambdaContext context)",
    "at lambda_method(Closure , Stream , Stream , ContextInfo )"
  ]
}

投稿されたオブジェクトがラムダ入力引数に渡されていないようです。

以下のコード

// Lambda function
     public LambdaResponse FunctionHandler(ZipRequest input, ILambdaContext context)
        {
            try
            {
                var logger = context.Logger;
                var headers = new Dictionary<string, string>();

                if (input == null || input.files.Count == 0)
                {
                    logger.LogLine($"input was null");
                    headers.Add("testheader", "ohdear");
                    return new LambdaResponse { body = "fail", headers = headers, statusCode = HttpStatusCode.BadRequest };
                }
                else
                {
                    logger.LogLine($"recieved request from user{input?.userid}");
                    logger.LogLine($"recieved {input?.files?.Count} items to Zip");
                    headers.Add("testheader", "yeah");
                    return new LambdaResponse { body = "hurrah", headers = headers, statusCode = HttpStatusCode.OK };
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

//ラムダ応答/ ZipRequestクラス

public class LambdaResponse
{

    public HttpStatusCode statusCode { get; set; }
    public Dictionary<string, string> headers { get; set; }
    public string body { get; set; }
}
public class ZipRequest
{
    public int userid { get; set; }
    public IList<string> files { get; set; }
}
11
Tim

API GatewayでLambdaプロキシ統合を使用する場合、FunctionHandlerの最初のパラメーターはPOSTの本文ではなく、LambdaRequestを呼び出す別のAPI Gateway作成オブジェクトです。これらの変更をサンプルコードに試してください。追加:

public class LambdaRequest
{
   public string body { get; set; }
}

ハンドラプロトタイプを次のように変更します。

public LambdaResponse FunctionHandler(LambdaRequest req, ILambdaContext context)

そしてFunctionHandlerの中に追加:

ZipRequest input = JsonConvert.DeserializeObject<ZipRequest>(req.Body);

完全なLambdaRequestオブジェクトは、AWSドキュメントの プロキシ統合用のLambda関数の入力形式 に記載されており、HTTPヘッダー、HTTPメソッド、クエリ文字列、本文、およびその他いくつかのものが含まれています。

7
phebert

これは、OPが質問したときに利用できなかった可能性がありますが、API Gatewayを使用してLambda関数を呼び出すと、特定の応答オブジェクトが提供されます。

前述のドキュメント ラムダ入力形式のAPIゲートウェイシンプルプロキシ で述べたように、APIゲートウェイは入力引数をかなり冗長なラッパーでラップします。また、同様に冗長な応答オブジェクトを想定しています。

ただし、カスタムの要求オブジェクトと応答オブジェクトを作成する必要はありません。 AWSチームは Amazon.Lambda.APIGatewayEvents ライブラリを提供しています。これはNuGetでも利用できます。このライブラリには、既製のAPIGatewayProxyRequestおよびAPIGatewayProxyResponseオブジェクトが含まれています。

リクエストのBodyはJSONオブジェクトではなく文字列であるため、手動で逆シリアル化する必要があります。これは柔軟性のために行われたと思いますか?

関数の例は次のようになります。これは、AWSツールによって提供されるデフォルト関数の変更です。

    public APIGatewayProxyResponse FunctionHandler(APIGatewayProxyRequest request, ILambdaContext context)
    {
        var bodyString = request?.Body;

        if (!string.IsNullOrEmpty(bodyString))
        {
            dynamic body = JsonConvert.DeserializeObject(bodyString);

            if (body.input != null)
            {
                body.input = body.input?.ToString().ToUpper();

                return new APIGatewayProxyResponse
                {
                    StatusCode = 200,
                    Body = JsonConvert.SerializeObject(body)
                };
            }
        }

        return new APIGatewayProxyResponse
        {
            StatusCode = 200
        };
    }
18
SouthShoreAK

また、Getメソッドで渡された「パスパラメータ」を取得しようとすると、多くの時間を失いました。たとえば、次のようなパスがある場合

/ appsetting/123

...その後、次のように構成されます

enter image description here

リソース「appid」を{appid}として指定することにより、APIゲートウェイにこれをパス変数としてキャプチャするように指示します。

私が見つけた重要な発見の1つは、POSTタイプのアクションの本文に投稿することで、Lambdaが機能することです。他のいくつかのスレッドを読んで、パス変数をGETアクションの本体:

  1. GET値の選択(写真)
  2. 統合リクエストをクリック
  3. 以下に示すようなマッピングテンプレートの作成

enter image description here

テストすると、appid値のみをプラグインして適切な結果を得ることができます。これが誰かを助けることを願っています。

0
ebol2000