🌟
serverless framework 第3回 dynamodb crud作成
はじめに
記事についての
こちらの記事は連載企画の第 3 弾です!
aws-sdk を利用した dynamodb での crud の作成についてです!
予定記事
- セットアップ&チュートリアル
- cognito を利用した認証機能の作成
- dynamodb を利用した CRUD の作成 <-- 現在
- serverless-offline を利用したローカル環境の作成
- 応用的な使い方(cognito を利用した authorizer の作成)
dynamodb を利用した CRUD の作成
dynamodb のテーブル設計に
事前にこちらの記事に目を通しておくとわかりやすいです。
検索のために用いる GlobalSecondaryIndexes
の概念がわかりやすく説明されています。
dynamodb のセットアップ
まずは、serverless
コマンドによりプロジェクトを作成します。
- dynamodb へのアクセス権限と環境変数の設定を追加します。
provider:
...
environment: # lambda内で使用する環境変数を指定できる
DYNAMODB_USER_TABLE: ${self:app}-userTable
iamRoleStatements: # アクセス権限の設定
- Effect: Allow
Action:
- dynamodb:DescribeTable
- dynamodb:Query
- dynamodb:Scan
- dynamodb:GetItem
- dynamodb:PutItem
- dynamodb:UpdateItem
- dynamodb:DeleteItem
- "cognito:*"
- "apigateway:*"
Resource:
- "*"
- 操作を行うテーブルを作成します。
今回はUserTable
を使用します。
resources:
Resources:
UserTable: # 作成するテーブル名
Type: AWS::DynamoDB::Table
Properties:
TableName: ${self:app}-userTable # 任意のテーブル名
ProvisionedThroughput: # エラーが治る
ReadCapacityUnits: 5
WriteCapacityUnits: 5
AttributeDefinitions: # 属性の定義(必須属性のみで良い)
- AttributeName: email
AttributeType: S
- AttributeName: name
AttributeType: S
KeySchema: # primary keyの設定
- AttributeName: email
KeyType: HASH # Hash key 必須 (Hash key (+ Sort key)がprimary keyとなる)
GlobalSecondaryIndexes: # 検索のために
- IndexName: name-index # 任意のインデックス名
KeySchema: # 検索に用いるprimary keyの設定
- AttributeName: name
KeyType: HASH
Projection:
ProjectionType: ALL
ProvisionedThroughput: # エラーが治る
ReadCapacityUnits: 5
WriteCapacityUnits: 5
- 今回使用する関数を定義します。
事前に定義しておくことで関数のみのデプロイを行えるようになります。(serverless deploy functions -f [関数名]
)
空の関数を作成
handler.js
"use strict";
module.exports.createUser = async (event) => {};
module.exports.getUser = async (event) => {};
module.exports.getAllUser = async (event) => {};
module.exports.getUsers = async (event) => {};
module.exports.updateUser = async (event) => {};
module.exports.deleteUser = async (event) => {};
作成した関数を紐付け
serverless.yml
functions:
createUser:
handler: handler.createUser
events:
- httpApi:
path: /createUser
method: post
getUser:
handler: handler.getUser
events:
- httpApi:
path: /getUser
method: get
getAllUser:
handler: handler.getAllUser
events:
- httpApi:
path: /getAllUser
method: get
getUsers:
handler: handler.getUsers
events:
- httpApi:
path: /getUsers
method: get
updateUser:
handler: handler.updateUser
events:
- httpApi:
path: /updateUser
method: post
deleteUser:
handler: handler.deleteUser
events:
- httpApi:
path: /deleteUser
method: delete
- ここまで行ったら一旦デプロイ
serverless deploy
- テーブルが正しく作られていることを AWS Console より確認
dynamodb のテーブルに新規テーブルが作成されていれば OK
これでセットアップ終了
関数の構成
// レスポンスのbody
let body;
// レスポンスのステータスコード
let statusCode = 200;
const headers = {
"Content-Type": "application/json",
};
// リクエストボディ
const requestBody = JSON.parse(event.body);
/**
* 関数内での変更箇所
*/
try {
// 処理の実行
await documentClient.put(params).promise();
body = { data: Item, message: "create user success" };
} catch (err) {
// console.logの結果はcloudwatch上で確認ができる
console.log({ err });
// エラーがあった際にはステータスコードを更新
statusCode = 400;
body = { message: "create user failed" };
}
// 返り値はレスポンスとして送られる
return {
statusCode,
body: JSON.stringify(body),
headers,
};
CREATE
データの作成(put)
createUser
を編集
// 登録する値
const Item = {
email: requestBody.email,
name: requestBody.name,
// 定義していない属性を追加することができる
// age: 23
};
const params = {
TableName: process.env.DYNAMODB_USER_TABLE,
// attribute_not_existsは重複した値を防ぐことができる
ConditionExpression: "attribute_not_exists(email)",
Item,
};
// putによりデータの追加を行うことができる
await documentClient.put(params).promise();
body = { data: Item };
curl -XPOST \
-H 'Content-Type: application/json' \
-d '{ "email": "test@example.com", "name": "test" }' \
[生成されたエンドポイント]/createUser
READ
単一データ取得(get)
getUser
を編集
const params = {
TableName: process.env.DYNAMODB_USER_TABLE,
Key: {
// 更新したい項目をハッシュキー(及びソートキー)によって1つ指定
email: requestBody.email,
},
};
// getではプライマリーキーにより一件データを取得できる
const result = await documentClient.get(params).promise();
body = { data: result.Item };
curl -XGET \
-H 'Content-Type: application/json' \
-d '{ "email": "test@example.com" }' \
[生成されたエンドポイント]/getUser
一括データ取得(scan)
const params = {
TableName: process.env.DYNAMODB_USER_TABLE,
};
// scanではテーブルに含まれる全件のデータを取得する
await documentClient.scan(params).promise();
body = { data: result.Items };
curl -XGET [生成されたエンドポイント]/getAllUser
検索データ取得(query)
const params = {
TableName: process.env.DYNAMODB_USER_TABLE,
IndexName: "name-index",
ExpressionAttributeNames: { "#name": "name" },
ExpressionAttributeValues: { ":val": requestBody.name },
KeyConditionExpression: "#name = :val", // 検索条件 (部分一致検索はできない)
};
await documentClient.query(params).promise();
body = { data: result.Items };
curl -XGET \
-H 'Content-Type: application/json' \
-d '{ "name": "test" }' \
[生成されたエンドポイント]/getUsers
UPDATE
データの更新(update)
const requestBody = JSON.parse(event.body);
const Item = {
email: requestBody.email,
name: requestBody.name,
};
const params = {
TableName: process.env.DYNAMODB_USER_TABLE,
Key: {
// 更新したい項目をハッシュキー(及びソートキー)によって1つ指定
email: Item.email,
},
ExpressionAttributeNames: { "#name": "name" },
ExpressionAttributeValues: { ":val": Item.name },
UpdateExpression: "SET #name = :val", // 検索条件 (部分一致検索はできない)
};
await documentClient.update(params).promise();
body = { data: Item };
curl -XPOST \
-H 'Content-Type: application/json' \
-d '{ "email": "test@example.com", "name": "test mark2" }' \
[生成されたエンドポイント]/updateUser
DELETE
データの削除(delete)
const requestBody = JSON.parse(event.body);
const params = {
TableName: process.env.DYNAMODB_USER_TABLE,
Key: {
// 更新したい項目をハッシュキー(及びソートキー)によって1つ指定
email: requestBody.email,
},
};
// deleteでは一件のデータを削除できる
await documentClient.delete(params).promise();
curl -XDELETE \
-H 'Content-Type: application/json' \
-d '{ "email": "test@example.com" }' \
[生成されたエンドポイント]/deleteUser
まとめ
今回はsdkを利用したdynamodbのcrudの作成方法について書いていきました。あまり細かいことは書かずに気軽に試せる程度にしました。そのうちより細かな補足もまとめたいなとおもます。
参考
会社の紹介
株式会社 mofmof では一緒に働いてくれるエンジニアを募集しています。
興味のある方は是非こちらのページよりお越しください!
次回は『serverless-offline を利用したローカル環境の作成』を予定しています。
Discussion