Nest js with AWS Dynamo DB 🚀🚀

Nest js with AWS Dynamo DB using Amazon DynamoDB DataMapper 🚀🚀

What is DynamoDB?

DynamoDB is a hosted NoSQL database offered by Amazon Web Services (AWS). It offers:

reliable performance even as it scales; a managed experience, so you won't be SSH-ing into servers to upgrade the crypto libraries; a small, simple API allowing for simple key-value access as well as more advanced query patterns. DynamoDB is a particularly good fit for the following use cases:

Applications with large amounts of data and strict latency requirements. As your amount of data scales, JOINs and advanced SQL operations can slow down your queries. With DynamoDB, your queries have predictable latency up to any size, including over 100 TBs!

Serverless applications using AWS Lambda. AWS Lambda provides auto-scaling, stateless, ephemeral compute in response to event triggers. DynamoDB is accessible via an HTTP API and performs authentication & authorization via IAM roles, making it a perfect fit for building Serverless applications.

Data sets with simple, known access patterns. If you're generating recommendations and serving them to users, DynamoDB's simple key-value access patterns make it a fast, reliable choice.

On aws we may want to use Dynamo for our APIs

Lets see how we can do this with nestjs

for Other database like SQL we always use some kind of ORM to deal with database like

  • knex
  • typeorm
  • sequelize

and may be some other ORM, now we are talking here about AWS managed solution Dynamo DB so we don't have pre installed local setup fpr this we have to access AWS managed database only from AWS account.

Some simple javascript solution provided by data mapper library using which we can query dynamo Table

We can setup new nestjs app

Setting up a new project is quite simple with the Nest CLI. With npm installed, you can create a new Nest project with the following commands in your OS terminal:

$ npm i -g @nestjs/cli
$ nest new project-name

The project-name directory will be created, node modules and a few other boilerplate files will be installed, and a src/ directory will be created and populated with several core files.

We can create a dynamo Module and simple Service on top of Query data mapper AWS library

// Package.
import { Injectable } from "@nestjs/common";
import { DynamoDB } from "aws-sdk";
import { DataMapper, QueryIterator } from "@aws/dynamodb-data-mapper";

// Internal.
import { AppConfigService } from "@lib/config";

// Code.
@Injectable()
export class DynamoDBDataMapperService {
  private client: DynamoDB;
  public mapper: DataMapper;

  constructor(private configService: AppConfigService) {
    this.client = new DynamoDB({
      region: "REGION",
    });
    this.mapper = new DataMapper({ client: this.client });
  }

  async put(params: any): Promise<any> {
    return await this.mapper.put(params);
  }

  async scan(domain: any) {
    const response = [];
    for await (const item of this.mapper.scan(domain)) {
      // individual items will be yielded as the scan is performed
      response.push(item);
    }
    return response;
  }

  async delete(item: any): Promise<void> {
    await this.mapper.delete(item);
  }

  async update(item: any): Promise<any> {
    return await this.mapper.update(item);
  }

  async query(
    entity: any,
    query: any,
    options?: {
      indexName?: string;
    }
  ): Promise<QueryIterator<typeof entity>> {
    return await this.mapper.query(entity, query, options);
  }

  async get(entity: any): Promise<typeof entity> {
    return await this.mapper.get(entity);
  }
}

This service contains basic Dynamo DB operations like put, update, query,scan

// Package.
import { Global, Module } from "@nestjs/common";

// Internal.
import { AppConfigModule } from "@lib/config";
import { DynamoDBDataMapperService } from "./dynamodb.service";

// Code.
@Global()
@Module({
  imports: [AppConfigModule],
  providers: [DynamoDBDataMapperService],
  exports: [DynamoDBDataMapperService],
})
export class DynamoDBDataMapperModule {}

Now we just need AWS credentials and Dynamo DB NO Sql schema mapper file

import { config } from "aws-sdk";

 config.update({
    accessKeyId: process.env.MERCANIS_AWS_ACCESS_KEY,
    secretAccessKey: process.env.MERCANIS_AWS_SECRET_ACCESS,
    region: process.env.MERCANIS_AWS_REGION,
    signatureVersion: "v4",
  });

Lets build a simple CRUD operation with simple dynamo Table Dynamo DB Table with basic columns, while creating this dynamo table through either aws-cdk or any manually we can set sort key and partition keys.

import {
  attribute,
  autoGeneratedHashKey,
  table,
} from "@aws/dynamodb-data-mapper-annotations";

@table(`notes-${process.env.STAGE}`)
export class NotesCrud {
  @autoGeneratedHashKey()
  id: string;

  @attribute()
  description?: object;

  @attribute()
  name: string;

  @attribute()
  notes: string;


  @attribute()
  created_at: string;

  @attribute()
  updated_at: string;
}

Now the core part is how to access this using dynamo DB Module service and write CRUD operation which can be accessed by nestjs controllers, This is our dao service which is using DynamoDBDataMapperService to access dynamo DB Table

import { Injectable } from "@nestjs/common";
import { DynamoDBDataMapperService } from "@lib/dynamodb/dynamodb.service";
import { NotesCrud } from "./notes.schema";

@Injectable()
export default class CrudDaoService {
  constructor(private readonly ddb: DynamoDBDataMapperService) {}

  async create(payload: Partial<NotesCrud>) {
    try {
      return this.ddb.put(payload);
    } catch (err) {
      return err;
    }
  }
  async update(payload: Partial<NotesCrud>) {
    try {
      return this.ddb.update(payload);
    } catch (err) {
      return err;
    }
  }
  async delete(payload: Partial<NotesCrud>) {
    try {
      return this.ddb.delete(payload);
    } catch (err) {
      return err;
    }
  }
  async getById(milestoneId: string) {
    const record: NotesCrud = await this.ddb.get(
      Object.assign(new NotesCrud(), {
        id: milestoneId,
      })
    );
    return record;
  }
}

This is the overall flow controllers -> Service -> CrudDaoService -> DynamoDBDataMapperService we are running simple operations like getById, update, delete and create

Conclusion

I hope this example is helpful for those who wants to explore nestjs api services with dynamo DB AWS

References

Comments