🐡

Chalice with DynamoDB

2022/01/24に公開

この記事の目的

この記事の目的は、AWS製のサーバーレスフレームワークChaliceとDynamoDBを組み合わせて利用する手順を個人的なメモとして記すことです。

以下の内容を含みます。

  • Chalice, DynamoDBともにAWS上で利用します
  • Chalice, DynamoDBLocalを用いてローカルマシンでも利用します(長くなるので次回投稿にします)

以下の内容はカバー出来なかったので今後の課題とします。

  • ローカル環境でのIDEを利用したデバッグ
  • DynamoDB構築のCDKなどの利用(今回はaws-cliコマンドで実行)
  • ユニットテスト

前提事項

以下のインストールについては済んでいるものとします。

  • Python3
  • chalice
  • aws-cli
  • docker-compose
ちなみに、私の環境は以下のようになっています。(2022/1/24時点)
  • Python 3.8.9 (Pipenv利用)
  • chalice 1.26.4
  • aws-cli 2.4.11
  • docer-compose 2.1.1
  • VSCode 1.63.2
  • macOS Monterey 12.1

References

Chalice公式サイト https://aws.github.io/chalice/index.html

構築手順

Project作成

% chalice new-project chalice_demo
Your project has been generated in ./chalice_demo

AWSにデプロイする

デプロイ

% chalice deploy
Creating deployment package.
Creating IAM role: chalice_demo-dev
Creating lambda function: chalice_demo-dev
Creating Rest API
Resources deployed:
  - Lambda ARN: arn:aws:lambda:ap-northeast-1:123456789012:function:chalice_demo-dev
  - Rest API URL: https://abcdefghij.execute-api.<region>.amazonaws.com/api/

リソースを消す

% chalice delete
Deleting Rest API: abcdefghij
Deleting function: arn:aws:lambda:ap-northeast-1:123456789012:function:chalice_demo-dev
Deleting IAM role: chalice_demo-dev

以下のIAMロールとインラインのポリシーが作成される

  • IAM Role chalice_demo-dev
{
  "Version": "2012-10-17",
  "Statement": [ 
    {
      "Effect": "Allow",
      "Action": [
        "logs:CreateLogGroup",
        "logs:CreateLogStream",
        "logs:PutLogEvents"
      ],
      "Resource": "arn:*:logs:*:*:*"
    }
  ]
}

DynamoDBのテーブルをAWS上に構築する

本来は、CDKなどで実施したいのですが、スタディーが足りないので、今回はaws-cliで作成しました。
詳細は、README.mdを参照ください。

DBアクセス処理を実装する

  • config.jsonの変更
  • policy-dev.jsonの追加
  • chalicelib/database.pyを追加
  • app.pyの変更

config.jsonが重要なので、そこから説明します。
詳しくは、こちらをご覧ください。
ここでのポイントは、環境変数DB_TABLE_NAMEにDynamoDBのテーブル名を設定するところと、autogen_policy(ソースからIAMロールを自動生成する機能)をFalseにしているところ。

config.json
{
  "version": "2.0",
  "app_name": "chalice_demo",
  "stages": {
    "dev": {
      "api_gateway_stage": "api",
      "environment_variables": {
        "DB_TABLE_NAME": "Records"
      },
      "autogen_policy": false
    }
  }
}

上で、autogen_plicyをFalseにしているので、ポリシーを手動で定義する。
このファイルのネーミングルールは、policy-<ステージ名>.jsonとなる。

policy-dev.json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "logs:CreateLogGroup",
        "logs:CreateLogStream",
        "logs:PutLogEvents"
      ],
      "Resource": "arn:aws:logs:*:*:*"
    },
    {
      "Effect": "Allow",
      "Action": [
        "dynamodb:PutItem",
        "dynamodb:DeleteItem",
        "dynamodb:UpdateItem",
        "dynamodb:GetItem",
        "dynamodb:Scan",
        "dynamodb:Query"
      ],
      "Resource": "*"
    }
  ]
}

Pythonのソースコードは長いので、要所だけ記載します。
全体はGitHubを参照ください。

chalicelib/database.py
import os
import boto3
from boto3.dynamodb.conditions import Key,Attr
import uuid

def _get_database():
    endpoint = os.environ.get('DB_ENDPOINT')
    if endpoint:
        print('*** DB_ENDPOINT指定あり ***')
        print(endpoint)
        return boto3.resource('dynamodb', endpoint_url=endpoint)
    else:
        print('*** DB_ENDPOINT指定なし ***')
        return boto3.resource('dynamodb')

def get_record(record_id):
    table = _get_database().Table(os.environ['DB_TABLE_NAME'])
    response = table.get_item(Key={'id': record_id})
    return response['Item']

app.pyにrecords/{record_id}のエンドポイントを追加する例です。

app.py
import os

from chalice import Chalice, NotFoundError, BadRequestError
from chalicelib import database

app = Chalice(app_name='chalice_demo')

@app.route('/records/{record_id}', methods=['GET'], cors=True)
def get_records(record_id):
    record = database.get_record(record_id)
    if record:
        return record
    else:
        raise NotFoundError('Record not found.')

再度デプロイし動作確認します。

再度chalice deployを行い、エンドポイントを呼び出します。

# 結果は見やすく整形しています。
% curl https://abcdefghij.execute-api.<リージョン名>.amazonaws.com/api/records/id2
{
  "result_time":"00:23:11",
  "race":"3",
  "section":"2",
  "runner_name":"test-runner",
  "team":"TeamA",
  "description":"Memo2",
  "id":"id2",
  "sub":"LOCAL_USER"
}

まとめ

今回は、Chalice with DynamoDBということで、簡単な処理を実装してみました。
Chaliceで基本構成のAPI Gatewayは簡単に作成できますが、いろいろなリソースとの連携は、Chaliceだけだと限界がある気はします。
それもあってか、Chaliceは最近ではCDKとの連携もできるようです。
https://aws.github.io/chalice/tutorials/cdk.html
今回は採用していませんが、そのうちに、他のAWSサービスとの連携に使ってみたいと思います。

次回は、Chalice with DynamoDBのローカル実行について書きたいと思います。

Discussion