Taste of Tech Topics

Acroquest Technology株式会社のエンジニアが書く技術ブログ

API Gatewayから、AWS Lambdaを使わずにDynamoDBにアクセスする

こんにちは、ツカノ(@)です。

クラウド上にアプリケーションを構築することがアドバンテージとなり、AWSを利用したサーバレスな事例を多く目にするようになりました。
例えば、DBアクセスする場合などは、EC2のようにサーバ管理が必要なサービスを使わずに構築できるようになりました。

DynamoDBにアクセスする例は、様々な方がWeb上に掲載していますが、
f:id:acro-engineer:20160923092042p:plain
API GatewayAWS Lambda → DynamoDB
という流れで呼び出している例を多く目にします。

こういった例の中には、AWS Lambdaでは特に他の処理をせず、単にDynamoDBのAPIを呼び出しているだけのものもあります。
実はAPI Gatewayにはマッピングテンプレートという機能があり、httpボディのjsonフォーマットを変換して、AWSの様々なサービスと連携できます。

docs.aws.amazon.com

この機能を利用すれば、フォーマット変換が簡単なケースではAWS Lambdaを利用せずとも、
f:id:acro-engineer:20160923092111p:plain
API Gateway → DynamoDB
という流れで呼び出すことができます。
AWS Lambdaを利用しなくてよいため、ある程度利用料金も安くなりますね。

ただ、API Gatewayマッピングテンプレート(Velocityを利用している)を実際に書いてみると、多少の慣れが必要だと感じます。
そこで、API GatewayからDynamoDBのAPIを呼び出すためのマッピングテンプレートを具体的にまとめてみました。

今回利用したデータ

RDBMSでよく例に登場するemployeesのデータを利用しました。

ここから、employeesテーブルだけ利用します。
http://dev.mysql.com/doc/employee/en/sakila-structure.html

emp_no INT(11)
birth_date DATE
first_name VARCHAR(14)
last_name VARCHAR(16)
gender ENUM('M', 'F')
hire_date DATE
  • データ

先ほどのテーブルに入る具体的なデータは、このサイトにサンプルがあります。
https://launchpad.net/test-db/

何行か見てみると、このようなデータになっています。

(10001,'1953-09-02','Georgi','Facello','M','1986-06-26'),
(10002,'1964-06-02','Bezalel','Simmel','F','1985-11-21'),
(10003,'1959-12-03','Parto','Bamford','M','1986-08-28'),
(10004,'1954-05-01','Chirstian','Koblick','M','1986-12-01'),
(10005,'1955-01-21','Kyoichi','Maliniak','M','1989-09-12'),
(10006,'1953-04-20','Anneke','Preusig','F','1989-06-02')
(10007,'1957-05-23','Tzvetan','Zielinski','F','1989-02-10'),
(10008,'1958-02-19','Saniya','Kalloufi','M','1994-09-15'),
(10009,'1952-04-19','Sumant','Peac','F','1985-02-18'),
(10010,'1963-06-01','Duangkaew','Piveteau','F','1989-08-24'),

API GatewayAPIについて

API GatewayAPIについては以下のサイトを参考にしました。

https://docs.aws.amazon.com/ja_jp/amazondynamodb/latest/developerguide/HowItWorks.API.html
http://docs.aws.amazon.com/ja_jp/amazondynamodb/latest/developerguide/Programming.LowLevelAPI.html

GetItemのリクエスト・レスポンスの例が載っていますが、ちょっと癖がありますね。

{
    "TableName": "Pets",
    "Key": {
        "AnimalType": {"S": "Dog"},
        "Name": {"S": "Fido"}
    }
}
{
    "Item": {
        "Age": {"N": "8"},
        "Colors": {
            "L": [
                {"S": "White"},
                {"S": "Brown"},
                {"S": "Black"}
            ]
        },
        "Name": {"S": "Fido"},
        "Vaccinations": {
            "M": {
                "Rabies": {
                    "L": [
                        {"S": "2009-03-17"},
                        {"S": "2011-09-21"},
                        {"S": "2014-07-08"}
                    ]
                },
                "Distemper": {"S": "2015-10-13"}
            }
        },
        "Breed": {"S": "Beagle"},
        "AnimalType": {"S": "Dog"}
    }
}

