Amazon API Gatewayから返されるhttpステータスコードを変更する方法はありますか?


95

たとえば、無効なパラメーターに対して特定の400エラーを返したい場合や、ラムダ関数呼び出しの結果が201の場合に201を返します。

異なるhttpステータスコードが欲しいのですが、ラムダ関数がエラーを返していても、apiゲートウェイは常に200ステータスコードを返すようです。


2
したがって、私が抱えていた問題は、カスタムエラータイプを返すことでした。これにより、errorMessage正規表現が正しく機能しなくなりました。ラムダからの失敗応答で標準文字列を返すと、以下のソリューションが機能します。ただし、独自のカスタムエラーオブジェクトを返すと機能しません。
MonkeyBonkey

私の解決策は、Servelessバージョン0.5から1.0に切り替えることでした。また、Servelessドキュメントからの応答を使用して、応答オブジェクトのstatusCodeをプロパティとして指定しています。それがお役に立て
ば幸い

回答:


79

2016年9月9日ごとの更新

Amazonは、Lambdaプロキシ統合を使用して、これをようやく簡単にしました。これにより、Lambda関数が適切なHTTPコードとヘッダーを返すことができます。

let response = {
    statusCode: '400',
    body: JSON.stringify({ error: 'you messed up!' }),
    headers: {
        'Content-Type': 'application/json',
    }
};

context.succeed(response);

APIゲートウェイでリクエスト/レスポンスのマッピングを終了します。

オプション2

aws-serverless-expressを使用して、既存のExpressアプリをLambda / API Gatewayと統合します。


統合できません。つまり、200のステータスと作成された応答(作成されたエラー)を取得します。何か不足していますか?「s-function.json」はどのように見えますか?
Relu Mesaros

最も単純な例として、microservice-http-endpoint(AWS Lambdaコンソール内)と呼ばれるAWS独自のLambdaブループリントをご覧ください。サーバーレスフレームワーク(serverless.com)を使用しているように聞こえる「s-function.json」について言及します。これは完全に別の獣であり、aws-serverless-expressまたは「生の」Lambda / API Gatewayと混同しないでください。私の答えは、サーバーレスフレームワークを使用してこれを機能させる方法を説明していません。
Eric Eijkelenboom

7
不思議に思う人のために、これは新しいcallbackスタイルを使用しても実現できます。ただしてくださいcallback(null, {statusCode: 200, body: 'whatever'})
Widdershin 2017年

1
@Sushilええ、上記の応答変数のようにJSONを返すだけです。
未解決の問題

8
@Sushil私はこれをPythonでLambdaProxyIntegrationを使って解決し、戻ってきましたreturn { "isBase64Encoded": True, "statusCode": 200, "headers": { }, "body": "" }
Jithu R Jacob

74

カスタムHTTPステータスコードとカスタムを返す最も速い方法はerrorMessage次のとおりです。

API Gatewayダッシュボードで、次の手順を実行します。

  1. リソースメソッドで、メソッドの応答をクリックします
  2. ではHTTPステータステーブル、クリックレスポンスを追加し、使用したい各HTTPステータスコードに追加します。
  3. リソースメソッドで、統合応答をクリックします
  4. 前に作成したHTTPステータスコードごとに統合応答を追加します。入力パススルーがチェックされていることを確認してください。ラムダエラー正規表現を使用して、ラムダ関数からエラーメッセージを返すときに使用するステータスコードを特定します。例えば:

    // Return An Error Message String In Your Lambda Function
    
    return context.fail('Bad Request: You submitted invalid input');
    
    // Here is what a Lambda Error Regex should look like.
    // Be sure to include the period and the asterisk so any text
    // after your regex is mapped to that specific HTTP Status Code
    
    Bad Request: .*
    
  5. API Gatewayルートはこれを返す必要があります:

    HTTP Status Code: 400
    JSON Error Response: 
        {
            errorMessage: "Bad Request: You submitted invalid input"
        }
    
  6. これらの設定をコピーしてさまざまな方法で再利用する方法がないので、冗長な手動入力を行うのは非常に煩わしいです!

私の統合応答は次のようになります:

