0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

【CDK】 色んな言語でCRUD API作る【Python】

Posted at

この記事について

AWS CDKv2でCRUD操作ができるAPIを作る
今回はPythonを使う

プロジェクト初期化

CLIのインストール

CLI自体はnodeのものを使う(ので導入済みならスキップ)

npm install -g aws-cdk
cdk --version

バージョンが表示されればOK

CDK Toolkitのデプロイ

初回のみCDKを利用する際に必要となるファイル群のデプロイが必要
→これもやったことがあるならスキップ

cdk bootstrap aws://${ACCOUNT}/${REGION}

以下のように表示されればOK

✅  Environment aws://${ACCOUNT}/${REGION} bootstrapped.

※異なるアカウント、リージョンでCDKを利用する場合はまたこの作業が必要になる

プロジェクト初期化

適当なディレクトリで↓を実行

cdk init app --language python

こんな感じでプロジェクトが初期化される

スクリーンショット 2022-07-04 174309.jpg

モジュールのインストール

venvを使って仮想環境にモジュールをインストールする

python3 -m venv .venv
source .venv/bin/activate

これで仮想環境が立ち上がる
次にインストールするモジュールのリスト(requirements.txt)を更新

requirements.txt
aws-cdk-lib==2.29.1
constructs>=10.0.0,<11.0.0
aws_cdk.aws_lambda_python_alpha

そうしたらpipインストールする

pip install -r requirements.txt

実装

CDKのコードを書く

/todoapp_py/todoapp_py_stack.py
from aws_cdk import (
    RemovalPolicy,
    Stack,
    aws_dynamodb as dynamodb,
    aws_iam as iam,
    aws_lambda,
    aws_lambda_python_alpha,
    aws_logs as logs,
    aws_apigateway as apigateway
)
from constructs import Construct


class TodoappPyStack(Stack):

    def __init__(self, scope: Construct, construct_id: str, **kwargs) -> None:
        super().__init__(scope, construct_id, **kwargs)

        # DynamoDB
        todos_table = dynamodb.Table(
            self,
            'TodosTable',
            table_name='todoapp-py-todos-table',
            partition_key=dynamodb.Attribute(
                name='id',
                type=dynamodb.AttributeType.STRING
            ),
            removal_policy=RemovalPolicy.DESTROY)

        # Lambda
        todo_function = aws_lambda_python_alpha.PythonFunction(
            self,
            'TodoFunction',
            runtime=aws_lambda.Runtime.PYTHON_3_9,
            entry='src',
            index='main.py',
            handler='handler',
            function_name='todoapp-py-function',
            environment={
                'TODOS_TABLE_NAME': todos_table.table_name
            },
        )
        # LambdaにDynamoDBのCRUD操作権限を付与
        todo_function.add_to_role_policy(iam.PolicyStatement(
            effect=iam.Effect.ALLOW,
            actions=[
                'dynamodb:Scan',
                'dynamodb:PutItem',
                'dynamodb:UpdateItem',
                'dynamodb:DeleteItem',
            ],
            resources=[todos_table.table_arn]
        ))

        # LogGroup
        logs.LogGroup(self,
                      'TodoFunctionLogs',
                      log_group_name='/aws/lambda/' + todo_function.function_name,
                      removal_policy=RemovalPolicy.DESTROY)

        # API Gateway
        api = apigateway.RestApi(self,
                                 'TodoAPI',
                                 rest_api_name='todoapp-py-api',
                                 default_cors_preflight_options=apigateway.CorsOptions(
                                     allow_origins=apigateway.Cors.ALL_ORIGINS,
                                     allow_methods=apigateway.Cors.ALL_METHODS,
                                     allow_headers=apigateway.Cors.DEFAULT_HEADERS,
                                     status_code=200
                                 ))
        integration = apigateway.LambdaIntegration(todo_function)

        # /todos
        todos_resource = api.root.add_resource('todos')
        todos_resource.add_method('GET', integration=integration)
        todos_resource.add_method('POST', integration=integration)

        # /todos/{id}
        todo_id_resource = todos_resource.add_resource('{id}')
        todo_id_resource.add_method('PUT', integration=integration)
        todo_id_resource.add_method('DELETE', integration=integration)

前回TypeScriptで実装した時とほぼいっしょ
Lambdaを定義している箇所は少々ややこしいので↓に抜き出して補足する

aws_lambda_python_alphaについて

todo_function = aws_lambda_python_alpha.PythonFunction(
    self,
    'TodoFunction',
    runtime=aws_lambda.Runtime.PYTHON_3_9,
    entry='src',
    index='main.py',
    handler='handler',
    function_name='todoapp-py-function',
    environment={
        'TODOS_TABLE_NAME': todos_table.table_name
    },
)
  • entry
    • Lambdaのソースコードがあるディレクトリを指定する
  • index
    • Lambdaのエントリーポイントとなるファイル名を指定する
  • handler
    • Lambdaのエントリーポイントとなる関数名を指定する

端的に言うと、↑のように書いた場合はここをLambdaのエントリーポイントとして、
ここを参照してモジュールをインストールしアップロードしてくれる

※ドキュメントも参照

Lambdaのコード実装

こちらのサンプルコードを参照
ルーティングをFlaskで、API Gatewayとの結合をawsgiで実装した

デプロイ

↓を実行

cdk deploy TodoappPyStack

動作確認

↓を実行

export ENDPOINT="API Gatewayのエンドポイント"
bash tests/test.bash

感想

CDKのコードは概ねTypeScriptで実装した時と同じ感覚で書けた
唯一Lambdaは割と勝手が違っていたので少々躓いた

※aws_lambda_nodejsとaws_lambda_python_alphaの差分

  • エントリーポイントの書き方
  • Lambdaのコードで使うモジュールの指定
    • nodejs...CDKのプロジェクトのpackage.jsonに書けばOK
    • python...別途Lambdaのコードのディレクトリにrequirements.txtを書く必要がある

また、TypeScriptに比べて資料が少ないように感じたので、CDK全く触ったことない人が始めるには公式ドキュメントとにらめっこしないといけないので大変そう
※技術ブログではなく何事も常に一次資料にあたるのが本来あるべき姿というのは置いておくとして

とはいえ、(至極当然のことではあるけど)PythonのCDK固有の難点みたいなものは特に感じられなかったので、Pythonをよく使っているチームなら採用しても全く問題ないと思う

次はC#かGolangでやってみる予定

参考リンク

サンプルコード
https://github.com/tetsu0000/todoapp-py

0
0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?