はじめに
django REST Frameworkとboto3でAWSのDynamoDBに対して操作を行うapiを作成する。
GET、POST、PUT、DELETEの操作ができるようにする。
Dynamodbテーブル作成(事前準備)
下記のようなテーブルを事前に用意し、いくつかデータを入れておく
テーブル名: Fruits
hash key: Name
 
djangoプロジェクトの作成
django project(dynamo_operation)とapp(api)を作成
$ django-admin startproject dynamo_operation
$ cd dynamo_operation/
$ django-admin startapp api 
setting.pyの編集
setting.pyにrest_frameworkと先ほど作成したappのconfigを追加する。
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'rest_framework', #追加
    'api.apps.ApiConfig', #追加
]
DynamoDBリクエスト用のmodelを作成
djangoではDBの作成、操作にmodelを用意する。
DynamoDBへのリクエストはboto3を使用するので特にmodelは必要ないが、今回はmodel(dynamo_model.py)を用意した。
class Fruit():
    def __init__(self, name):
        self.name = name
views.pyの編集
from rest_framework import status
from rest_framework.views import APIView
from rest_framework.response import Response 
from api.dynamo_models import Fruit
from boto3 import client
dynamodb_client = client('dynamodb')
class DynamoRequest(APIView):
    # 全体GET
    def get(self, request):
        response = []
        items = dynamodb_client.scan(TableName='Fruits')['Items']
        for item in items:
            fruit = Fruit(item['Name']['S'])
            fruit.price = item.get('Price',{}).get('N', '')
            response.append(fruit.__dict__)
        return Response(response)
    
    def post(self, request):
        request_data = request.data
        item = {'Name': {'S': request_data['Name']}}
        if 'Price' in request_data:
            item['Price'] = {'N': request_data['Price']}
        dynamodb_client.put_item(
            TableName = 'Fruits',
            Item = item
        )
        return Response(status=status.HTTP_201_CREATED)
class DynamoDetailRequest(APIView):
    #単体GET
    def get(self, request, pk):
        item = dynamodb_client.get_item(
            TableName = 'Fruits',
            Key = {
                'Name': {'S': pk},
            }
        )['Item']
        fruit = Fruit(item['Name']['S'])
        fruit.price = item.get('Price',{}).get('N', '')
        return Response(fruit.__dict__)
    
    def put(self, request, pk):
        request_data = request.data
        item = dynamodb_client.get_item(
            TableName = 'Fruits',
            Key = {
                'Name': {'S': pk},
            }
        )['Item']
        price = item.get('Price',{}).get('N', '0')
        if 'Price' in request_data:
            price = request_data['Price']
        dynamodb_client.put_item(
            TableName = 'Fruits',
            Item = {
                'Name': {'S': item['Name']['S']},
                'Price': {'N': price}
            }
        )
        return Response(status=status.HTTP_200_OK)
    
    def delete(self, request, pk):
        dynamodb_client.delete_item(
            TableName = 'Fruits',
            Key = {
                'Name': {'S': pk},
            }
        )
        return Response(status=status.HTTP_204_NO_CONTENT)
rest_frameworkのAPIViewを継承したclassでリクエストを処理する。
DynamoRequestがpathパラメータなしのリクエストを処理し、DynamoDetailRequestでpathパラメータ(pk)ありのリクエストの処理を行う。
APIViewを継承することにより、HTTPメソッドごとにfunctionを用意することでそれぞれのメソッドに対応する処理を追加することができる。
urls.pyの編集
from django.urls import path
from api import views
urlpatterns = [
    path('api/', views.DynamoRequest.as_view()),
    path('api/<pk>/', views.DynamoDetailRequest.as_view())
]
dynamo_oprationフォルダのurls.pyも編集する
from django.urls import path, include
urlpatterns = [
    path('', include('api.urls')),
]
curlコマンドで動作確認
serverの起動
$ python manage.py runserver
GET(全体検索)
$ curl http://127.0.0.1:8000/api/
# レスポンス
[{"name":"orange","price":"200"},{"name":"banana","price":"100"},{"name":"apple","price":"100"}]
POST
$ curl -X POST \
  -H 'Content-Type:application/json' \
  -d '{"Name": "peach", "Price": "400"}' \
  http://127.0.0.1:8000/api/
peachの項目が追加されている。
GET(単体)
appleの項目を取得
$ curl http://127.0.0.1:8000/api/apple/
# レスポンス
{"name":"apple","price":"100"}
PUT
appleのpriceを100 -> 200へ変更する
$ curl -X PUT \
  -H 'Content-Type:application/json' \
  -d '{"Price": "200"}' \
  http://127.0.0.1:8000/api/apple/
DELETE
peachの項目を削除する。
$ curl -X DELETE http://127.0.0.1:8000/api/peach/
おわりに
django REST Framework + boto3でDynamoDBの操作を行うREST Apiを作成した。
今回は、dynamodb_model.pyを用意してmodelを管理するようにしたが、必要なかったかもしれない(この辺の設計は今後改善していきたい)。