aws apiゲートウェイラムダエラー応答処理


3
だから私の問題は、正規表現トリガーが機能しなかったようです。文字列だけではなく、failメソッドでラムダからエラーオブジェクトを返すからです。例return context.fail(new Error('bad one'))
MonkeyBonkey 2015

7
@kalisjoshua私は最近、APIゲートウェイ/ラムダとエラー処理にかなり詳細な記事を出版:jayway.com/2015/11/07/...
カール・

9
Python Lambdaのcontext.failに相当するものは何ですか?
routeburn 2015年

1
Pythonの場合:例外を発生させます。docs.aws.amazon.com/lambda/latest/dg/python-exceptions.html
devxoul

1
エラー以外の応答でステータスコードを変更する方法はありませんか?作成したオブジェクトと共に「201 Created」を送信したい場合はどうなりますか?
Ben Davis

18

カスタムエラーオブジェクトをJSONとして返すことができるようにするには、いくつかのフープをジャンプする必要があります。

まず、Lambdaを失敗させ、文字列化されたJSONオブジェクトを渡す必要があります。

exports.handler = function(event, context) {
    var response = {
        status: 400,
        errors: [
            {
              code:   "123",
              source: "/data/attributes/first-name",
              message:  "Value is too short",
              detail: "First name must contain at least three characters."
            },
            {
              code:   "225",
              source: "/data/attributes/password",
              message: "Passwords must contain a letter, number, and punctuation character.",
              detail: "The password provided is missing a punctuation character."
            },
            {
              code:   "226",
              source: "/data/attributes/password",
              message: "Password and password confirmation do not match."
            }
        ]
    }

    context.fail(JSON.stringify(response));
};

次に、返すステータスコードごとに正規表現マッピングを設定します。上記で定義したオブジェクトを使用して、この正規表現を400に設定します。

。* "ステータス":400. *

最後に、Lambdaから返されたerrorMessageプロパティからJSON応答を抽出するようにマッピングテンプレートを設定します。マッピングテンプレートは次のようになります。

$ input.path( '$。errorMessage')

私はこれについてより詳細に説明し、LambdaからAPI Gatewayへの応答フローを説明する記事をここに書き込みました:http : //kennbrodhagen.net/2016/03/09/how-to-return-a-custom-error-object -and-status-code-from-api-gateway-with-lambda /


@kennbrodhagen API GatewayとJava Lambdasについて知っていますか?私は同じ正規表現を使用していますが、うまくいきません。私は。* statusCode ":422. *を使用しています
Perimosh '19

@Perimoshは、Java例外を使用してこれを行う方法を説明するこの記事をチェックしてください。aws.amazon.com
compute

10

1) API Gatewayリソース定義の[Integration Request]画面で[ Use Lambda Proxy Integration]チェックボックスをオンにして、Lambda Proxy Integrationを使用するようにAPI Gatewayリソースを構成します。(または、それをcloudformation / terraform / serverless / etc構成で定義します)

2) 2つの方法でラムダコードを変更する

  • 入力event(最初の関数引数)を適切に処理します。それはもはや単なるペイロードではなく、ヘッダー、クエリ文字列、本文を含むHTTPリクエスト全体を表します。以下のサンプル。重要な点は、JSON本体は明示的なJSON.parse(event.body)呼び出しを必要とする文字列になることです(それを忘れないでくださいtry/catch)。以下に例を示します。
  • その後、ヌルを含むHTTPの詳細を提供し、応答オブジェクトにコールバックを呼び出すことによって応答しstatusCodebody、とheaders
    • body文字列でなければならないのでJSON.stringify(payload)、必要に応じて
    • statusCode 数字にすることができます
    • headers 値に対するヘッダー名のオブジェクトです

プロキシ統合のサンプルLambdaイベント引数

