Instruction file imported from sugiyama404/practice_local_lambda_for_flask (
.github/instructions/lambda-architecture.instructions.md). Copyright stays with the author.
Lambda アーキテクチャ(完成版)
全体設計
- 依存方向は
api/adapters→api/functions/**に保つ。 api/functions/**は Flask に依存しない(flask.requestの import 禁止)。- Flask は
api/adapters/http_flask.pyのみで使用し、HTTP ⇄ event 変換のみを責務とする。 - Lambda の入力は API Gateway HTTP API v2 互換の event とする。
- event の生成および
parse_body()はapi/adapters/event_builder.pyに集約する。 - レスポンスは API Gateway 互換の dict(
statusCode,body)とする。 - Flask では
response_mapperにより HTTP レスポンスへ変換する。
Lambda ハンドラ設計
基本構造(全ハンドラ共通)
def lambda_handler(event, context):
return safe_execute(execute, event)
def execute(event):
data = validate(event)
result = process(data)
return success(result)
def validate(event):
# 入力検証
# parse_body() を使用
# エラー時は BadRequest を raise
...
return validated_data
def process(data):
# ビジネスロジックのみを記述
# HTTPレスポンスやevent構造を意識しない
...
return result
設計ルール(重要)
lambda_handlerは エントリポイントとして safe_execute を呼ぶだけの薄い関数とする。- エラーハンドリングおよびレスポンス生成は
safe_executeに委譲する。 execute()は「validate → process → success」の流れに統一する。process()は純粋なビジネスロジックのみを扱い、副作用(DB・外部API)は許容するが、HTTPレスポンス形式を扱わない。validate()は必ず dict を返す(None禁止)。validate()は event を直接受け取り、parse_body()を利用する。- バリデーションエラーは必ず
BadRequestを raise する。
エラーハンドリング設計
例外クラス
-
BadRequest- 入力不正(JSON不正、必須フィールド不足、型不正)
-
DomainError- 業務的に不正な状態
- 例:残高不足、重複データ、存在しないリソース
-
Exception- 予期しないエラー(500)
safe_execute(共通ランタイム)
配置:api/common/runtime.py
def safe_execute(func, event):
try:
return func(event)
except BadRequest as e:
return error(400, str(e))
except DomainError as e:
return error(400, str(e))
except Exception:
return error(500, "internal error")
レスポンスヘルパー
def success(data):
return {
"statusCode": 200,
"body": json.dumps(data)
}
def error(status_code, message):
return {
"statusCode": status_code,
"body": json.dumps({"error": message})
}
parse_body 仕様
api/adapters/event_builder.py
def parse_body(event):
raw = event.get("body")
if raw is None or raw == "":
return {"_type": "empty"}
try:
return {"_type": "json", "data": json.loads(raw)}
except (json.JSONDecodeError, TypeError):
return {"_type": "invalid"}
戻り値
{"_type": "empty"}{"_type": "json", "data": {...}}{"_type": "invalid"}
validate 実装ルール
parse_body()を必ず使用する_typeによって分岐する- invalid → BadRequest
- 必須フィールド不足 → BadRequest
- 型不正 → BadRequest
- 正常時のみ dict を返す
Flask アダプタ
api/adapters/http_flask.pyのみが Flask を使用可能- 処理内容:
event = from_flask_request(request)
response = lambda_handler(event, None)
return to_flask_response(response)
- ビジネスロジックは禁止
初期化とパフォーマンス
- boto3 クライアント、DB接続、設定値はモジュールスコープで初期化
- Execution Environment Reuse を前提とする
ログ設計
- JSON形式の構造化ログを使用
- エラー時は stack trace を記録
- ログレベルは環境変数で制御
設計原則まとめ
- event中心設計
- adapter分離
- handler最小化
- 例外ベース制御
- 単一責務
- 過剰抽象化禁止
禁止事項
- handler内で直接 HTTPレスポンスを組み立てること
- Flask依存を functions 層に持ち込むこと
- Pydanticなど重い外部バリデーションライブラリの導入
- event構造を無視した独自設計
完了条件
- 全Lambdaが統一構造に従っている
- バリデーションが共通化されている
- エラーハンドリングが例外ベースで統一されている
- Flaskは完全にアダプタとして分離されている