この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
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テンプレート
template.yaml
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
ヘッダーを付与しているだけです。
app.py
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でエラー発生したことを想定して、動作確認してみます。
app.py
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