{
    "resource": "/example-path",
    "path": "/example-path",
    "httpMethod": "POST",
    "headers": {
        "Accept": "*/*",
        "Accept-Encoding": "gzip, deflate",
        "CloudFront-Forwarded-Proto": "https",
        "CloudFront-Is-Desktop-Viewer": "true",
        "CloudFront-Is-Mobile-Viewer": "false",
        "CloudFront-Is-SmartTV-Viewer": "false",
        "CloudFront-Is-Tablet-Viewer": "false",
        "CloudFront-Viewer-Country": "US",
        "Content-Type": "application/json",
        "Host": "exampleapiid.execute-api.us-west-2.amazonaws.com",
        "User-Agent": "insomnia/4.0.12",
        "Via": "1.1 9438b4fa578cbce283b48cf092373802.cloudfront.net (CloudFront)",
        "X-Amz-Cf-Id": "oCflC0BzaPQpTF9qVddpN_-v0X57Dnu6oXTbzObgV-uU-PKP5egkFQ==",
        "X-Forwarded-For": "73.217.16.234, 216.137.42.129",
        "X-Forwarded-Port": "443",
        "X-Forwarded-Proto": "https"
    },
    "queryStringParameters": {
        "bar": "BarValue",
        "foo": "FooValue"
    },
    "pathParameters": null,
    "stageVariables": null,
    "requestContext": {
        "accountId": "666",
        "resourceId": "xyz",
        "stage": "dev",
        "requestId": "5944789f-ce00-11e6-b2a2-dfdbdba4a4ee",
        "identity": {
            "cognitoIdentityPoolId": null,
            "accountId": null,
            "cognitoIdentityId": null,
            "caller": null,
            "apiKey": null,
            "sourceIp": "73.217.16.234",
            "accessKey": null,
            "cognitoAuthenticationType": null,
            "cognitoAuthenticationProvider": null,
            "userArn": null,
            "userAgent": "insomnia/4.0.12",
            "user": null
        },
        "resourcePath": "/example-path",
        "httpMethod": "POST",
        "apiId": "exampleapiid"
    },
    "body": "{\n  \"foo\": \"FOO\",\n  \"bar\": \"BAR\",\n  \"baz\": \"BAZ\"\n}\n",
    "isBase64Encoded": false
}

コールバック応答形状のサンプル

callback(null, {
  statusCode: 409,
  body: JSON.stringify(bodyObject),
  headers: {
    'Content-Type': 'application/json'
  }
})

- contextなどのメソッドcontext.succeed()は廃止されていると思います。それらはまだ機能しているようですが、もはや文書化されていません。今後は、コールバックAPIへのコーディングが正しいと思います。


これは動作しません。この応答全体の出力で200ステータスが返されます。実際に409ステータスを返すようにAPIを設定できない
Andy N

7

Lambdaのエラーを適切な500エラーにしたかったのですが、多くの調査を行った後、以下のように機能しました。

LAMBDAについて

良い応答のために、私は以下のように戻ります:

exports.handler = (event, context, callback) => {
    // ..

    var someData1 =  {
        data: {
            httpStatusCode: 200,
            details: [
                {
                    prodId: "123",
                    prodName: "Product 1"
                },
                {
                    "more": "213",
                    "moreDetails": "Product 2"
                }
            ]
        }
    };
    return callback(null, someData1);
}

レスポンスが悪い場合は、以下のように返します

exports.handler = (event, context, callback) => {
    // ..

    var someError1 = {
        error: {
            httpStatusCode: 500,
            details: [
                {
                    code: "ProductNotFound",
                    message: "Product not found in Cart",
                    description: "Product should be present after checkout, but not found in Cart",
                    source: "/data/attributes/product"
                },
                {
                    code: "PasswordConfirmPasswordDoesntMatch",
                    message: "Password and password confirmation do not match.",
                    description: "Password and password confirmation must match for registration to succeed.",
                    source: "/data/attributes/password",
                }
            ]
        }
    };

    return callback(new Error(JSON.stringify(someError1)));
}

APIゲートウェイ上

GETメソッドの場合は、/ res1 / service1のGETと言います。

Through Method Response > Add Response, added 3 responses:
- 200
- 300
- 400

そして、

Through 'Integration Response' > 'Add integration response', create a Regex for 400 errors (client error):

Lambda Error Regex    .*"httpStatusCode":.*4.*

'Body Mapping Templates' > Add mapping template as:  
    Content-Type                 application/json  
    Template text box*           $input.path('$.errorMessage')  


