はじめに
LambdaでHTTP接続する際、URLのパスで処理を変えたいと思い試した内容を記事にします。
参考
概要
前提として、Pythonを用いています。
以下の2つのやり方を見つけました。
- AWSGIを使う方法
- LambdaでFlaskを使える
- API Gateway経由のeventを処理可能
- Function URLのeventはできない
- AWS Lambda Powertoolsを使う方法
- ユーティリティーのライブラリ
- 今回のイベントハンドラ以外のユーティリティも提供
- Python以外の言語でも提供
- API Gateway経由のeventも、Function URLのeventも可能
- 未検証だが、ALB経由のも可能な模様
- ユーティリティーのライブラリ
やってみた
いずれの方法もAWS SAMを用いています。私はCloud9上で行いました。
AWSGIを使う方法
使い方は以下のページにありますので、そちらをご参考ください。
Flaskを使われていた方には、いいかもしれません。
AWS Lambda Powertoolsを使う方法
以下のページを参考に、コードを書いてみました。
まず使用するフォルダ、ファイルを作ります。
mkdir -p sample-lambda_powertools/functions && cd sample-lambda_powertools
touch functions/app.py
touch functions/requirements.txt
touch template.yaml
それぞれのファイルに記載していきます。
まずはインポートするモジュールを宣言します。
aws-lambda-powertools
Function URLの場合
Function URLの場合は、LambdaFunctionUrlResolver
を用います。
from aws_lambda_powertools.event_handler import LambdaFunctionUrlResolver
app = LambdaFunctionUrlResolver()
@app.get("/")
def get_home():
return "get_home"
@app.post("/")
def post_home():
return "post_home"
@app.put("/")
def put_home():
return "put_home"
@app.delete("/")
def delete_home():
return "delete_home"
@app.get("/hello")
@app.post("/hello")
def hello():
return "hello"
@app.get("/hello/<inputname>")
@app.post("/hello/<inputname>")
def hello_withname(inputname : str):
return f"hello {inputname}!"
def lambda_handler(event, context):
print('sample function')
return app.resolve(event, context)
Function URLを持つLambdaを作るSAMのテンプレートは以下になります。
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: SAM Template for Lambda Function
Resources:
TargetFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri: functions/
Handler: app.lambda_handler
Runtime: python3.9
TargetFunctionUrl:
Type: AWS::Lambda::Url
Properties:
AuthType: NONE
TargetFunctionArn: !GetAtt TargetFunction.Arn
TargetFunctionUrlPermission:
Type: AWS::Lambda::Permission
Properties:
Action: lambda:InvokeFunctionUrl
FunctionName: !GetAtt TargetFunction.Arn
FunctionUrlAuthType: NONE
Principal: "*"
FunctionLogGroup:
Type: AWS::Logs::LogGroup
Properties:
LogGroupName: !Sub /aws/lambda/${TargetFunction}
RetentionInDays: 3653
Outputs:
FunctionUrl:
Value: !GetAtt TargetFunctionUrl.FunctionUrl
Export:
Name: TargetFunctionUrl
あとはBuildしてDeployです。
sam build && sam validate
sam deploy --guided
CURLコマンドで確かめられられます。
curl -X POST [関数URL]
curl -X POST [関数URL]/hello
curl -X POST [関数URL]/hello/taro
API Gatewayの場合
API Gatewayを使う場合は、APIGatewayRestResolver
を用います。
他の部分はFunction URLのコードと変わらないです。
from aws_lambda_powertools.event_handler import APIGatewayRestResolver
app = APIGatewayRestResolver()
@app.get("/")
def get_home():
return "get_home"
@app.post("/")
def post_home():
return "post_home"
@app.put("/")
def put_home():
return "put_home"
@app.delete("/")
def delete_home():
return "delete_home"
@app.get("/hello")
@app.post("/hello")
def hello():
return "hello"
@app.get("/hello/<inputname>")
@app.post("/hello/<inputname>")
def hello_withname(inputname : str):
return f"hello {inputname}!"
def lambda_handler(event, context):
print('sample function')
return app.resolve(event, context)
SAMテンプレートは以下になります。
AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: SAM Template for Lambda Function
Resources:
TargetFunction:
Type: AWS::Serverless::Function
Properties:
CodeUri: functions/
Handler: app.lambda_handler
Runtime: python3.9
Events:
ApiRoot:
Type: Api
Properties:
Path: '/'
Method: ANY
ApiProxy:
Type: Api
Properties:
Path: '/{proxy+}'
Method: ANY
FunctionLogGroup:
Type: AWS::Logs::LogGroup
Properties:
LogGroupName: !Sub /aws/lambda/${TargetFunction}
RetentionInDays: 3653
Outputs:
TargetdApi:
Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/"
あとはBuildとDeployで作成し、CURLコマンドで確かめられます。
おわりに
Flaskを勉強していた流れで知った知識であり、色々使いどころがありそうです。
ただ、1つの関数をリッチにしがちになりそうなので、そこは注意が必要かと感じます。