httpリクエストをAPI Gatewayに送信するとき、ボディのjsonに型を記載しないことが多いと思いますが、DynamoDBのAPIでは型指定が必要になります。
そのため、API Gatewayでボディのjsonを変換する必要があります。

API Gatewayの設定方法について

API Gatewayの設定方法については、こちらのサイトが分かりやすいです。
dev.classmethod.jp

このサイトに「Integration Response の設定」が記載されています。
DynamoDBのいくつかのAPIに対して、実際にマッピングテンプレートを記載してみましょう。

PutItemの例

#set($item = $input.path('$'))
{
  "TableName": "employees",
  "Item": { 
    "emp_no": {
      "N": "$item.emp_no"
    },
    "birth_date": {
      "S": "$item.birth_date"
    },
    "first_name": {
      "S": "$item.first_name"
    },
    "last_name": {
      "S": "$item.last_name"
    },
    "gender": {
      "S": "$item.gender"
    },
    "hire_date": {
      "S": "$item.hire_date"
    }
  }
}

応答にボディは不要とすると、レスポンスのマッピングテンプレートは不要です。

Scanの例

全件取得のため、リクエストのマッピングテンプレートは不要です。

#set($items = $input.path('$.Items'))
{
  [
#foreach($item in $items)
    {
      "emp_no": $item.emp_no.N,
      "birth_date": "$item.birth_date.S",
      "first_name": "$item.first_name.S",
      "last_name": "$item.last_name.S",
      "gender": "$item.gender.S",
      "hire_date": "$item.hire_date.S"
    }#if($foreach.hasNext),#end

#end
  ]
}

emp_noは数値型であるため、JSONのレスポンスの値はダブルコーテーションで囲いません

GetItemの例

リクエストするURLにemp_noが入っていることを前提とします。

{
  "TableName": "employees",
  "Key": { 
    "emp_no": {
      "N": "$input.params('emp_no')"
    }
  }
}
#set($item = $input.path('$.Item'))
{
  "emp_no": $item.emp_no.N,
  "birth_date": "$item.birth_date.S",
  "first_name": "$item.first_name.S",
  "last_name": "$item.last_name.S",
  "gender": "$item.gender.S",
  "hire_date": "$item.hire_date.S"
}

emp_noは数値型であるため、jsonのレスポンスの値はダブルコーテーションで囲いません

DeleteItemの例

リクエストするURLにemp_noが入っていることを前提とします。

{
  "TableName": "employees",
  "Key": { 
    "emp_no": {
      "N": "$input.params('emp_no')"
    }
  }
}

応答にボディは不要とすると、レスポンスのマッピングテンプレートは不要です。

最後に

書き方に慣れるとそうでもないのですが、初めて書くときは苦労しますよね。
今回は、ちょっとした実践例ですが、初めてマッピングテンプレートを書く方のお役に立てば幸いです。
それではまた。

Acroquest Technologyでは、キャリア採用を行っています。


  • 日頃勉強している成果を、AWSHadoop、Storm、NoSQL、Elasticsearch、SpringBoot、HTML5/CSS3/JavaScriptといった最新の技術を使ったプロジェクトで発揮したい。
  • 社会貢献性の高いプロジェクトに提案からリリースまで携わりたい。
  • 書籍・雑誌等の執筆や対外的な勉強会の開催を通した技術の発信や、社内勉強会での技術情報共有により、技術的に成長したい。
  • OSSの開発に携わりたい。

 
少しでも上記に興味を持たれた方は、是非以下のページをご覧ください。
 
データ分析で国内に新規市場を生み出す新サービス開発者WANTED! - Acroquest Technology株式会社の新卒・インターンシップ - Wantedlywww.wantedly.com