NestJS and Dependency Injection
By: Vladimir Topolev
Tags: Decorators, JavaScript, Nestjs, Dependency Injection

For the last decade JS is getting popular not only for FrontEnd development, but for BackEnd either. JS isn’t a toy language anymore and it should be ready adjusted for any entreprise projects. The good news here is that we have a big inheritance from such mature technologies like Java which already passed the particular path and have a lot of features which just needed to be adjusted in JS land. One of such patterns is Dependency Inversion and it’s a D letter in acronym SOLID which I guess should be familiar each JS BackEnd Developer now.

The Dependency Inversion principle tells us that the most flexible system are those in which source code dependencies refer only to abstractions, not concrete implementation. Well, this definition is straightforward for statically typed languages like Java and may be vague or even confusion for dynamically typed languages like JavaScript. We will explore those differences a little bit later comparing how DI implemented in both Spring framework (Java) and NestJS (NodeJS).

Let’s have a look where we would need to apply this pattern and how it may be useful. Any well-designed BackEnd application has strictly defined layers (see picture 1):

controllers — usually responsible for getting http requests from the particular route and invocation of domain specific services and preparation http responses

— usually responsible for getting http requests from the particular route and invocation of domain specific services and preparation http responses services — the main business unit and it’s intermediate layer between controllers and repositories.

— the main business unit and it’s intermediate layer between controllers and repositories. repositories — responsible for communication with any persistent layer, it may be either any relational DB (Postgres, MySQL) or NoSQL DB (MongoDB, Redis)

Picture 1

The first requirement for the project is that we need to implement User domain and for persistent layer should be used MySQL DB. First of all, User class entity should be defined with all necessary properties (fields). Let’s also declare TS interface for UserRepository and the first its implementation which is supposed to work with MySQL — UserMySQLRepository. UserService is the intermediate layer between controller and repository, which needs to have dependency from UserRepository:

Listing 1

The project is growing, but in one moment for bunch of reasons application architect has decided to change persistence layer and instead of using MySQL we need to use MongoDB.

Well, the first step is to implement UserRepository interface which would work with MongoDB:

Linsting 2

The next question is how we’re going to change UserRepository dependency in UserService. Of course, the first which may come in mind is just change it in constructor:

Linsting 3

But let’s imagine, that our UserRepository is used for other services as well, for example in ProfileService. Actually in a real project it may look like that:

Picture 2

The larger app the higher probability that our UserRepository is a dependency for N services and in this case with our naive way we would need to change in each service implementation of UserRepository. It would be tedious and error-prone process.

Initializing UserRepository in constructor has also another drawback. How would we create unit test for UserService? We need a way to mock UserRepository implementation. Of course, it’s possible to implement using diverse tools which jest may provide to us and it would look like that:

Listing 4

Again, as soon as we need to change implementation for UserRepository, we need to change path to file which we’re trying to mock.

Let’s refactor UserService and decouple it with UserRepository implementation, we just ask to initialize needed UserRepository outside of UserService and it will be passed in constructor:

Listing 5

This straightforward step to refactor brings one benefit for test, let’s have a look:

Listing 6

Since we decoupled UserService and UserRepository implementation, right now we don’t take care in unit test which implementation is used, we just need to follow UserRepository interface.

Let’s depict what we have done, it allows to get intuitive grasp of total picture and in which direction we’re trying to move:

Picture 3

But in writhing test we created mocked version of UserRepository, but who should be responsible for managing UserRepository in application? Well, there should be any factory pattern applied. Here such frameworks like Spring and NestJS have their role and provide container which will be responsible for initializing all dependencies and injecting them where it’s needed. The benefits here that we just implement out components without any acknowledge about the concrete implementation and we need to work only against interfaces of any outside needed components.

Let’s have a look how it works in NestJS. But before divining deeper just remind you one thing which we all need to keep in mind. When we defined UserRepository as TypeScript interface we need to know that it will be erased in transpilation phase and won’t be available in runtime, it’s the main difference between statically typed languages and dynamically typed ones. TypeScript here is just like a syntax sugar which make feel us more confident about what we’ writing and fix a lot of bugs before runtime. Well, NestJS has several ways to configure our dependencies and since we’re using UserRepository as TypeScript interface we have only one way to define our dependency — non-class-based provider tokens:

Listing 7

We defined AppModule with two providers/dependencies and some of them may depend on each other, in our case UserService is expected to get UserRepository implementation. Pay attention, how we set up UserRepository dependency, since it defined as TypeScript interface and it’s gonna to be erased we need to define any unique token which would help lookup mechanism define dependency in runtime. Let’s inject this dependency in UserService then:

Listing 8

First of all, we put decorator @Injectable, which say that this component is gonna to be used as dependency in application, and in constructor we used @Inject decorator and passes which exact dependency we’re interested in, lookup mechanism by Symbol or it may be any unique string without any problem may match needed component associated and registered in container.

Pay attention, that in listing 7, UserService set up in container as a dependency in a different way. UserService is defined as a JS class and therefore this information is available in runtime, therefore it’s not difficult for lookup mechanism to find needed dependency by class, framework just uses JS operator instanceOf.

Right now in any time when we would like to change one implementation into another — we just need to make changes in one places and NestJS just propagate it across all components of application. It will look like that:

I would also recommend you to review the following links: