Using the DynamoDB in Serverless Framework

Serverless Framework Try using the DynamoDB in.

### Source Repository

Source, please refer to the following repository.
https://github.com/katsuhiko/sls-dynamodb

### version

version

node 6.9.1

npm 3.10.8

serverless framework 1.1.0

Lambda is because Node.js V4.3, you may wish to adjust. Do not put together because it does not move in the local now.

### todos.js

I want feel free to use, but I do not want too much layer is provided, and only the portion corresponding to the Model　todos.jswas cut out as.

But the Lambda and DynamoDB may make without consciousness, is made to be aware of a whole bunch DynamoDB.

" moment " is a library that easy to handle the date.

To generate a unique key " uuid we use." " chance I think that it may be".

It adds a stage as a prefix to the table name of DynamoDB. Approach might have other, I think that trouble when you actually use and not included a mechanism to create a DynamoDB table for each stage. This time, has been supported by attaching to the table name the stage as a prefix.

In order to be able to see the stage from Javascript Plugin " serverless-plugin-write-env-vars vars " said " dotenv we use." Since seems functionality that is similar in Serverless Framework According to the comments are provided, I think that in any unnecessary.

'use strict';

const uuid = require('uuid'),
moment = require('moment'),
tableName = ${process.env.STAGE}-todos; module.exports.readAll = (db, callback) => { const params = { TableName: tableName }; return db.scan(params, (err, data) => { if (err) { callback(err); } else { callback(err, data.Items); } }); }; module.exports.readOne = (db, id, callback) => { const params = { TableName: tableName, Key: { id: id } }; return db.get(params, (err, data) => { if (err) { callback(err); } else { callback(err, data.Item); } }); }; module.exports.create = (db, data, callback) => { data.id = uuid.v1(); data.updatedUtc = moment().utc().toISOString(); const params = { TableName: tableName, Item: data }; return db.put(params, (err, data) => { if (err) { callback(err); } else { callback(err, params.Item); } }); }; module.exports.update = (db, id, data, callback) => { data.id = id; data.updatedAt = moment().utc().toISOString(); const params = { TableName : tableName, Item: data }; return db.put(params, (err, data) => { if (err) { callback(err); } else { callback(err, params.Item); } }); }; module.exports.delete = (db, id, callback) => { const params = { TableName : tableName, Key: { id: id } }; return db.delete(params, (err, data) => { if (err) { callback(err); } else { callback(err, params.Key); } }); };  ### handler.js It is returning corresponding to the Lambda Proxy. contextInstead callback it uses. You could not get a firm information, but callbackI think that it would be good to use. I want to as simple as possible, but where to return the HTTP status was not able to clean and really entered IF is. 'use strict'; const AWS = require('aws-sdk'), dynamoDb = new AWS.DynamoDB.DocumentClient(), env = require('dotenv').config(), todos = require('./todos.js'); const createResponse = (statusCode, body) => ( { statusCode, headers: { 'Access-Control-Allow-Origin': '*', //Required for CORS support to work }, body: JSON.stringify(body), } ); module.exports.todosReadAll = (event, context, callback) => { todos.readAll(dynamoDb, (err, result) => { if (err) { callback(createResponse(500, { message: err.message })); } else { callback(null, createResponse(200, result)); } }); }; module.exports.todosReadOne = (event, context, callback) => { const id = event.pathParameters.id; todos.readOne(dynamoDb, id, (err, result) => { if (err) { callback(createResponse(500, { message: err.message })); } else if (!result) { callback(null, createResponse(404, { message: 'not found'})); } else { callback(null, createResponse(200, result)); } }); }; module.exports.todosCreate = (event, context, callback) => { const data = JSON.parse(event.body); todos.create(dynamoDb, data, (err, result) => { if (err) { callback(createResponse(500, { message: err.message })); } else { callback(null, createResponse(201, result)); } }); }; module.exports.todosUpdate = (event, context, callback) => { const id = event.pathParameters.id, data = JSON.parse(event.body); todos.update(dynamoDb, id, data, (err, result) => { if (err) { callback(createResponse(500, { message: err.message })); } else { callback(null, createResponse(200, result)); } }); }; module.exports.todosDelete = (event, context, callback) => { const id = event.pathParameters.id; todos.delete(dynamoDb, id, (err, result) => { if (err) { callback(createResponse(500, { message: err.message })); } else { callback(null, createResponse(204)); } }); };  ### serverless.yml iamRoleStatementsYou bet Resourceswe are the right to create a table for access to DynamoDB using. This DynamoDB table made in the configuration DeletionPolicy: Retainbecause it specified, sls removewill not be deleted by the execution. If not required, it must be deleted separately using the AWS Console or the like. service: sls-dynamodb provider: name: aws runtime: nodejs4.3 stage:${opt:stage, self:custom.defaultStage}
region: ${opt:region, self:custom.defaultRegion} profile:${self:custom.profiles.${self:provider.stage}} iamRoleStatements: - Effect: Allow Action: - dynamodb:DescribeTable - dynamodb:Query - dynamodb:Scan - dynamodb:GetItem - dynamodb:PutItem - dynamodb:UpdateItem - dynamodb:DeleteItem Resource: "arn:aws:dynamodb:${self:provider.region}:*:table/${self:provider.stage}-*" custom: defaultStage: dev defaultRegion: ap-northeast-1 profiles: dev: devSls prod: prodSls writeEnvVars: STAGE:${self:provider.stage}

