Guide to Initializing and Connecting AWS DynamoDB

Introduction

Amazon DynamoDB is a fully managed NoSQL database service that provides fast and predictable performance with seamless scalability at any scale.

Key benefits include: unlimited scalability, extremely low latency in milliseconds, built-in security, and flexible pricing models based on usage (On-demand) to optimize costs.

Detail

Use AWS CDK to create the lib/dynamodb-stack.ts file

import * as cdk from "aws-cdk-lib"
import * as dynamodb from "aws-cdk-lib/awsf-dynamodb"
import { Construct } from "constructs"

export class DynamodbStack extends cdk.Stack {
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props)

const productTable = new dynamodb.Table(this, "ProductTable", {
tableName: "Products",
partitionKey: {
name: "id",
type: dynamodb.AttributeType.STRING,
},
billingMode: dynamodb.BillingMode.PAY_PER_REQUEST,
removalPolicy: cdk.RemovalPolicy.DESTROY,
})

new cdk.CfnOutput(this, "ProductTableArn", {
value: productTable.tableArn,
exportName: "ProductTableArn",
})
}
}

This code snippet uses AWS CDK to define and initialize a DynamoDB table named "Products" with the primary key "id", configure On-demand billing based on actual throughput, and set up a table removal policy for when the stack is destroyed.


Update the bin/aws-cdk.ts file

#!/usr/bin/env node
import 'dotenv/config';
import * as cdk from "aws-cdk-lib/core"
import { DynamodbStack } from '../lib/dynamodb-stack';

const app = new cdk.App()
new DynamodbStack(app, "DynamodbStack")


To use DynamoDB in a NestJS project, first install the following packages

npm install @aws-sdk/client-dynamodb @aws-sdk/lib-dynamodb


Create the dynamodb.service.ts file

import {Injectable, NotFoundException} from '@nestjs/common'
import {DynamoDBClient} from '@aws-sdk/client-dynamodb'
import {
DynamoDBDocumentClient,
PutCommand,
GetCommand,
UpdateCommand,
DeleteCommand,
ScanCommand,
} from '@aws-sdk/lib-dynamodb'
import {v4 as uuidv4} from 'uuid'

@Injectable()
export class DynamoDBService {
private readonly docClient: DynamoDBDocumentClient
private readonly tableName = 'Products'

constructor() {
const client = new DynamoDBClient()
this.docClient = DynamoDBDocumentClient.from(client)
}

async createProduct(data: {name: string; price: number}) {
const product = {
id: uuidv4(),
name: data.name,
price: data.price,
createdAt: new Date().toISOString(),
}

await this.docClient.send(
new PutCommand({
TableName: this.tableName,
Item: product,
})
)
return product
}

async getProduct(id: string) {
const result = await this.docClient.send(
new GetCommand({
TableName: this.tableName,
Key: {id},
})
)

if (!result.Item) {
throw new NotFoundException(`Not found ID ${id}`)
}
return result.Item
}

async getAllProducts() {
const result = await this.docClient.send(
new ScanCommand({
TableName: this.tableName,
})
)
return result.Items || []
}

async updateProduct(id: string, data: {name?: string; price?: number}) {
const result = await this.docClient.send(
new UpdateCommand({
TableName: this.tableName,
Key: {id},
UpdateExpression: 'set #n = :name, price = :price',
ExpressionAttributeNames: {
'#n': 'name',
},
ExpressionAttributeValues: {
':name': data.name,
':price': data.price,
},
ReturnValues: 'ALL_NEW',
})
)

return result.Attributes
}

async deleteProduct(id: string) {
await this.docClient.send(
new DeleteCommand({
TableName: this.tableName,
Key: {id},
})
)
return {message: `Delete completed ${id}`}
}
}

This is the Service class that performs CRUD (Create, Read, Update, Delete) operations and Table Scans on the DynamoDB table using the AWS SDK, while handling the logic to generate unique IDs using uuid.


Create the dynamodb.controller.ts file

import {Controller, Get, Post, Body, Param, Put, Delete} from '@nestjs/common'
import {DynamoDBService} from 'src/service/dynamodb.service'

@Controller('dynamodb')
export class DynamoDBController {
constructor(private readonly dynamoDBService: DynamoDBService) {}

@Post()
create(@Body() body: {name: string; price: number}) {
return this.dynamoDBService.createProduct(body)
}

@Get()
findAll() {
return this.dynamoDBService.getAllProducts()
}

@Get(':id')
findOne(@Param('id') id: string) {
return this.dynamoDBService.getProduct(id)
}

@Put(':id')
update(
@Param('id') id: string,
@Body() body: {name?: string; price?: number}
) {
return this.dynamoDBService.updateProduct(id, body)
}

@Delete(':id')
remove(@Param('id') id: string) {
return this.dynamoDBService.deleteProduct(id)
}
}

This Controller class defines HTTP API endpoints like GET, POST, PUT, DELETE to receive user requests and route them to the corresponding methods in the DynamoDBService.


Update the app.module.ts file to use the controller and service

import {Module} from '@nestjs/common'
import {DynamoDBService} from './service/dynamodb.service'
import {DynamoDBController} from './controller/dynamodb.controller'

@Module({
controllers: [DynamoDBController],
providers: [DynamoDBService],
})
export class AppModule {}


Testing with Postman yields the following results






Or you can query directly on the AWS web console.

Happy coding!

See more articles here.

Comments

Popular posts from this blog

All Practice Series

Deploying a NodeJS Server on Google Kubernetes Engine

Kubernetes Deployment for Zero Downtime

Setting up Kubernetes Dashboard with Kind

Using Kafka with Docker and NodeJS

Monitoring with cAdvisor, Prometheus and Grafana on Docker

Practicing with Google Cloud Platform - Google Kubernetes Engine to deploy nginx

Kubernetes Practice Series

NodeJS Practice Series

Sitemap