27
11

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

はじめに

私たちのチームでは、企業が利用している人事システムなどのデータを取り込み、集計して、人的資本にまつわる様々な指標を表示したり、業界平均などと比較することのできる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ステップです。

  1. aws-lambda-powertoolsからインポートしたTracerクラスのインスタンス化
  2. handler関数へのデコレータの追加

これだけで、APIリクエストのトレース情報がCloudWatchに送られます。
APIリクエストによって実行されるLambda AuthorizerやLambda、DynamoDBへのアクセスにかかる時間などが確認できます。
スクリーンショット 2024-03-27 23.20.28.png

Lambdaを利用してAPIを構築すると、API GatewayやLambda Authorizer、Lambdaなどさまざまなサービスに分散して処理が行われるため、エラー原因の特定が面倒だったり、レスポンス速度のボトルネックの発見が難しかったりします。
トレースを確認することで、これらの発見がいとも簡単に行えます!

便利な点② ロギング(参考

使い方は以下の3ステップです。

  1. aws-lambda-powertoolsからインポートしたLoggerクラスのインスタンス化
  2. handler関数へのデコレータの追加
  3. ロジック内で利用

ロジック内に自分で記述したログだけでなく、以下のような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ステップです。

  1. ミドルウェア関数の定義(後述)
  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 の機能をご紹介しました。
まだまだたくさんの機能があるので、どんどん使っていきたいと思います!

27
11
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
27
11

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?