How to create and access DynamoDB tables for local development in a Serverless Framework project - all without using any plugins!
Example source code from article Using DynamoDB Locally in a Serverless Framework project.
How to create and access DynamoDB tables for local development in a Serverless Framework project - all without using any plugins!
Example source code from article Using DynamoDB Locally in a Serverless Framework project.
const fs = require('fs') | |
const DynamoDB = require('aws-sdk/clients/dynamodb') | |
const yaml = require('js-yaml') | |
const cloudformationSchema = require('@serverless/utils/cloudformation-schema') | |
const SERVERLESS_CONFIG = __dirname + '/serverless.yml' | |
const ddb = new DynamoDB({ | |
accessKeyId: 'fake-key', | |
endpoint: 'http://localhost:8001', | |
region: 'local', | |
secretAccessKey: 'fake-secret', | |
}) | |
async function getDynamoDBTableResources() { | |
const tables = Object.entries( | |
yaml.loadAll(fs.readFileSync(SERVERLESS_CONFIG), { | |
schema: cloudformationSchema, | |
})[0].resources.Resources, | |
).filter( | |
([, resource]) => | |
resource.Type === 'AWS::DynamoDB::Table', | |
) | |
return tables | |
} | |
;(async function main() { | |
console.info('Setting up local DynamoDB tables') | |
const tables = await getDynamoDBTableResources() | |
const existingTables = (await ddb.listTables().promise()) | |
.TableNames | |
for await ([logicalId, definition] of tables) { | |
const { | |
Properties: { | |
BillingMode, | |
TableName, | |
AttributeDefinitions, | |
KeySchema, | |
GlobalSecondaryIndexes, | |
LocalSecondaryIndexes, | |
}, | |
} = definition | |
if ( | |
existingTables.find((table) => table === TableName) | |
) { | |
console.info( | |
`${logicalId}: DynamoDB Local - Table already exists: ${TableName}. Skipping..`, | |
) | |
continue | |
} | |
const result = await ddb | |
.createTable({ | |
AttributeDefinitions, | |
BillingMode, | |
KeySchema, | |
LocalSecondaryIndexes, | |
GlobalSecondaryIndexes, | |
TableName, | |
}) | |
.promise() | |
console.info( | |
`${logicalId}: DynamoDB Local - Created table: ${TableName}`, | |
) | |
} | |
})() |
version: '2.1' | |
services: | |
dynamodb: | |
image: amazon/dynamodb-local:latest | |
command: -jar DynamoDBLocal.jar -sharedDb -inMemory -port 8001 | |
ports: | |
- '8001:8001' | |
hostname: dynamodb.localhost | |
working_dir: /home/dynamodblocal |
const DynamoDB = require('aws-sdk/clients/dynamodb') | |
// If the code is running locally, we point the | |
// DynamoDB client at our local instance of | |
// DynamoDB Local, otherwise we point it at the | |
// real AWS DynamoDB. | |
const ddbClient = new DynamoDB.DocumentClient({ | |
service: | |
typeof process.env.AWS_ACCESS_KEY_ID === 'undefined' | |
? new DynamoDB({ | |
accessKeyId: 'fake-key', | |
endpoint: 'http://localhost:1338', | |
region: 'local', | |
secretAccessKey: 'fake-secret', | |
}) | |
: new DynamoDB(), | |
}) | |
module.exports.handler = async function handler(event) { | |
const { pk, id } = event | |
const result = await ddbClient | |
.get({ | |
TableName: process.env.DYNAMODB_TABLE, | |
Key: { pk, id }, | |
}) | |
.promise() | |
return result.Item | |
} |
const DynamoDB = require('aws-sdk/clients/dynamodb') | |
const { nanoid } = require('nanoid') | |
const { handler } = require('./example') | |
process.env.DYNAMODB_TABLE = 'example' | |
const ddb = new DynamoDB.DocumentClient({ | |
service: new DynamoDB({ | |
accessKeyId: 'fake-key', | |
endpoint: 'http://localhost:8001', | |
region: 'local', | |
secretAccessKey: 'fake-secret', | |
}), | |
}) | |
describe('example handler', () => { | |
it('should return an item from DynamoDB specified by key', async () => { | |
const testItem = { | |
pk: 'test-pk-' + nanoid(), | |
sk: 'test-sk-' + nanoid(), | |
} | |
await ddb | |
.put({ | |
TableName: process.env.DYNAMODB_TABLE, | |
Item: testItem, | |
}) | |
.promise() | |
const result = await handler(testItem) | |
expect(result).toMatchObject(testItem) | |
}) | |
}) |
{ | |
"name": "example", | |
"scripts": { | |
"setup:dynamodb": "node create-tables-locally.js", | |
"up": "docker-compose up -d", | |
"postup": "npm run setup:dynamodb", | |
"down": "docker-compose down", | |
"pretest": "npm run up", | |
"test": "jest --passWithNoTests", | |
"posttest": "npm run down", | |
"pretest:watch": "npm run up", | |
"test:watch": "jest --watch" | |
}, | |
"dependencies": { | |
"aws-sdk": "2.906.0" | |
}, | |
"devDependencies": { | |
"jest": "27.0.6", | |
"js-yaml": "4.1.0", | |
"nanoid": "3.1.23", | |
"serverless": "2.55.0" | |
} | |
} |
service: example | |
provider: | |
name: aws | |
runtime: nodejs14.x | |
functions: | |
example: | |
description: An example lambda function | |
handler: example.handler | |
memorySize: 256 | |
role: LambdaRole | |
environment: | |
DYNAMODB_TABLE: !Ref DynamoDBExampleTable | |
resources: | |
Resources: | |
DynamoDBExampleTable: | |
Type: AWS::DynamoDB::Table | |
Properties: | |
TableName: example | |
SSESpecification: | |
SSEEnabled: true | |
BillingMode: PAY_PER_REQUEST | |
AttributeDefinitions: | |
- AttributeName: pk | |
AttributeType: S | |
- AttributeName: sk | |
AttributeType: S | |
- AttributeName: sk2 | |
AttributeType: S | |
KeySchema: | |
- AttributeName: pk | |
KeyType: HASH | |
- AttributeName: sk | |
KeyType: RANGE | |
GlobalSecondaryIndexes: | |
- IndexName: pk-sk2 | |
KeySchema: | |
- AttributeName: pk | |
KeyType: HASH | |
- AttributeName: sk2 | |
KeyType: RANGE | |
Projection: | |
ProjectionType: ALL | |
LambdaRole: | |
Type: AWS::IAM::Role | |
Properties: | |
AssumeRolePolicyDocument: | |
Statement: | |
- Effect: Allow | |
Principal: | |
Service: lambda.amazonaws.com | |
Action: sts:AssumeRole | |
ManagedPolicyArns: | |
- arn:aws:iam::aws:policy/AWSXrayWriteOnlyAccess | |
- arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole | |
Policies: | |
- PolicyName: dynamodb | |
PolicyDocument: | |
Statement: | |
- Effect: Allow | |
Action: | |
- 'dynamodb:BatchGetItem' | |
- 'dynamodb:BatchWriteItem' | |
- 'dynamodb:PutItem' | |
- 'dynamodb:DeleteItem' | |
- 'dynamodb:GetItem' | |
- 'dynamodb:Scan' | |
- 'dynamodb:Query' | |
- 'dynamodb:UpdateItem' | |
- 'dynamodb:PartiQL*' | |
Resource: | |
- !GetAtt DynamoDBExampleTable.Arn | |
- !Sub | |
- ${Table}/* | |
- Table: !GetAtt DynamoDBExampleTable.Arn |