(Update from future John: god this is boring. I hope it's helped someone somewhere somehow)
I was interested in learning how use DynamoDB, but didn't want to set it up on AWS personally because I'm lazy, and scared of accidentally getting billed for 10,000 euros.
Instead I decided to run it locally in a docker-container.
This article is going to walk through the process that I followed, in case you want to do something similar.
The first step is to create a docker-compose.yaml
.
Docker Compose let's us define containers that we want to run to support our
project. It's a pretty neat way to set up a development environment.
Here's the file I created
version: '3' # The version of docker-compose syntax we're using. Just pick 3 I guess
services: # We define the containers we want to create under this header
dynamodb:
image: amazon/dynamodb-local # The image we're using. Thanks Amazon.
container_name: dynamodb-local
ports:
- "8042:8000" # binds the localhost port on the left, to the container port on the right
You'll need docker installed for this step.
Run this command
docker-compose -f docker-compose.yaml up -d
-f
allows us specify the file to use, in our case this is the
docker-compose.yaml we just created
up
tells docker-compose to “build, (re)create, start, and attache to containers for a service.”
-d
specifies that we want to run the container in 'detached' mode.
Now our container should be running. Running docker ps
in the command line
should show that the container is alive and kicking.
To use DynamoDB in JavaScript, we're going to rely on the aws-sdk. So let's install it!
yarn add aws-sdk
And then let's use it to make a table!
const AWS = require('aws-sdk');
async function main() {
// Even though we're using the SDK locally the SDK will throw an error
// if these items are missing. We don't need to use real keys for local
// development however.
AWS.config.update({
region: 'local',
accessKeyId: 'random-not-real-id',
secretAccessKey: 'random-not-real-key',
})
// Now we create our Client!
const dynamoClient = new AWS.DynamoDB({ endpoint: 'http://localhost:8042' })
// And we can start making tables
try {
await dynamoClient.createTable({
// The name of our table
TableName: 'user-info',
// The attributes that our needed to create our primary key.
// We can still store other data as part of each item, but we don't need
// to define it as part of the table
AttributeDefinitions: [
{
AttributeName: 'name',
AttributeType: 'S',
}
],
// How the primary keys for our table are generated.
// In our case we are simply going to hash the attribute 'name'
KeySchema: [
{
AttributeName: 'name',
KeyType: 'HASH',
},
],
// Some Config stuff. Ask your ops team about this I guess.
ProvisionedThroughput: {
ReadCapacityUnits: 5,
WriteCapacityUnits: 5,
},
}).promise()
console.log('create table user-info')
} catch (e) {
console.error(error)
process.exit(1)
}
}
Although we only specified the attributes that are required to make each items primary key, we can store other data in each item.
A thing that puzzled me when looking at the DynamoDB sdk was the difference between a DynamoClient
and a DocumentClient
. We used the DynamoClient
to create our table above, but using that to add data actually becomes quite tricky. We have to painstakingly describe the different keys we'll be adding.
The document client seems to have been added to the SDK to make life easier for JavasScript developers. It gives us some methods that let us interact with our DB using normal JavaScript objects that match the shape of the data we want to store. More details can be seen in this announcement post.
Long story short, we're going to use the DocumentClient
to store data in our
table.
const docClient = new AWS.DynamoDB.DocumentClient({ endpoint: 'http://localhost:8042' })
Now to make our lives easier let's define a function that adds users to our table.
const addUser = async (name, email) => {
return docClient.put({
Item: {
name,
email
},
TableName: 'user-info'
}).promise()
}
and one to list all of our users
const listUsers = async () => {
return docClient.scan({
TableName: 'user-info'
}).promise()
}
We can then use these functions to add some users to our table, and then print them out again.
const addUsers = async () => {
await addUser('bobby', '[email protected]')
await addUser('tomboy', '[email protected]')
await addUser('blobby', '[email protected]')
console.log(await listUsers())
}
addUsers()
If we run this code we'll see the following output in our terminal
{
Items: [
{ name: 'bobby', email: '[email protected]' },
{ name: 'blobby', email: '[email protected]' },
{ name: 'tomboy', email: '[email protected]' }
],
Count: 3,
ScannedCount: 3
}
You'se now seen how to set up a local DynamoDB - and how to do some basic interaction with it in JavaScript. A runnable version of the code in this article can be found here.