Build an Kanban based on NestJS

freedomsean
3 min readNov 30, 2020

Last time, I try to introduce how to build a kanban. This time, I try to introduce how to use NestJS to build a kanban. If you are interested in NestJS source code, you can check this article.

To summarize this first, I really hate NestJS to instantize and modularized everything , but its components, such as filter, interceptor and its decorator definitely help you organize your code. Sometimes, it can reduce your time to think how to build your file architecture. It is suitable for some junior developers to use, but for me, I really hate this.

If you have interesting about my source code, you can checkout from there.

First of all, you should know why does NestJS instantize everything. That’s because he want to make sure you won’t have second instance and manage them in its kernel.

In the express-kanban project, if we want to achieve this, we will use singleton to build that. Take database as example.

In express-kanban, we will have one database service like this.

In NestJS document, you will need to use dynamic module to develop this.

In NestJS official tutorial, it has some example code.

But it is not enough to replace singleton. Singleton has two characteristics.

  1. It only has one or countable instances.
  2. It is global.

In order to avoid that you put everything as global, you need to set some flag to make the module as global. Actually, it is a good design for its strategy, instanizing everything; otherwise, everyone will call from global.

Let’s discuss about how to achieve that in NestJS.

In NestJS, actually, every instant is definitely global, but you need to import them every time in the different module. That’s say you have 3 modules, and the relation will be A -> B -> C. If you don’t put A as global, you need to declare the relationship in C module and you need to follow the sequence also. Unfortunately, you won’t have 3 modules only, and the relationship is extremely chaos.

First of all, you will create one module. In this module, you will have one register static function. register can be replace with any name you want, because it does not have any interface about initializing dynamic module. In this function, it should return a DynamicModule and set global as true. Noted that, global can be set in the module level only.

Second, you will need create your own database library like this.

You may found that, in the constructor, it will have one envService which manage all environment variables. envService is the other provider in other module. You only can inject this when you generate this provider.

That is a bad thing caused by instantize everything.

Actually, it will be very simple and elegant to make EnvService be a global constants or some static getter functions, but in order to follow the logic in NestJS and use its module ConfigModule which will help you read from .env, we will keep this design.

Last, to resolve the inject problem, we won’t use DatabaseService as the main provider key. We will do something like this.

We use DATABASE_PROVIDER as our key for NestJS kernel, and we use useFactory and inject to resolve the problem we mentioned.

If you want to use DATABASE_PROVIDER, you can do something like this.

In users.repository.ts:

In users.module.ts:

You don’t need to import anything in users.module, because DATABASE_PROVIDER is global, but you should remember to import this in your root module like this.

In app.module.ts:

This kind of design will be very common in my project, because we don’t want to including all dependencies again and again.

Of course, you also can use this kind of design in NestJS components.

For example, I hope to log every request and response, so I will have one interceptor which is a component in NestJS.

In logger.interceptor.ts:

It should inject loggerService which is the other provider but in the same module and called by main.ts, so we will have one provider generator like this.

A small tricky thing at the interceptor is if it has exception, you need to use one pipe to catch that first, and to process the successful response.

Finally, we define all in logger.module.ts.

In main.ts, you will have something like this:

The other tricky thing is in nestjs/config, you cannot use the same name in your configService with process.env. I think it is extremely a bug, but when I sent a pr, they mentioned it is a expected behavior. I cannot figure out and get no answer.

This is also a big problem to use this kind of super heavy framework. You do not know how to debug sometimes.

--

--