Dependency injection in ExpressWebJs 4

Dependency injection in ExpressWebJs 4

ExpressWebJs supports the dependency injection (DI) software design pattern, a technique for achieving Inversion of Control (IoC) between classes and their dependencies.

Dependency injection involves the use of ExpressWebJs service container*, a container that is used to manage class dependencies.*

This topic provides information on dependency injection in ExpressWebJs. The primary documentation on dependency injection is in the Service container in ExpressWebJs.

Overview Of Dependency Injection

A dependency is an object that another object depends on. For example, examine the following EmailServiceImp class with a SendEmail method that other classes depend on:

export class EmailServiceImp{ 
  async sendEmail(emailAddress:string,message:string): Promise<void>{
    console.log("EmailServiceImp.sendEmail called");
  }
}

A class can create an instance of the EmailServiceImp class to make use of its sendEmail method.

Let’s try to send an email in our user class after saving a user:

export class User{
  private emailService:EmailServiceImp = new EmailServiceImp();  

  async saveUser(userData:object){
    ...after saving user;
    emailService.sendEmail(userData.email,"Hello world");
  }
}

The class creates and directly depends on the EmailServiceImp class. Code dependencies, such as in the previous example, are problematic and should be avoided for the following reasons:

  • To replace EmailServiceImp with a different implementation, the User class must be modified.

  • If EmailServiceImp has dependencies, they must also be configured by the User class. In a large project with multiple classes depending on EmailServiceImp, the configuration code becomes scattered across the app.

  • This implementation is difficult to unit test.

Dependency injection solves these problems through:

  • The use of an abstract or base class to abstract the dependency implementation.

  • Registration of the dependency in a service container.

  • Injection of the service into the constructor of the class where it’s used. ExpressWebJs takes on the responsibility of creating an instance of the dependency and disposing of it when it’s no longer needed.

Dependency abstraction

Let’s create an abstraction for EmailServiceImp and implement it.

export abstract class EmailService{
  abstract sendEmail(emailAddress:string,message:string): void
}

This abstract class also serves as an interface that is implemented by a concrete class, EmailServiceImp:

export class EmailServiceImp implements IEmailService { 
 async sendEmail(emailAddress:string,message:string): Promise<void>{
    console.log("EmailServiceImp.sendEmail called");
 }
}

Service Provider

In ExpressWebJs service provider class, thebindAsSingletonClass method binds an abstract interface class or name to a concrete class into the container that should only be resolved one time. Once a singleton binding is resolved, the same object instance will be returned on subsequent calls on the abstract interface class or name.

class AppServiceProvicer extends ServiceProvider {

  public register() {
     this.bindAsSingletonClass(EmailService, EmailServiceImp);
  }
}

Dependency injection

We can now inject EmailServiceinto User class.

export class User{
  constructor(private emailService:EmailService){}

   async saveUser(userData:object){
    ...after saving user;
    this.emailService.sendEmail(userData.email,"Hello world");
  }
}

By using the DI pattern, User class:

  • You won't use the concrete implementation, instead the EmailService interface it implements. That makes it easy to change the implementation without modifying the User class.

  • You won't create an instance of the EmailServiceImp, it's created by the DI container.

Conclusion

In this article, we discussed what is dependency injection, its importance, when, and how to use it in ExpressWebJs.

To learn more about ExpressWebJs, check out the official documentation. Kindly Join the ExpressWebJs community on Discord.

You can follow ExpressWebJs on Twitter @expresswebjs and don’t forget to star ExpressWebJs Project on GitHub