Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save mauricionobrega/8631cdb388591698780624e6e3f31cce to your computer and use it in GitHub Desktop.
Save mauricionobrega/8631cdb388591698780624e6e3f31cce to your computer and use it in GitHub Desktop.
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
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment