AWSメモ >

PythonでAWS DynamoDBのCRUDを書いてみる

概要

Python で DynamoDB へのCRUDを書いてみる。

尚、今回は GET、POST、PUT、DELETE ハンドラーをそれぞれ別々に作成する。
https://github.com/awslabs/serverless-application-model/tree/master/examples/2016-10-31/api_backend

参考

http://docs.aws.amazon.com/ja_jp/amazondynamodb/latest/developerguide/GettingStarted.Python.03.html
http://boto3.readthedocs.io/en/latest/reference/services/dynamodb.html
http://boto3.readthedocs.io/en/latest/guide/dynamodb.html

テーブル作成

テーブル定義の作成

ddl/books.json

{
    "TableName": "Books",
    "AttributeDefinitions": [
        { "AttributeName": "id", "AttributeType": "S" },
        { "AttributeName": "isbn", "AttributeType": "S" },
        { "AttributeName": "title", "AttributeType": "S" }
    ],  
    "KeySchema": [
        { "AttributeName": "id", "KeyType": "HASH" }
    ],  
    "ProvisionedThroughput": { "WriteCapacityUnits": 1, "ReadCapacityUnits": 1 },
    "GlobalSecondaryIndexes": [
        {
            "IndexName": "isbn-index",
            "KeySchema": [
                { "AttributeName":"isbn", "KeyType":"HASH" }
            ],
            "Projection": {"ProjectionType": "KEYS_ONLY" },
            "ProvisionedThroughput": {"ReadCapacityUnits": 1,"WriteCapacityUnits": 1 } 
        },
        {
            "IndexName": "title-index",
            "KeySchema": [
                { "AttributeName":"title", "KeyType":"HASH" }
            ],
            "Projection": {"ProjectionType": "KEYS_ONLY" },
            "ProvisionedThroughput": {"ReadCapacityUnits": 1,"WriteCapacityUnits": 1 } 
        }
    ]   
}

テーブル作成

aws dynamodb create-table  --endpoint-url http://localhost:8000  --cli-input-json file://ddl/books.json

※ローカルのDynamoDBでない場合は --endpoint-url は不要。

Lambda関数の作成

book.js

import os
import boto3
import json
import decimal

dynamodb = None
if os.environ and os.environ["DYNAMO_REGION"] and os.environ["DYNAMO_END_POINT"]:
    dynamodb = boto3.resource('dynamodb', region_name=os.environ["DYNAMO_REGION"], endpoint_url=os.environ["DYNAMO_END_POINT"])
else:
    dynamodb = boto3.resource('dynamodb', dynamo_opt)

# テーブル名
TABLE_NAME = "Books"

# 一覧
def list(event, context):
    res = dynamodb.Table(TABLE_NAME).scan()
    return { 'body' : str(res) }

# 一意検索
def get(event, context):
    res = dynamodb.Table(TABLE_NAME).get_item(
        Key={
            "id" : event["pathParameters"]["id"]
        }   
    )   
    return { 'body' : str(res) }

# 登録
def create(event, context):
    req = json.loads(event["body"]) if type(event["body"]) == str else event["body"]
    res = dynamodb.Table(TABLE_NAME).put_item(
        Item={
            "id": req["id"],
            "isbn": req["isbn"],
            "title": req["title"],
            "price": decimal.Decimal(req["price"])
        }   
    )
    return { 'body' : str(res) }

# 更新
def update(event, context):
    req = json.loads(event["body"]) if type(event["body"]) == str else event["body"]
    res = dynamodb.Table(TABLE_NAME).update_item(
        Key={
            'id': event["pathParameters"]["id"]
        },  
        UpdateExpression="set isbn=:i, title=:t, price=:p",
        ExpressionAttributeValues={
            ':i': req["isbn"],
            ':t': req["title"],
            ':p': decimal.Decimal(req["price"])
        },  
        ReturnValues="UPDATED_NEW"
    )
    return { 'body' : str(res) }

# 削除
def delete(event, context):
    res = dynamodb.Table(TABLE_NAME).delete_item(
        Key={
            'id': event["pathParameters"]["id"]
        }
    )
    return { 'body' : str(res) }

template.yml の作成

template-local.yml

AWSTemplateFormatVersion : '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: Test serverless application.

Resources:

  BookListFunction:
    Type: AWS::Serverless::Function
    Properties:
      Handler: book.list
      Policies: AmazonDynamoDBFullAccess
      Runtime: python3.6
      MemorySize: 128 
      Timeout: 5
      Environment:
        Variables:
          DYNAMO_END_POINT: http://10.20.30.40:8000
          DYNAMO_REGION: localhost
      Events:
        List:
          Type: Api 
          Properties:
            Path: /book
            Method: get 

  BookGetFunction:
    Type: AWS::Serverless::Function
    Properties:
      Handler: book.get
      Policies: AmazonDynamoDBFullAccess
      Runtime: python3.6
      MemorySize: 128 
      Timeout: 5
      Environment:
        Variables:
          DYNAMO_END_POINT: http://10.20.30.40:8000
          DYNAMO_REGION: localhost
      Events:
        Get:
          Type: Api 
          Properties:
            Path: /book/{id}
            Method: get 

  BookCreateFunction:
    Type: AWS::Serverless::Function
    Properties:
      Handler: book.create
      Policies: AmazonDynamoDBFullAccess
      Runtime: python3.6
      MemorySize: 128 
      Timeout: 5
      Environment:
        Variables:
          DYNAMO_END_POINT: http://10.20.30.40:8000
          DYNAMO_REGION: localhost
      Events:
        Create:
          Type: Api 
          Properties:
            Path: /book
            Method: post

  BookUpdateFunction:
    Type: AWS::Serverless::Function
    Properties:
      Handler: book.update
      Policies: AmazonDynamoDBFullAccess
      Runtime: python3.6
      MemorySize: 128
      Timeout: 5
      Environment:
        Variables:
          DYNAMO_END_POINT: http://10.20.30.40:8000
          DYNAMO_REGION: localhost
      Events:
        Update:
          Type: Api
          Properties:
            Path: /book/{id}
            Method: put

  BookDeleteFunction:
    Type: AWS::Serverless::Function
    Properties:
      Handler: book.delete
      Policies: AmazonDynamoDBFullAccess
      Runtime: python3.6
      MemorySize: 128
      Timeout: 5
      Environment:
        Variables:
          DYNAMO_END_POINT: http://10.20.30.40:8000
          DYNAMO_REGION: localhost
      Events:
        Delete:
          Type: Api
          Properties:
            Path: /book/{id}
            Method: delete

sam local 上で api を起動

AWS Lambda のローカル開発手順 も参照

sam local start-api --template template-local.yml 

動作確認

一覧

curl http://localhost:3000/book

登録

curl -XPOST -H 'Content-type: application/json' --data '{ "id" : "A01", "isbn" : "ABC001", "title" : "テスト001", "price": 1008 }' http://localhost:3000/book
curl -XPOST -H 'Content-type: application/json' --data '{ "id" : "A02", "isbn" : "ABC002", "title" : "テスト002", "price": 2016 }' http://localhost:3000/book

更新

curl -XPUT -H 'Content-type: application/json' --data '{ "isbn" : "XXXXX1", "title" : "テストXX1", "price": 108 }' http://localhost:3000/book/A01

削除

curl -XDELETE http://localhost:3000/book/A01

トップ   一覧 単語検索 最終更新   ヘルプ   最終更新のRSS