2 min read

Integrate Dapr with Nest.js and the Dapr JS SDK

Integrate Dapr with Nest.js and the Dapr JS SDK

As the official maintainer of the Dapr JS SDK, I am always looking on how we can improve our documentation, tooling and API to integrate Dapr through Javascript.

Recently, I started working on Tinx.ai where I am using Dapr to host the Backend and send events to my event queue. So in this blog article, I wanted to dive a bit deeper on how you can integrate Dapr utilizing Nestjs

File Structure

The first thing we should do is to create our file structure containing our NestJS project:

💡 To learn more on how you can bootstrap a NestJS project, check out their documentation
src/
    main.ts             # NestJS Bootstrap (see https://docs.nestjs.com/first-steps)
    app.module.ts       # App Module
    config/config.ts    # Config 
    dapr/
        dapr.module.ts  # Dapr module main entry point
        dapr.service.ts # Dapr Service containing our functions

Create a Nest Dapr Module

Once our file structure is created we can configure our module and make it available to NestJS

src/dapr/dapr.module.ts

import { Module } from "@nestjs/common";
import { ConfigModule } from "@nestjs/config";
import { DaprService } from "./dapr.service";

@Module({
    // List of imported modules
    imports: [ ConfigModule ],

    // List of controllers
    controllers: [ ],

    // Providers that will be instantiated by the Nest injector and that may be shared at least across this module
    providers: [ DaprService ],

    // which providers can be used in other modules?
    exports: [ DaprService ]
})
export class DaprModule {}

The code above will utilize the Config module (which we use to inject configuration into our service later on) as well as the Dapr Service that we will create that holds the Dapr JS SDK methods.

Finally, register this module in the app.module.ts file:

import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import configuration from '../config/config';
import { DaprModule } from './dapr/dapr.module';

@Module({
  imports: [
    ConfigModule.forRoot({
      load: [configuration],
    }), // https://docs.nestjs.com/techniques/configuration
    DaprModule
  ],
  controllers: [],
  providers: [],
})
export class AppModule;

src/dapr/dapr.service.ts

Now we have our module registered, let's create the service class that helps us access the Dapr JS SDK:

import { Injectable, Logger } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { DaprClient } from 'dapr-client';

@Injectable()
export class DaprService {
  daprClient: DaprClient;
  private readonly logger = new Logger(DaprService.name);

  constructor(
    private readonly configService: ConfigService
  ) {
    const daprHost = this.configService.get<string>('third_party.dapr.host');
    const daprPort = this.configService.get<string>('third_party.dapr.port');

    this.logger.log(`Initializing DaprClient("${daprHost}", ${daprPort})`);
    this.daprClient = new DaprClient(daprHost, daprPort);
  }
}

As you can see, we are accessing third_party.dapr.host and third_party.dapr.port here that pull information from the config/config.ts file. So go ahead and utilize the following config:

export default () => ({
  third_party: {
    dapr: {
      host: process.env.DAPR_SIDECAR_HOST || '127.0.0.1',
      port: process.env.DAPR_SIDECAR_PORT || '3500',
    }
  },
});

Utilize the Nest Module

Now we created our module, we can import it to any of our Nest modules (add it under imports: [ DaprModule ], more info here) and start utilizing it.

import { Controller, Get, HttpCode, Req, Logger } from '@nestjs/common';
import { ApiTags } from '@nestjs/swagger';
import { DaprService } from '../dapr/dapr.service';

@Controller('demo')
@ApiTags('demo') // Attaches controller to a specific tag - https://docs.nestjs.com/websites/swagger#tags
export class DemoController {
  private readonly logger = new Logger(DemoController.name);

  constructor(
    private readonly daprService: DaprService,
  ) { }

  @Get('/')
  @HttpCode(200)
  async demo(@Req() req): Promise<void> {
    await this.daprService.daprClient.binding.send(`my-component`, "create", { hello: "world" });
  }

Start Nest with Dapr

To start all of this, we can now utilize the dapr run command, which will create our process with Dapr in it.

dapr run --app-id my-application --app-protocol http --app-port 50001 --dapr-http-port 3500 --components-path ./components npm run start