Use DynamoDB in NestJS Application With Serverless Framework on AWS

Muhd Mohaiminul Islam
Jan 16 · 4 min read

In this article, we’re going to learn how we can use DynamoDB in the NestJS application using the Serverless framework on the AWS platform.

Image for post
Image for post
DynamoDB in NestJS application with Serverless framework on AWS

Before we proceed, first we need to set up a NestJS application into the Serverless framework.

Once done the setup of the NestJS application in the Serverless framework, we can proceed with our hands-on steps.

Hands-on Steps:

This node package that we need to install first before we proceed.

npm install --save aws-sdk

Here we need to add all these additional configurations of DynamoDB and its permission for the Serverless application.

// serverless.yml...provider:
...
environment:
...
USERS_TABLE_NAME: ${self:custom.usersTable.name}
iamRoleStatements: ${file(iam/usersTableIAM.yml)}
resources:
Resources:
usersTable: ${file(resources/usersTable.yml):usersTable}
...custom:
usersTable:
name: ${self:provider.stage}-users
arn: !GetAtt usersTable.Arn

These are the permissions of DynamoDB that need to present in Serverless configurations.

// iam/usersTableIAM.yml- Effect: 'Allow'
Action:
- 'dynamodb:Query'
- 'dynamodb:Scan'
- 'dynamodb:GetItem'
- 'dynamodb:PutItem'
- 'dynamodb:UpdateItem'
- 'dynamodb:DeleteItem'
Resource:
- ${self:custom.usersTable.arn}

These are the definitions of the User table that need to present in Serverless configurations.

// resources/usersTable.ymlusersTable:
Type: AWS::DynamoDB::Table
Properties:
TableName: ${self:custom.usersTable.name}
AttributeDefinitions:
- AttributeName: id
AttributeType: S
KeySchema:
- AttributeName: id
KeyType: HASH
BillingMode: PAY_PER_REQUEST

We need to run these commands to create a User module with its controller and service.

nest generate module user
nest generate controller user --no-spec
nest generate service user --no-spec

Here we need to define all the endpoints that the User module allows access to everyone.

// src/user/user.controller.tsimport {
Body,
Controller,
Get,
NotFoundException,
Param,
Post,
} from '@nestjs/common';
import { UserService } from './user.service';
@Controller('user')
export class UserController {
constructor(private readonly userService: UserService) {}

@Post()
async createUser(@Body() body: any): Promise<any> {
const user = await this.userService.createUser(body);

return { status: true, data: user };
}
@Get(':id')
async getUserById(@Param() { id }: any): Promise<any> {
const user = await this.userService.getUserById(id);
if (!user) {
throw new NotFoundException(`User with ID "${id}" not found`);
}
return { status: true, data: user };
}
}

Here we need to define all the implementations that the User controller needs to take care of.

// src/user/user.service.tsimport { Injectable, InternalServerErrorException } from '@nestjs/common';
import * as AWS from 'aws-sdk';
import { v4 as uuid } from 'uuid';
const dynamoDB = new AWS.DynamoDB.DocumentClient();@Injectable()
export class UserService {
async createUser(dto: any): Promise<any> {
const user = {
id: uuid(),
...dto,
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
};
try {
await dynamoDB
.put({
TableName: process.env.USERS_TABLE_NAME,
Item: user,
})
.promise();
} catch (error) {
throw new InternalServerErrorException(error);
}
return user;
}
async getUserById(id: string): Promise<any> {
let user;
try {
const result = await dynamoDB
.get({
TableName: process.env.USERS_TABLE_NAME,
Key: { id },
})
.promise();
user = result.Item;
} catch (error) {
throw new InternalServerErrorException(error);
}
return user;
}
}

Make sure, we always build our application before deploying to AWS. Because all the changes will reflect after the build process is successful as we upload the files from the dist directory into AWS S3.

npm run build && serverless deploy

AWS DynamoDB Local:

To speed up our development cycles, we can run and test our application on our local machine. And as we use DynamoDB, therefore, we can add this serverless-dynamodb-local plugin to run our Serverless application to run in the local machine.

Install this npm package before we proceed.

npm install --save serverless-dynamodb-local

We need to add this serverless-dynamodb-local plugin in our Serverless configuration file with other changes.

// serverless.yml...plugins:
- serverless-dynamodb-local
...
provider:
...
environment:
...
DYNAMODB_ENDPOINT: ${self:custom.endpoints.dynamodbURL}
...
custom:
dynamodb:
stages:
- ${self:provider.stage}
start:
migrate: true
endpoints:
dynamodbURL: 'http://localhost:8000'
...
...

We need to modify the DocumentClient declaration for DynamoDB to check whether we use the local endpoint or not during the process.

// src/user/user.service.ts...let dynamoDB;
if (process.env.IS_OFFLINE === 'true') {
dynamoDB = new AWS.DynamoDB.DocumentClient({
region: 'localhost',
endpoint: process.env.DYNAMODB_ENDPOINT,
});
} else {
dynamoDB = new AWS.DynamoDB.DocumentClient();
}
...

Same as before, we always build our application before running the application. Because all the changes will reflect after the build process is successful as our build codes point to the dist directory.

serverless dynamodb installnpm run build && serverless offline start

The Startup

Medium's largest active publication, followed by +771K people. Follow to join our community.

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store