はじめに
記事についての
こちらの記事は連載企画の第 3 弾です! aws-sdk を利用した dynamodb での crud の作成についてです!
記事一覧
- セットアップ&チュートリアル
- cognito を利用した認証機能の作成
- dynamodb を利用した CRUD の作成 <-- 現在
- serverless-offline を利用したローカル環境の作成
- 応用的な使い方(cognito を利用した authorizer の作成)
dynamodb を利用した CRUD の作成
dynamodb のテーブル設計に
事前にこちらの記事に目を通しておくとわかりやすいです。
検索のために用いる GlobalSecondaryIndexes
の概念がわかりやすく説明されています。
https://blog.usize-tech.com/table-design-for-amazon-dynamodb/
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 [関数名]
)
空の関数を作成
"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) => {};
作成した関数を紐付け
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の作成方法について書いていきました。あまり細かいことは書かずに気軽に試せる程度にしました。そのうちより細かな補足もまとめたいなとおもます。
参考
https://www.serverless.com/ https://blog.usize-tech.com/table-design-for-amazon-dynamodb/ https://qiita.com/Fujimon_fn/items/66be7b807a8329496899
会社の紹介
株式会社 mofmof では一緒に働いてくれるエンジニアを募集しています。 興味のある方は是非こちらのページよりお越しください! https://www.mof-mof.co.jp/ https://www.mof-mof.co.jp/recruit/
次回は『serverless-offline を利用したローカル環境の作成』を予定しています。