package:
exclude:
- .git/**
- node_modules/serverless-plugin-write-env-vars/**

plugins:
- serverless-plugin-write-env-vars

functions:
events:
- http:
path: todos
method: get
cors: true

events:
- http:
path: todos/{id}
method: get
cors: true

todosCreate:
handler: handler.todosCreate
events:
- http:
path: todos
method: post
cors: true

todosUpdate:
handler: handler.todosUpdate
events:
- http:
path: todos/{id}
method: patch
cors: true

todosDelete:
handler: handler.todosDelete
events:
- http:
path: todos/{id}
method: delete
cors: true

resources:
Resources:
TodosDynamoDbTable:
Type: 'AWS::DynamoDB::Table'
DeletionPolicy: Retain
Properties:
AttributeDefinitions:
-
AttributeName: id
AttributeType: S
KeySchema:
-
AttributeName: id
KeyType: HASH
ProvisionedThroughput:
WriteCapacityUnits: 1
TableName: "\${self:provider.stage}-todos"


### Try to move the sample

"For installation, etc. of Serverless Framework for starting the development make the Hello World in Serverless Framework Please refer to the".

### Sample of installation/deployment

If I can be connected to the installation of Serverless Framework and AWS, you can install/deploy the sample with the following command.

serverless install --url https://github.com/katsuhiko/sls-dynamodb
cd sls-dynamodb
npm install
serverless deploy -v


### Execution

Use the curl and run. "XXXX" part, please change put together in each environment.

curl https://XXXX.execute-api.ap-northeast-1.amazonaws.com/dev/todos


curl https://XXXX.execute-api.ap-northeast-1.amazonaws.com/dev/todos/<id>


### Create

curl -X POST https://XXXX.execute-api.ap-northeast-1.amazonaws.com/dev/todos --data '{ "content" : "Learn Serverless" }'


### Update

curl -X PATCH https://XXXX.execute-api.ap-northeast-1.amazonaws.com/dev/todos/<id> --data '{ "content" : "Understand Serverless" }'


### Delete

curl -X DELETE https://XXXX.execute-api.ap-northeast-1.amazonaws.com/dev/todos/<id>


### After tidying up

serverless remove -v


Since there remains a DynamoDB table is also in the above, remove the DynamoDB tables from the AWS Console or the like.

### Impressions

To use a DynamoDB was easy.

One point that was worrisome.

The zip of node_modules that are deployed on the Lambda is that it also includes the source about the plugin. (This is fine, but.)

Although we are package.exclude in serverless.yml, I thought that I want a mechanism to ensure that not include devDependencies of package.json.