├── .gitignore ├── testDynamo ├── config.js └── databaseManager.spec.js ├── package.json ├── README.md ├── databaseManager.js ├── handler.js └── serverless.yml /.gitignore: -------------------------------------------------------------------------------- 1 | # package directories 2 | node_modules 3 | jspm_packages 4 | 5 | # Serverless directories 6 | .serverless -------------------------------------------------------------------------------- /testDynamo/config.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Shared config and hooks for all tests. 3 | */ 4 | const path = require('path'); 5 | 6 | process.env.DOT_ENV_PATH = path.join(__dirname, '.env'); 7 | process.env.ITEMS_DYNAMODB_TABLE = 'sls-basic-operations-items-table'; 8 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "serverless-dynamo-basic-operations", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "jest", 8 | "watch": "jest --watch" 9 | }, 10 | "keywords": [], 11 | "author": "", 12 | "license": "ISC", 13 | "dependencies": { 14 | "aws-sdk": "^2.171.0", 15 | "chai": "^4.1.2", 16 | "jest": "^22.0.0", 17 | "serverless-dynamodb-local": "^0.2.26", 18 | "uuid": "^3.1.0" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # serverless-dynamo-basic-operations 2 | This code is for the video tutorial called: "Basic operations with DynamoDB", you can check the instructions on for this code in that video. 3 | 4 | [![Basic operations with DynamoDB | Serverless | FooBar](https://img.youtube.com/vi/EzgyTzJll5U/0.jpg)](https://youtu.be/EzgyTzJll5U "Basic operations with DynamoDB | Serverless | FooBar") 5 | 6 | You can check my youtube channel for more serverless videos: [Foobar Youtube Channel](https://www.youtube.com/foobar-codes). 7 | -------------------------------------------------------------------------------- /testDynamo/databaseManager.spec.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | require('./config'); 4 | 5 | const assert = require('chai').assert; 6 | const databaseManager = require('../databaseManager'); 7 | var AWS = require('aws-sdk'); 8 | 9 | beforeAll(() => { 10 | const dynamo = new AWS.DynamoDB.DocumentClient({ 11 | region: 'localhost', 12 | endpoint: 'http://localhost:8000' 13 | }); 14 | 15 | databaseManager.initializateDynamoClient(dynamo); 16 | }); 17 | 18 | afterAll(() => { 19 | const dynamo = new AWS.DynamoDB.DocumentClient(); 20 | databaseManager.initializateDynamoClient(dynamo); 21 | }); 22 | 23 | describe('Test database save and get item', () => { 24 | const item = { 25 | itemId: 'itemId', 26 | name: 'itemName', 27 | status: 'itemStatus' 28 | }; 29 | 30 | it('save an item', done => { 31 | databaseManager.saveItem(item).then(result => { 32 | assert.equal('itemId', result); 33 | done(); 34 | }); 35 | }); 36 | 37 | it('get an item', done => { 38 | databaseManager.getItem('itemId').then(result => { 39 | assert.equal(item.itemId, result.itemId); 40 | assert.equal(item.name, result.name); 41 | assert.equal(item.status, result.status); 42 | done(); 43 | }); 44 | }); 45 | }); 46 | -------------------------------------------------------------------------------- /databaseManager.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const AWS = require('aws-sdk'); 4 | let dynamo = new AWS.DynamoDB.DocumentClient(); 5 | 6 | const TABLE_NAME = process.env.ITEMS_DYNAMODB_TABLE; 7 | 8 | module.exports.initializateDynamoClient = newDynamo => { 9 | dynamo = newDynamo; 10 | }; 11 | 12 | module.exports.saveItem = item => { 13 | const params = { 14 | TableName: TABLE_NAME, 15 | Item: item 16 | }; 17 | 18 | return dynamo.put(params).promise().then(() => { 19 | return item.itemId; 20 | }); 21 | }; 22 | 23 | module.exports.getItem = itemId => { 24 | const params = { 25 | Key: { 26 | itemId: itemId 27 | }, 28 | TableName: TABLE_NAME 29 | }; 30 | 31 | return dynamo.get(params).promise().then(result => { 32 | return result.Item; 33 | }); 34 | }; 35 | 36 | module.exports.deleteItem = itemId => { 37 | const params = { 38 | Key: { 39 | itemId: itemId 40 | }, 41 | TableName: TABLE_NAME 42 | }; 43 | 44 | return dynamo.delete(params).promise(); 45 | }; 46 | 47 | module.exports.updateItem = (itemId, paramsName, paramsValue) => { 48 | const params = { 49 | TableName: TABLE_NAME, 50 | Key: { 51 | itemId 52 | }, 53 | ConditionExpression: 'attribute_exists(itemId)', 54 | UpdateExpression: 'set ' + paramsName + ' = :v', 55 | ExpressionAttributeValues: { 56 | ':v': paramsValue 57 | }, 58 | ReturnValues: 'ALL_NEW' 59 | }; 60 | 61 | return dynamo.update(params).promise().then(response => { 62 | return response.Attributes; 63 | }); 64 | }; 65 | -------------------------------------------------------------------------------- /handler.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const databaseManager = require('./databaseManager'); 4 | const uuidv1 = require('uuid/v1'); 5 | 6 | function createResponse(statusCode, message) { 7 | return { 8 | statusCode: statusCode, 9 | body: JSON.stringify(message) 10 | }; 11 | } 12 | 13 | module.exports.saveItem = (event, context, callback) => { 14 | const item = JSON.parse(event.body); 15 | console.log(item); 16 | item.itemId = uuidv1(); 17 | 18 | databaseManager.saveItem(item).then(response => { 19 | console.log(response); 20 | callback(null, createResponse(200, response)); 21 | }); 22 | }; 23 | 24 | module.exports.getItem = (event, context, callback) => { 25 | const itemId = event.pathParameters.itemId; 26 | 27 | databaseManager.getItem(itemId).then(response => { 28 | console.log(response); 29 | callback(null, createResponse(200, response)); 30 | }); 31 | }; 32 | 33 | module.exports.deleteItem = (event, context, callback) => { 34 | const itemId = event.pathParameters.itemId; 35 | 36 | databaseManager.deleteItem(itemId).then(response => { 37 | callback(null, createResponse(200, 'Item was deleted')); 38 | }); 39 | }; 40 | 41 | module.exports.updateItem = (event, context, callback) => { 42 | const itemId = event.pathParameters.itemId; 43 | 44 | const body = JSON.parse(event.body); 45 | const paramName = body.paramName; 46 | const paramValue = body.paramValue; 47 | 48 | databaseManager.updateItem(itemId, paramName, paramValue).then(response => { 49 | console.log(response); 50 | callback(null, createResponse(200, response)); 51 | }); 52 | }; 53 | 54 | module.exports.triggerStream = (event, context, callback) => { 55 | console.log('trigger stream was called'); 56 | 57 | const eventData = event.Records[0]; 58 | //console.log(eventData); 59 | 60 | console.log(eventData.dynamodb.NewImage); 61 | callback(null, null); 62 | }; 63 | -------------------------------------------------------------------------------- /serverless.yml: -------------------------------------------------------------------------------- 1 | service: serverless-dynamo-basic-operations 2 | 3 | plugins: 4 | - serverless-dynamodb-local 5 | 6 | custom: 7 | myStage: ${opt:stage, self:provider.stage} 8 | settings: 9 | dev: 10 | ITEMS_DYNAMODB_TABLE: sls-basic-operations-items-dev 11 | prod: 12 | ITEMS_DYNAMODB_TABLE: sls-basic-operations-items-prod 13 | 14 | provider: 15 | name: aws 16 | runtime: nodejs6.10 17 | profile: default 18 | region: eu-west-1 19 | environment: ${self:custom.settings.${self:custom.myStage}} 20 | 21 | iamRoleStatements: 22 | - Effect: "Allow" 23 | Action: 24 | - "dynamodb:GetItem" 25 | - "dynamodb:PutItem" 26 | - "dynamodb:UpdateItem" 27 | - "dynamodb:DeleteItem" 28 | - "dynamodb:ListStreams" 29 | Resource: 30 | - "arn:aws:dynamodb:${self:provider.region}:*:table/${self:custom.settings.${self:custom.myStage}.ITEMS_DYNAMODB_TABLE}" 31 | 32 | functions: 33 | saveItem: 34 | handler: handler.saveItem 35 | events: 36 | - http: 37 | path: item 38 | method: post 39 | getItem: 40 | handler: handler.getItem 41 | events: 42 | - http: 43 | path: item/{itemId} 44 | method: get 45 | deleteItem: 46 | handler: handler.deleteItem 47 | events: 48 | - http: 49 | path: item/{itemId} 50 | method: delete 51 | updateItem: 52 | handler: handler.updateItem 53 | events: 54 | - http: 55 | path: item/{itemId} 56 | method: put 57 | triggerStream: 58 | handler: handler.triggerStream 59 | events: 60 | - stream: 61 | type: dynamodb 62 | batchSize: 1 63 | startingPosition: LATEST 64 | arn: 65 | Fn::GetAtt: 66 | - ImagesTable 67 | - StreamArn 68 | 69 | resources: 70 | Resources: 71 | ImagesTable: 72 | Type: "AWS::DynamoDB::Table" 73 | Properties: 74 | AttributeDefinitions: 75 | - AttributeName: "itemId" 76 | AttributeType: "S" 77 | KeySchema: 78 | - AttributeName: "itemId" 79 | KeyType: "HASH" 80 | ProvisionedThroughput: 81 | ReadCapacityUnits: 1 82 | WriteCapacityUnits: 1 83 | TableName: ${self:custom.settings.${self:custom.myStage}.ITEMS_DYNAMODB_TABLE} 84 | StreamSpecification: 85 | StreamViewType: NEW_IMAGE 86 | --------------------------------------------------------------------------------