Unleashing the Power of Dependency Injection and IoC Containers with InversifyJS and NestJS

yovchenko

Volodymyr

Posted on August 3, 2023

Unleashing the Power of Dependency Injection and IoC Containers with InversifyJS and NestJS

Welcome to an exploration into crafting robust, testable, and maintainable software. We'll delve into Dependency Inversion Principle (DIP) and Dependency Injection (DI), two design concepts crucial for achieving loose coupling and seamless dependency management in your applications.

Before we embark on this journey, let's understand each definition step by step:

Dependency Inversion Principle is one of the SOLID principles, emphasizing that high-level modules should not directly depend on low-level modules. Instead, both should depend on abstractions. By depending on abstractions, we achieve loose coupling and a modular design, making it easier to swap and extend components.

Dependency Inversion Principle

Dependency Injection is a practical implementation of DIP. It allows us to provide the dependencies of a class from an external source, typically through the constructor or setters. DI facilitates loose coupling, enhances testability, and promotes modular design.

๐ŸŒŸ Example: Without Dependency Injection

class NotificationService {
  private readonly emailService: EmailService;

  constructor() {
    // The NotificationService creates its own emailService.
    this.emailService = new EmailService();
  }

  sendNotification(message: string): void {
    // The NotificationService sends a notification.
    this.emailService.sendEmail(message);
  }
}
Enter fullscreen mode Exit fullscreen mode

๐ŸŒŸ Example: With the Power of Dependency Injection!

class NotificationService {
  // The emailService joins the NotificationService as a companion.
  constructor(private readonly emailService: EmailService) {}

  sendNotification(message: string): void {
    // With the power of Dependency Injection, the NotificationService sends a notification.
    this.emailService.sendEmail(message);
  }
}
Enter fullscreen mode Exit fullscreen mode

Now that we understand DIP and DI, let's talk a bit about the out-of-the-box solution:

IoC Container of InversifyJS - A Lightweight Solution:
Inversion of Control (IoC) containers are tools that manage the creation and resolution of dependencies in an application. InversifyJS is a powerful IoC container tailored for Typescript projects. It simplifies dependency management by allowing the registration of classes and interfaces, automating the resolution and instantiation of dependencies.

๐ŸŒŸ Example: using InversifyJS

import { Container, injectable, inject } from "inversify";

@injectable()
class EmailService {
  sendEmail(message: string): void {
    // Prepare for sending an email
    // The email is on its way! ๐Ÿ’Œ๐Ÿช„
  }
}

@injectable()
class NotificationService {
  constructor(@inject(EmailService) private readonly emailService: EmailService) {}

  sendNotification(message: string): void {
    // With InversifyJS, the NotificationService casts the spell of email sending! ๐ŸŒˆ๐Ÿ“ง
    this.emailService.sendEmail(message);
  }
}

const container = new Container();
container.bind<EmailService>(EmailService).toSelf();
container.bind<NotificationService>(NotificationService).toSelf();

const notificationService = container.get<NotificationService>(NotificationService);
notificationService.sendNotification("Hello, World! Prepare to be amazed! ๐ŸŒŸ๐Ÿš€");
Enter fullscreen mode Exit fullscreen mode

With InversifyJS, you can effortlessly manage dependencies and create a modular and organized architecture. It provides automation for your code.

But that's not all, folks! Now, let's teleport ourselves to the enchanting realm of NestJS - a powerful framework that knows how to dance with Dependency Injection and IoC too! NestJS offers a modular architecture that's perfect for large-scale projects. It's like having a magical beast that roars scalability and maintainability! ๐Ÿฆ๐Ÿงญ

๐ŸŒŸ Example: using NestJS

import { Controller, Get, Injectable, Module } from '@nestjs/common';
import { Inject } from '@nestjs/common';
import { ModuleRef } from '@nestjs/core';

@Injectable()
class EmailService {
  sendEmail(message: string): void {
    // Your email is on its way to the realm of the internet.
  }
}

@Controller()
class MagicController {
  constructor(private readonly emailService: EmailService) {}

  sendNotification(message: string): void {
    // Your message is being sent through the EmailService.
    this.emailService.sendEmail(message);
  }
}

@Module({
  controllers: [MagicController],
  providers: [EmailService],
})
class MagicModule {}

// Your NestJS app is about to get enchanted! โœจ๐Ÿ”ฎ
Enter fullscreen mode Exit fullscreen mode

In this implementation, we've summoned the power of NestJS to create a MagicController that casts a spell using the EmailService. NestJS seamlessly injects the service into the controller.

To conclude our journey, remember that Dependency Injection and IoC containers promote flexibility and decoupling in software development. Embrace the lightweight spell-caster, InversifyJS, for smaller projects, and explore NestJS for larger endeavors. Together, these tools will transform your Typescript projects into remarkable software solutions.

Now, you can join us on this adventure! Let's code and create magic! ๐Ÿง™โ€โ™€๏ธ

๐Ÿ’– ๐Ÿ’ช ๐Ÿ™… ๐Ÿšฉ
yovchenko
Volodymyr

Posted on August 3, 2023

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related

ยฉ TheLazy.dev

About