Similarly, create a Regex for 500 errors (server error):

Lambda Error Regex    .*"httpStatusCode":.*5.*

'Body Mapping Templates' > Add mapping template as:  
    Content-Type                 application/json  
    Template text box*           $input.path('$.errorMessage')  

ここで、/ res1 / service1を公開します。公開されたURLにアクセスします。これは、上記のラムダに接続されています。

高度なRESTクライアント(またはPostman)Chromeプラグインを使用すると、「httpStatusCode」で指定されたすべてのリクエストに対して、200 HTTP応答コードではなく、サーバーエラー(500)または400などの適切なhttpコードが表示されます。

APIの「ダッシュボード」から、API Gatewayで、次のようなhttpステータスコードを確認できます。

400および500エラー


7

これを行う最も簡単な方法は、LAMBDA_PROXY統合使用することです。この方法を使用すると、API Gatewayパイプラインに設定する特別な変換は必要ありません。

戻りオブジェクトは、以下のスニペットのようにする必要があります。

module.exports.lambdaHandler = (event, context, done) => {
    // ...
    let response = {
        statusCode: 200, // or any other HTTP code
        headers: {       // optional
             "any-http-header" : "my custom header value"
        },
        body: JSON.stringify(payload) // data returned by the API Gateway endpoint
    };
    done(null, response); // always return as a success
};

これにはいくつかの欠点があります。エラー処理に特に注意しなければならず、ラムダ関数をAPI Gatewayエンドポイントに結合する必要があるためです。とはいえ、他の場所で実際に使用しないのであれば、それほど問題にはなりません。


6

この質問にすべてを試してみて、これをうまく機能させることができなかった人(私のように)は、この投稿のthedevkitコメントをチェックしてください(私の一日を保存しました)。

https://forums.aws.amazon.com/thread.jspa?threadID=192918

以下で完全に再現:

私自身もこれに問題があり、改行文字が原因であると思います。

foo。*は、「foo」とそれに続く改行以外の任意の文字の出現に一致します。通常、これは「/ s」フラグ、つまり「foo。* / s」を追加することで解決されますが、Lambdaエラーの正規表現はこれを考慮していないようです。

別の方法として、foo(。| \ n)*のようなものを使用できます。


素晴らしい発見!それはちょうど私の頭を叩く時間を節約しました!そして、それは自明ではありません。
MirkoVukušić2017

ミルコ、助けてくれて嬉しいです!
カルロスバロック2017

2

これは、API Gatewayを使用する場合にAWS Compute Blogで推奨される方法です。統合がLambdaの直接呼び出しで機能するかどうかを確認します。

var myErrorObj = {
    errorType : "InternalServerError",
    httpStatus : 500,
    requestId : context.awsRequestId,
    message : "An unknown error has occurred. Please try again."
}
callback(JSON.stringify(myErrorObj));

Lambdaを直接呼び出す場合、これはクライアント側で解析する最良のソリューションのようです。


例がラムダからラムダへの呼び出しであった場合はどうなりますか?これはまだ呼び出されたラムダが返すものですか?呼び出し元のラムダでそのhttpStatusをどのように読み取ることができますか?
ロッド

1

サーバーレス0.5を使用しています。これは私の場合、それがどのように機能するかです

s-function.json:

{
  "name": "temp-err-test",
  "description": "Deployed",
  "runtime": "nodejs4.3",
  "handler": "path/to/handler.handler",
  "timeout": 6,
  "memorySize": 1024,
  "endpoints": [
    {
      "path": "test-error-handling",
      "method": "GET",
      "type": "AWS_PROXY",
      "responses": {
        "default": {
          "statusCode": "200"
        }
      }
    }
  ]
}

handler.js:

'use strict';
function serveRequest(event, context, cb) {
  let response = {
    statusCode: '400',
    body: JSON.stringify({ event, context }),
    headers: {
      'Content-Type': 'application/json',
    }
  };
  cb(null, response);
}
module.exports.handler = serveRequest;

1

プロキシを使用したくない場合は、次のテンプレートを使用できます。

#set($context.responseOverride.status =  $input.path('$.statusCode'))
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.