🍵

Serverless Framework で任意のステータスコードを返す API を作る

2021/09/26に公開

Lambda プロキシ統合を使って任意の HTTP ステータスコードを返す API を作りたいだけなのに、はっきりこれだという情報を見つけられなかったので書いておく。

公式ドキュメントを見るのが手っ取り早い。
https://www.serverless.com/framework/docs/providers/aws/events/apigateway#status-codes
つまり Lambda で { statusCode: 404, body: "msg" } という JSON を返すだけ。

※ Lambda プロキシ統合でない場合 integration: lambda の場合は面倒なのでおすすめしない。
※ Lambda プロキシ統合 integration: lambda_proxy はデフォルトなので省略可
※ HTTP ステータスコードについては HTTP レスポンスステータスコード - HTTP | MDN を参照のこと。

Serverless Framework のデプロイ

以下のような serverless.yml と hanlder.py を用意して sls deploy --aws-profile <your_profile> してあげれば teapot になりきることも可能。
というか軽い気持ちでステータスコードを調べたら、大量に知らないステータスコードが出てきて焦った。

curl -i -X GET https://your_apigw_id.execute-api.ap-northeast-1.amazonaws.com/dev/status?c
ode=418
HTTP/2 418
content-type: application/json
content-length: 13
date: Sun, 26 Sep 2021 11:08:53 GMT
x-amzn-requestid: aec3359e-5e8b-4358-bbcf-XXXXXXXXXXX2
x-amz-apigw-id: GRIu6FgttjMFUAA=
x-amzn-trace-id: Root=1-615054c5-48d2867864cfe4de591XXXXX;Sampled=0
x-cache: Error from cloudfront
via: 1.1 1e25bd98fa0bda7498f5119d7dcXXXXX.cloudfront.net (CloudFront)
x-amz-cf-pop: NRT51-C3
x-amz-cf-id: WEG7QPCeJnqVv_RLjbJjmdbIvbL--xGu0XsMBH8N1QjZYpNKXXXXXA==

I'm a teapot

serverless.yml

service: api-response-codes
provider:
  name: aws
  runtime: python3.9
  region: ap-northeast-1
  lambdaHashingVersion: "20201221"
  stage: dev

package:
  patterns:
    - "!**"
    - handler.py

functions:
  handler:
    handler: handler.lambda_handler
    events:
      - http:
          method: get
          path: /status

handler.py

def lambda_handler(event, context):
    try:
        code = int(event.get("queryStringParameters", {}).get("code"))
    except:
        code = 200

    # see https://developer.mozilla.org/ja/docs/Web/HTTP/Status
    msg = {
        100: "Continue",
        101: "Switching Protocol",
        102: "Processing",
        103: "Early Hints",
        200: "OK",
        201: "Created",
        202: "Accepted",
        203: "Non-Authoritative Information",
        204: "No Content",
        205: "Reset Content",
        206: "Partial Content",
        207: "Multi-Status",
        208: "Already Reported",
        226: "IM Used",
        300: "Multiple Choice",
        301: "Moved Permanently",
        302: "Found",
        303: "See Other",
        304: "Not Modified",
        305: "Use Proxy",
        306: "unused",
        307: "Temporary Redirect",
        308: "Permanent Redirect",
        400: "Bad Request",
        401: "Unauthorized",
        402: "Payment Required",
        403: "Forbidden",
        404: "Not Found",
        405: "Method Not Allowed",
        406: "Not Acceptable",
        407: "Proxy Authentication Required",
        408: "Request Timeout",
        409: "Conflict",
        410: "Gone",
        411: "Length Required",
        412: "Precondition Failed",
        413: "Payload Too Large",
        414: "URI Too Long",
        415: "Unsupported Media Type",
        416: "Range Not Satisfiable",
        417: "Expectation Failed",
        418: "I'm a teapot",
        421: "Misdirected Request",
        422: "Unprocessable Entity",
        423: "Locked",
        424: "Failed Dependency",
        425: "Too Early",
        426: "Upgrade Required",
        428: "Precondition Required",
        429: "Too Many Requests",
        431: "Request Header Fields Too Large",
        451: "Unavailable For Legal Reasons",
        500: "Internal Server Error",
        501: "Not Implemented",
        502: "Bad Gateway",
        503: "Service Unavailable",
        504: "Gateway Timeout",
        505: "HTTP Version Not Supported",
        506: "Variant Also Negotiates",
        507: "Insufficient Storage",
        508: "Loop Detected",
        510: "Not Extended",
        511: "Network Authentication Required",
    }.get(code, "Hello Unknown StatusCode!")

    return dict(
        statusCode=code,
        body=f"{msg}\n",
    )

Discussion