NestJS Dependency Injection - Overview

Shameel Uddin - Jan 29 - - Dev Community

Video Explanation

Please find video explanation below:

Introduction

Lets first divide the entire term in two parts. "Dependency" and "Injection".
This suggests that there could be one dependency class which needs to be "injected" to another class (simplest of the example).

In nest.js, we normally inject providers (services) in controllers to perform some sort of business logic.

Please note that the task of service should not be authentication, authorization, validation, transformation and/or extending or overriding the function. Because, for all this, we have separate components in nest.js like middleware, guards, pipes and interceptors.

Make sure that the dependency you make should have one concern and the concern should be specific to the business logic you plan to implement.

Non Dependency Example

Lets take a look at the example below:

Image description

Car has an Engine that means, Car depends upon Engine.
As such, we have two classes, i.e., Car and Engine.

If you notice here:

Image description

We are directly instantiating Engine in the Car. You must have done this in other programming languages as well. This means that Car and Engine are tightly coupled. If you were to make any changes in Engine, then you might have to make changes in your class code as well to make sure that the Car class instantiates the Engine class correctly.

In short, in this example, your code is managing the dependency.

Goal of Dependency Injection

The main goal that dependency injection achieves is to reverse the order of things explained earlier.

Instead of the code managing the dependency, it ensures that the dependencies and their relationships are managed by library or framework. In our case, the dependencies would be managed by Nest.js runtime system.

Creating Injectable Dependency

Nest.js allows @Injectable() decorator to perform this operation. It can be imported from @nestjs/common.

Image description

This decorator needs to be placed right above the class and it ensures to add metadata to the class which makes the class as injectable to other classes via. dependency injection.

Make sure that the class you tend to make as a dependency is exported as shown in above image.

Some basic code would be like this:



import { Injectable } from '@nestjs/common';

@Injectable()
export class ShameelService {}


Enter fullscreen mode Exit fullscreen mode

Now lets take a look at the following code:

Image description

What I have done above is created a private variable cats which is an array of strings and created two methods create() which pushes incoming argument to cats variable and findaAll() which simply returns the cats array. It's pretty simple, no rocket science intended.

Injecting Service in Controller

This is the simplest code to inject service in a controller:

Image description

This is an example of dependency injection via. constructor (you guessed it right, there are other method but we will only be covering constructor based dependency injection here).

Lets understand that line a bit which does all the magic..



constructor(private readonly catService:CatService)


Enter fullscreen mode Exit fullscreen mode

So, we have a variable named catService which is private and readonly. This means, the scope of this variable is within this file only and it cannot be modified by any means from this file during run time.

The magical part is CatService which in TypeScript defines the type of catsService variable.

Lets add the following code here:

Image description

The code implements POST endpoint which adds incoming arguments to the cats privatevariable in CatsService.

But... How does CatsController just got access to everything within CatsService? Because, as far as the programming concept goes, CatsService needs to be fully resolved and its instance must be created so that it can be utilized somewhere else. Lets discuss this below.

Registering the Dependency

The key part after creating a dependency is to register it. Once you register the dependency then whenever you run your nest.js application, it will first resolve the dependency and create its instance.

Nest.js keeps instances of the providers within an IoC (Inversion of Control) container. Whenever some control tends to perform dependency injection for some service, nest.js runtime picks that service from its container and provides it to that particular controller, provided that the controller is in the scope of the service it tends to inject.

If you do not register your service and tends to inject it then you will get the following error:

Image description

Nest.js suggests you the following suggestions:

Image description

In order to register your service within a module, all you have to do is to give provider class name in providers array within the module.



@Module({
controllers: [CatsController],
providers: [CatsService],
})

Enter fullscreen mode Exit fullscreen mode




Conclusion

Provider and Controller both are classes. The difference comes from the decorator being used at the top of the class which adds relevant metadata to that particular class.

These are the steps that you have to follow:

  1. Create a dependency with @Injectable() decorator.
  2. Register the dependency within the module.
  3. Apply dependency injection within the Controller to get access to the instance of the dependency.

In next article, we will understand what actually is Inversion of Control, that we slightly mentioned in our article here.

Happy coding! 🚀

Follow me for more such content:
YouTube: https://www.youtube.com/@ShameelUddin123
LinkedIn: https://www.linkedin.com/in/shameeluddin/
GitHub: https://github.com/Shameel123

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
Terabox Video Player