🐍

Python+AWS serverless+DDDでのAPI開発環境構築の自分の方針

2024/09/21に公開

概要&動機

Python + AWS serverlessでのAPI開発のテンプレートレポジトリを作った。
gRPCを使った開発もやってみたくなり、Lambdaの開発から少し離れそうなので、開発環境方針の自分用メモとしてもまとめてみた。

ただし、全然いけてない点も多々あるがこだわり続けても終わりがないので、プロジェクトごとにカスタマイズしながら使う前提のベース的なテンプレートとして作成した。
とりあえず、API Gateway/Lambda/DynamoDBでの構成。

あとは、記事書いたことがなかったので、とりあえず何かしら記事を書いてみたかった。

重視した点

  • できるだけシンプルに
  • できるだけLambdaのコーディング以外の作業をしなくていいように
  • VSCodeにはロックインしていく
  • チーム開発というよりは個人開発を想定

テンプレート内容

レポジトリはこちら

devcontainer

buildpack-depsイメージをベースにfeatureで拡張していく

公式のbase-debianをベースにしても良かったが、dotfilesでzsh環境を構築しているのでOh my zshのインストールをさせたくなかった。
uvを使ってstandaloneのpythonを使用するので、pythonイメージを使う必要もない。

nodeはCDK用、docker-in-dockerはCDKでのLambdaビルド用に追加。

Python環境

uv

最近uvでもプロジェクト管理できるようになったということで、ryeから移行。

ruff

とりあえず全部enableに。
公式ドキュメントでdisable推奨のものだけdisableにしている。

mypy

PEP 695のsyntaxを一部使用しているので以下を設定。
enable_incomplete_feature = "NewGenericSyntax"

pytest

motoを使用し、DynamoDB等をmockする。
Lambdaの環境変数を設定する必要があるのでpytest-envを使用。

jupyter

libraryや関数などのちょっとした挙動確認などで、REPLで確認するのが面倒な時に、notebookだと快適に確認できるので用意している。

Lambda実装

DDD

DDD + Onion Architectureを採用。

modelなどはpydanticを使用し、validation等を行う。

個人開発だと簡単なものでもDDDライクに作っちゃう。
マインドとしては、扱う対象を自然な形で表現しつつ、domainロジック/applicationロジック/外部接続ロジックは疎結合にしておきたいなーくらいの感じ。

ちなみに、このレポジトリの実装は適当なのであまり参考にしないこと。
例えば、get projectなんかは1クエリで取れるようにDB設計してあるので、実際はCQRSを採用したりして、1クエリで取得する。

API handler

基本的に1 Lambdaでaws-lambda-powertoolsを使用してroutingする方針。

TL;DR. Start with a monolithic function, add additional functions with new handlers, and possibly break into micro functions if necessary.

ここで言われているようにmonolithicをベースに考えている。
分割判断としては、まずbounded context、次にアクセスパターンやメモリ要求によって、みたいな感じ?

同じcontext内で分割する場合はhandler以外のロジック(レポジトリ内のcoreに当たる部分)はLambda layerに置く。

Documentation

Material for MkDocsを使用。

mkdocstrings

実装のdocstringからリファレンスを自動生成。

OpenAPI

aws-lambda-powertoolsの機能でhandler実装を基に、OpenAPIスキーマを自動生成してくれるのでそれを利用して生成。

現状、1 Lambdaでの実装にしか対応していない。
ただ、pydanticモデルでもOpenAPIスキーマ出力できるので、複数Lambda実装でもmergeするスクリプトを書けば、割と簡単に対応できそう。

json/yamlを書く代わりに空のhandlerコードを書くという風にすれば、スキーマ駆動開発もできるかと。

Test coverage

Pytestの結果をhtml出力し、それを利用している。

CDK

API GatewayのRoute構成は実装から反映(Documentationと同じくaws-lambda-powertoolsのOpenAPI生成を利用)。
DynamoDBのindex設定も実装から反映。

LambdaにADOT(OpenTelemetry)を使用しているが、活用はまだできてない。

CI/CD

pre-commit

ruffのlint/formatを実行

Github Actions

  • mkdocsのビルド
  • CDK deployの実行

その他検討事項

  • localStack
    ローカルにserveして動作確認等したいが、cognitoなど使ったりするとfree版で対応できなくなってくる。
    なので、現状はとりあえずはmotoでできるだけ確認し、あとはAWS環境で。

  • DynamoDBのdocumentation
    DynamoDBのindex設計を自動documentationしてもいいかもだが、未着手

  • AWS構成図
    PDKというものが使えそう。だが、未着手

終わりに

自分以外の人が読んで理解できる記事になったかは分からないが、これからのアウトプット活動の一歩目としてアウトプットを習慣化できるようにしたい。

Discussion