A common approach to NestJS development is to build services that controllers communicate with to access data. But this approach isn’t the only valid design pattern in NestJS. There are other design patterns, such as the CQRS design pattern.

CQRS is a design pattern that separates the read and write operations of an application. This separation can help improve scalability, performance, and maintainability.

Find out all about CQRS and how you can apply it when building a NestJS API.

What Is CQRS?

CQRS stands for command-query responsibility segregation. It implements the use of commands to create, update, and delete data and queries to fetch data. This helps to eliminate the need to implement an application’s database calls into services.

It also enables a clear distinction between the logic of querying the database for data and performing other actions in an application.

The CQRS approach is useful in domain-driven design, which allows you to separate domain logic and infrastructural operations in your application. You can also use it to implement complex business logic, but this is not recommended for simpler applications.

Using CQRS in a NestJS API

You can use the CQRS design pattern in an API that you build in NestJS. To follow along, you need to have Node.js installed on your computer and a recent version of NestJS.

Use the following steps to build a simple blogging application that implements the CQRS design pattern.

Create a Nest Project

Create a new Nest project and generate a post resource for a blog application. You can do this by running the following commands in a terminal:

        nest new nestjs-cqrs
nest g module posts
nest g controller posts
nest g service posts

Install Dependencies

After you’ve completed the steps above, run this terminal command to install the NestJS CQRS package:

        npm install --save @nestjs/cqrs
    

Create a Post Service

Add the following code to your posts.service.ts file to define the PostService class.

        // posts.service.ts
import { Injectable } from '@nestjs/common';

export interface Post {
    title: string;
    content: string;
}

@Injectable()
export class PostService {
  private readonly posts: Post[] = [];

  create(post: Post): Post {
    this.posts.push(post);
    return post;
  }

  findById(id: number): Post {
    return this.posts.find(post => post.id === id);
  }
}

The PostService defines create and findById methods to create a new post and get an existing post from its ID.

Define Commands and Queries

The next step is to define the queries and commands that are core to the CQRS design pattern.

In the posts directory, create two new files: createPostCommand.command.ts and getPostQuery.query.ts. The command file should look like this:

        // createPostCommand.command.ts
export class CreatePostCommand {
  constructor(public readonly title: string, public readonly content: string) {}
}

And the query definition file, like this:

        // getPostQuery.query.ts
export class GetPostQuery {
  constructor(public readonly id: number) {}
}

Create Command and Query Handlers

After you have successfully defined your commands and queries, you need to create handlers for them. A handler is a function that runs a command or query and returns the outcome.

Create a handlers.ts file in your post directory and paste the following code in it:

        // handlers.ts
import { CommandHandler, ICommandHandler } from '@nestjs/cqrs';
import { CreatePostCommand } from './createPostCommand.command.ts';
import { PostService } from './post.service';

@CommandHandler(CreatePostCommand)
export class CreatePostHandler implements ICommandHandler<CreatePostCommand> {
  constructor(private readonly postService: PostService) {}

  async execute(command: CreatePostCommand) {
    const { name, price } = command;
    const post = await this.postService.create(title, content);
    return post;
  }
}

In the same handlers.ts file, you can modify the import statements to include the ones below, to allow for working with queries. You may then implement the query handler as seen in the below code:

        // handler.ts
import { QueryHandler, IQueryHandler } from '@nestjs/cqrs';
import { GetPostQuery } from './getPostQuery.query';
import { PostService } from './post.service';

// query handler
@QueryHandler(GetProductQuery)
export class GetPostHandler implements IQueryHandler<GetPostQuery> {
  constructor(private readonly postService: PostService) {}

  async execute(query: GetPostQuery) {
    const { id } = query;
    const post = await this.postService.findOneById(id);
    return post;
  }
}

Register Handlers

The last step is to register the command and query handlers with the NestJS module.

        // post.module.ts
import { Module } from '@nestjs/common';
import { CommandHandlers, QueryHandlers } from 'handlers.ts';
import { PostService } from './post.service';

@Module({
  providers: [
    PostService,
    ...CommandHandlers,
    ...QueryHandlers,
  ],
})
export class PostModule {}

This code registers the PostService, CommandHandlers, and QueryHandlers in the providers array. The use of a spread operator (...) is to merge the arrays of query handlers and command handlers into the providers array.

Execute Commands and Queries

The registered commands and query handlers are usable in controllers. The following code is the implementation of a posts controller which will accept HTTP requests and return required responses.

        // posts.controller.ts
import { Body, Controller, Post } from '@nestjs/common';
import { CommandBus } from '@nestjs/cqrs';
import { CreatePostCommand } from './createPostCommand.command.ts';

// controller that implements command
@Controller('posts')
export class PostController {
  constructor(private readonly commandBus: CommandBus) {}

  @Post()
  async createPost(@Body() body: { title: string; content: string }) {
    const { title, content } = body;
    const command = new CreatePostCommand(title, content);
    const post = await this.commandBus.execute(command);
    return post;
  }
}

In the code above, the CommandBus executes the CreatePostCommand and creates a new post.

This code shows how to implement a controller that uses a query:

        // posts.controller.ts
import { Controller, Get, Param } from '@nestjs/common';
import { QueryBus } from '@nestjs/cqrs';
import { GetPostQuery } from './getPostQuery.query';

@Controller('posts')
export class PostController {
  constructor(private readonly queryBus: QueryBus) {}

  @Get(':id')
  async getPost(@Param('id') id: number) {
    const query = new GetPostQuery(id);
    const post = await this.queryBus.execute(query);
    return post;
  }
}

The queryBus executes GetPostQuery which gets the post with the given ID and returns it.

After completing all the steps above, you should now have a minimalist, working application to create and fetch blog posts.

Although the code here uses an array to store the created posts in memory, you’re more likely to use a database in production. You can either use a SQL database, or a NoSQL database like MongoDB, as NestJS supports both options.

Building APIs With the CQRS Design Pattern

Incorporating the CQRS design pattern into your NestJS application can aid in scalability, performance, and maintainability. CQRS allows for more efficient and optimized operations by separating the read and write operations an application carries out.

The @nestjs/cqrs package provides a building block for implementing CQRS in NestJS with commands and query handlers. Overall, CQRS is a powerful pattern that can help create more efficient and scalable applications, and you should weigh up your options before using it.