DynamoDB as a Serverless Service
While creating a Serverless application with multiple services, you might want to split the DynamoDB portion out separately. This can be useful because you are probably not going to be making changes to this very frequently. Also, if you have multiple development environments, it is not likely that you are going to connect them to different database environments. For example, you might give the developers on your team their own environment but they might all connect to the same DynamoDB environment. So it would make sense to configure DynamoDB separately from the application API services.
In the example repo, you’ll notice that we have a database
service in the services/
directory. And the serverless.yml
in this service helps us manage our DynamoDB table.
service: notes-app-mono-database
custom:
# Our stage is based on what is passed in when running serverless
# commands. Or fallsback to what we have set in the provider section.
stage: ${opt:stage, self:provider.stage}
# Set our DynamoDB throughput for prod and all other non-prod stages.
tableThroughputs:
prod: 5
default: 1
tableThroughput: ${self:custom.tableThroughputs.${self:custom.stage}, self:custom.tableThroughputs.default}
provider:
name: aws
runtime: nodejs8.10
stage: dev
region: us-east-1
resources:
Resources:
NotesTable:
Type: AWS::DynamoDB::Table
Properties:
# Generate a name based on the stage
TableName: ${self:custom.stage}-mono-notes
AttributeDefinitions:
- AttributeName: userId
AttributeType: S
- AttributeName: noteId
AttributeType: S
KeySchema:
- AttributeName: userId
KeyType: HASH
- AttributeName: noteId
KeyType: RANGE
# Set the capacity based on the stage
ProvisionedThroughput:
ReadCapacityUnits: ${self:custom.tableThroughput}
WriteCapacityUnits: ${self:custom.tableThroughput}
Outputs:
NotesTableArn:
Value:
Fn::GetAtt:
- NotesTable
- Arn
Export:
Name: ${self:custom.stage}-NotesTableArn
NotesTableName:
Value:
Ref: NotesTable
Export:
Name: ${self:custom.stage}-NotesTable
If you have followed along with Part II of our guide, the Resources:
section should seem familiar. It is creating the Notes table that we use in our note taking application. The key addition here in regards to the cross-stack references is in the Outputs:
section. Let’s go over them quickly.
-
We are exporting two values here. The
NotesTableArn
is the ARN of the DynamoDB table that we are creating. And theNotesTableName
which is the name of the table being created. The ARN is necessary for any IAM roles that are going to reference the DynamoDB table. The table name on the other hand is what we need in our Lambda functions while making queries to it. -
The export names for both the values is based on the stage we are using to deploy this service -
${self:custom.stage}
. This is important because we want our entire application to be easily replicable across multiple stages. If we don’t include the stage name the exports will thrash when we deploy to multiple stages. -
The names of the exported values are
${self:custom.stage}-NotesTableArn
and${self:custom.stage}-NotesTable
. -
We get the table ARN by using the
Fn::GetAtt
CloudFormation function. This function takes a reference from the current service and the attribute we need. The reference in this case isNotesTable
. You’ll notice that the table we created in theResources:
section is created usingNotesTable
as the name. -
And finally, for a DynamoDB table resource the ref returns the generated table name. We use this value when we are exporting the table name.
When we deploy this service we’ll notice the exported values in the output and we can reference these cross-stack in our other services.
Next we’ll do something similar for our S3 bucket.
If you liked this post, please subscribe to our newsletter, give us a star on GitHub, and follow us on Twitter.
For help and discussion
Comments on this chapterFor reference, here is the code so far
Mono-repo Backend Source