リダイレクトするAPI GatewayとLambdaを作ってみた
WebサイトのバックエンドのAPIを作っているとき、次の動作を実現したくなりました。
- リダイレクトしたい
- 条件によって、リダイレクト先のURLを変えたい
単純なリダイレクトであれば、API Gateway単体でも実現可能だと思いますが、DynamoDBのデータ等でリダイレクト先のURLを変更したいのです。 そこで、Lambdaを使って実際に試してみました。
おすすめの方
- AWS SAMでAPIを作りたい方
- AWS SAMでLambdaを作りたい方
- API GatewayとLambdaでリダイレクトしたい方(Lambdaプロキシ統合の場合)
リダイレクトするAPIを作る
sam init
sam init \ --runtime python3.9 \ --name Redirect-Api-Sample \ --app-template hello-world \ --package-type Zip
SAMテンプレート
AWSTemplateFormatVersion: '2010-09-09' Transform: AWS::Serverless-2016-10-31 Description: Redirect-Api-Sample Resources: HelloWorldFunction: Type: AWS::Serverless::Function Properties: CodeUri: hello_world/ Handler: app.lambda_handler Runtime: python3.9 Architectures: - x86_64 Timeout: 5 Events: HelloWorld: Type: Api Properties: Path: /hello Method: get HelloWorldFunctionLogGroup: Type: AWS::Logs::LogGroup Properties: LogGroupName: !Sub /aws/lambda/${HelloWorldFunction} Outputs: HelloWorldApi: Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/hello/"
Lambdaコード
HTTPステータスを303にして、Location
ヘッダーを付与しているだけです。
def lambda_handler(event, context): # ここでなにか処理をして、その結果によってLocationを変更する、など return { "statusCode": 303, "headers": { "Location": "https://dev.classmethod.jp/" } }
デプロイ
sam build sam package \ --output-template-file packaged.yaml \ --s3-bucket cm-fujii.genki-deploy sam deploy \ --template-file packaged.yaml \ --stack-name Redirect-Api-Sample-Stack \ --s3-bucket cm-fujii.genki-deploy \ --capabilities CAPABILITY_NAMED_IAM \ --no-fail-on-empty-changeset
APIエンドポイント(URL)の取得
aws cloudformation describe-stacks \ --stack-name Redirect-Api-Sample-Stack \ --query 'Stacks[].Outputs'
動作確認
取得したURLにブラウザでアクセスすると、DevelopersIOにリダイレクトされました。 curlコマンドで確認すると、HTTPステータスとLocationヘッダーがありました。
$ curl -D - https://xxx.execute-api.ap-northeast-1.amazonaws.com/Prod/hello/ HTTP/2 303 content-type: application/json content-length: 0 location: https://dev.classmethod.jp/ 略
Lambdaエラーの場合
Lambdaでエラー発生したことを想定して、動作確認してみます。
def lambda_handler(event, context): raise NotImplementedError()
この場合は、Internal Server Error
のメッセージが返ってきます。
curlコマンドで確認すると、HTTPステータスは502です。
$ curl -D - https://xxx.execute-api.ap-northeast-1.amazonaws.com/Prod/hello/ HTTP/2 502 content-type: application/json content-length: 36 略 {"message": "Internal server error"}
これは、API GatewayをLambdaを「Lambdaプロキシ統合」で利用しているためです。 「Lambdaプロキシ統合」では、LambdaがAPI Gatewayに対して、想定されたResponseを返す必要があります。 しかし、Lambda自体がエラーになった場合は、想定されたResponseをAPI Gatewayに返せないため、API Gateway側で502が発生しています。
関数出力が別の形式である場合、API Gateway は 502 Bad Gateway エラーレスポンスを返します。
https://docs.aws.amazon.com/ja_jp/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html#api-gateway-simple-proxy-for-lambda-output-format