はじめに
Python / Lambda / DynamoDB / ServerlessFramework でのAPI開発手順を記しておきます。
AWSの方から「Lambda × Pythonは起動が速く(コールドスタートが起きない)相性がいい」と伺っていたので、デプロイして計測するのが楽しみです!
環境
- macOS Ventura
- Python 3.11.4
- ServerlessFramework 3.34.0
- npm 8.19.2
- node v18.18.0
$ python3 --version
$ python3 -m pip -V
Lambda作成
1. 事前準備
$ mkdir project-v1 #プロジェクト用ルートディレクトリ作成
$ npm install -g serverless #必要なプラグインのインストール
$ npm install --save serverless-iam-roles-per-function serverless-offline serverless-prune-plugin
$ sls plugin install -n serverless-python-requirements
$ sls plugin install -n serverless-dynamodb
$ sls dynamodb install
$ sls create --template aws-python3 #Serverlessプロジェクトを作成
※去年使用していた serverless-dynamodb-local はもう使えないようです(npm参照)。
2. Serverless定義
可読性・メンテナンス性を考慮し、定義元ファイルを個別に分けています。
service: project-v1
frameworkVersion: '3'
provider:
name: aws
runtime: python3.11
region: ap-northeast-1
stage: stg
plugins:
- serverless-dynamodb
- serverless-offline # dynamodb より offline を後ろに記載
- serverless-iam-roles-per-function
- serverless-prune-plugin
- serverless-python-requirements
custom:
stage: ${opt:stage, self:provider.stage}
dynamodb: ${file(./config/setting.yml):dynamodb}
seed: ${file(./config/setting.yml):dynamodb.seed}
resources: ${file(./config/resources.yml)}
serverless-offline:
stage: "local"
prune:
automatic: true
number: 5
resources:
- ${file(./config/dynamodb.yml)}
functions:
Hello:
handler: main.handlers.handler.lambda_handler
name: Hello
description: Pythonテスト
events:
- http:
path: hello
method: GET
cors: true
iamRoleStatements:
- ${file(./config/iam.yml):getItemTables}
以下、serverless.yml内で読み込む複数ファイルを定義
dynamodb:
stages:
- local
port: 8000
docker: false
start:
inMemory: true
migrate: true
seed: true
seed:
test:
sources:
- table: ${self:custom.resources.HogesTable.name}
sources: [./main/resources/migrations/Hoges.json]
- table: ${self:custom.resources.FugasTable.name}
sources: [./main/resources/migrations/Fugas.json]
Resources:
HogesTable:
Type: AWS::DynamoDB::Table
////
FugasTable:
Type: AWS::DynamoDB::Table
////
HogesTable:
name: Hoges
arn: "arn:aws:dynamodb:${aws:region}:${aws:accountId}:table/Hoges*"
FugasTable:
name: Fugas
arn: "arn:aws:dynamodb:${aws:region}:${aws:accountId}:table/Fugas*"
getItemTables:
Effect: Allow
Action:
- dynamodb:getItem
Resource:
- ${self:custom.resources.HogesTable.arn}
3. boto3 (AWS SDK for Python) インストール
$ pip3 install boto3
##Successfully installed boto3-1.28.59 botocore-1.31.59 jmespath-1.0.1 python-dateutil-2.8.2 s3transfer-0.7.0 six-1.16.0 urllib3-1.26.17
4. Handler作成
import json
from main.models.aws_dynamodb import AwsDynamoDb
def lambda_handler(event, context):
dynamoDb = AwsDynamoDb()
hoges = dynamoDb.get_item("table_name", "sk_name", "sk_value")
print(f"Hoges: {hoges}")
return {"statusCode": 200, "body": json.dumps(hoges)}
5. AwsDynamoDbクラス作成
import boto3
class AwsDynamoDb:
def __init__(self):
self.dynamodb = boto3.resource(
"dynamodb",
region_name="ap-northeast-1",
endpoint_url="http://localhost:8000",
)
# 値を一つ取得
def get_item(self, table_name, key, value):
try:
table = self.dynamodb.Table(table_name)
item = table.get_item(Key={key: value})
return item.get("Item")
except Exception as e:
print(f"Error getting item from DynamoDB: {e}")
return "エラー"
挙動確認
1. ローカル起動
$ sls offline start --stage local
$ sls dynamodb start --stage local
2. 疎通確認
$ curl http://localhost:3000/local/hello
参考
さいごに
サクッとAPI開発するのなら、とりあえず上記で試すのはありかなと思っています。
sls
や npm
でのインストールは、インストール時期によって使えない場合もあるので、公式ドキュメントをご確認ください。
Java歴約2年で、Pythonを使うのは初めてでした。
本記事には数行しかPython記述はないですが、これから外部連携したり、大きくしたりで開発続けます。
ユニットテスト・規約チェック・ログ関連・バージョン管理ツールは入れる予定です。
ディレクトリ構造の最適解はまだ持ち合わせていません。
ここ間違ってるよ!もっとこうしたらどう?といったご指摘やアドバイスはいつでも歓迎です!
(感想)2年半前のRuby以来の「動的型付け言語」でした。
🙆♀️
記述量少なくて済むの感激!書きやすい読みやすい!
(データ型の宣言ないことは少し違和感、、完全にJavaに慣れてしまいました)
🙅♀️
エラーやバグが、コンパイルではなくプログラム実行時にしか分からない。
コンパイルに時間を要すのは退屈だったけど、そこでエラー教えてくれるのありがたかった。
結果、どちらも一長一短で楽しいです。もう少しPython続けてみます。