はじめに
私たちのチームでは、企業が利用している人事システムなどのデータを取り込み、集計して、人的資本にまつわる様々な指標を表示したり、業界平均などと比較することのできるWebアプリケーションを開発しています。
WebアプリケーションのAPI(サーバーサイド)を、API Gateway + Lambda(Python)で構成しています。
その際に、 aws-lambda-powertools を使って、とても便利だと感じたので、紹介します。
なお、この記事で紹介する aws-lambda-powertools の機能は、バージョン2.15.0時点のものです。
便利な点の紹介
この記事では、実際にアプリケーションで利用しているLambdaのソースコードを用いて、 aws-lambda-powertools の便利な使い方を紹介していきます。
from http import HTTPStatus
from _types.errors import ClientError
from aws_lambda_powertools import Logger
from aws_lambda_powertools.utilities.data_classes import APIGatewayProxyEvent, event_source
from aws_lambda_powertools.utilities.parser import parse
from aws_lambda_powertools.utilities.typing import LambdaContext
from handlers.middleware_after import middleware_after
from handlers.tracer import tracer
logger = Logger(service="hci", log_uncaught_exceptions=True) # 便利な点① ロギング
@tracer.capture_lambda_handler # 便利な点② トレース
@logger.inject_lambda_context()
@middleware_after # 便利な点③ ミドルウェア
@event_source(data_class=APIGatewayProxyEvent)
def lambda_handler(event: APIGatewayProxyEvent, context: LambdaContext):
tenant_id = event["requestContext"]["authorizer"]["tenant_id"]
logger.info(f"tenant_id: {tenant_id}")
request = parse(event=event["body"], model=CompanyCreateRequest) # 便利な点④ リクエストのパース
# ...省略...
try:
usecase.create(command)
return {"statusCode": HTTPStatus.NO_CONTENT.value}
except ClientError as e:
logger.error(e)
return {"statusCode": HTTPStatus.BAD_REQUEST.value, "body": e.message}
便利な点① トレース(参照)
使い方は以下の2ステップです。
- aws-lambda-powertoolsからインポートしたTracerクラスのインスタンス化
- handler関数へのデコレータの追加
これだけで、APIリクエストのトレース情報がCloudWatchに送られます。
APIリクエストによって実行されるLambda AuthorizerやLambda、DynamoDBへのアクセスにかかる時間などが確認できます。
Lambdaを利用してAPIを構築すると、API GatewayやLambda Authorizer、Lambdaなどさまざまなサービスに分散して処理が行われるため、エラー原因の特定が面倒だったり、レスポンス速度のボトルネックの発見が難しかったりします。
トレースを確認することで、これらの発見がいとも簡単に行えます!
便利な点② ロギング(参考)
使い方は以下の3ステップです。
- aws-lambda-powertoolsからインポートしたLoggerクラスのインスタンス化
- handler関数へのデコレータの追加
- ロジック内で利用
ロジック内に自分で記述したログだけでなく、以下のようなLambda関数の情報もログ出力することができます。
Lambdaのコールドスタートの情報などもわかって良いですね!
{
"level": "INFO",
"location": "lambda_handler:35",
"message": "tenant_id: 19206e1e-9d9a-4301-b81c-xxxxxxxxxx",
"timestamp": "2024-03-23 13:31:42,315+0000",
"service": "hci",
"cold_start": true,
"function_name": "companies-create",
"function_memory_size": "128",
"function_arn": "arn:aws:lambda:ap-northeast-1:xxxxxxxxxxxx:function:companies-create",
"function_request_id": "69423838-9cb7-4376-9996-7c439df6d855",
"xray_trace_id": "1-64d243bc-xxxxxxxxxx"
}
ログ内に記載された xray_trace_id
を利用することで、CloudWatch の X-Ray トレースの画面から簡単に該当リクエストのトレースを検索できます。
便利な点③ ミドルウェア(参考)
使い方は以下の2ステップです。
- ミドルウェア関数の定義(後述)
- handler関数へのデコレータの追加
ミドルウェアを利用することで、handler関数の処理の前後に別の処理を実行することができます。
今回の例では、以下のようにミドルウェア関数を定義し、handler関数が返還するレスポンスのヘッダーにCORSポリシーを設定しています。
from typing import Callable
from aws_lambda_powertools.middleware_factory import lambda_handler_decorator
from config.index import FRONT_ORIGIN
@lambda_handler_decorator
def middleware_after(handler, event, context) -> Callable:
response = handler(event, context)
response["headers"] = {"Access-Control-Allow-Origin": FRONT_ORIGIN}
return response
LambdaでAPIを構築すると、とても多くのLambdaが作られると思いますが、お決まりの処理をミドルウェアで行うことで、実装コストが下がってとても良いです!
便利な点④ リクエストのパース(参考)
使い方はたった1つ、 aws-lambda-powertool からインポートした parse 関数にリクエストボディとPydanticのモデルクラスを渡すだけです。
これだけで、リクエストボディを検証することができ、また後続で型定義された情報を利用して処理することができます。
便利!!
おわりに
実際の開発で利用した aws-lambda-powertools の機能をご紹介しました。
まだまだたくさんの機能があるので、どんどん使っていきたいと思います!