# Service Container

# Introduction

ExpressWebJs service container is a powerful tool for managing class dependencies and performing dependency injection. Dependency injection means that a class dependencies are "injected" into the class via the constructor.

Let's look at a simple example:

import { IUserService } from "App/Service/UserService/IUserService";
import { Request, Response } from "Config/http";
import { BaseController } from "./BaseController";

export class UserController extends BaseController {
  protected userService: IUserService;

  constructor(userService: IUserService) {
    super();
    this.userService = userService;
  }
  /**
   * Display a listing of the resource.
   * @method
   * @endpoint
   */
  index = async (User: Request, res: Response) => {
    let result = await this.userService.getAllUsers();
    return this.response.OK(res, result);
  };
}
Copied!

In this example, the UserController needs to retrieve users from a data source. So, we will inject a service that is able to retrieve users. In this context, our userService which interacts with our UserRepository to retrieve user information from the database. However, since userService is injected, we are able to easily swap it out with another implementation. We are also able to easily "mock", or create a dummy implementation of the userService when testing our application.

A deep understanding of ExpressWebJs service container is essential to building a powerful, large application, as well as for contributing to ExpressWebJs core itself.

# Bind As Singleton

In our service provider class, the singleton method binds a 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 into the container.

import { ServiceProvider } from "Elucidate/Support/ServiceProvider";
import { UserService } from "App/Service/UserService";

export class AppServiceProvider extends ServiceProvider {
  /**
   * Register any application services.
   * @return void
   */
  public register() {
    this.singleton(UserService);
  }
}
Copied!

# Bind As Transient

The transient method binds a class into the container any time a call is made to the class. Once a transient binding is resolved, the object instance will be returned.

import { ServiceProvider } from "Elucidate/Support/ServiceProvider";
import { UserService } from "App/Service/UserService";

export class AppServiceProvider extends ServiceProvider {
  /**
   * Register any application services.
   * @return void
   */
  public register() {
    this.transient(UserService);
  }
}
Copied!

# Binding Interfaces To Implementations

# Bind As Singleton Class

The bindAsSingletonClass 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.

import { ServiceProvider } from "Elucidate/Support/ServiceProvider";
import { UserService } from "App/Service/UserService";
import { UserInterface } from "App/Service/UserInterface";

export class AppServiceProvider extends ServiceProvider {
  /**
   * Register any application services.
   * @return void
   */
  public register() {
    this.bindAsSingletonClass(UserInterface, UserService);
  }
}
Copied!

This statement tells the container that it should inject the UserService when a class needs an implementation of UserInterface. Now we can type-hint the UserInterface in the constructor of a class that is resolved by the container. Remember, controllers, and other registered classes within ExpressWebJs applications are always resolved using the container.

import { UserInterface } from "App/Service/UserService/UserInterface";
import { Request, Response } from "Config/http";
import { BaseController } from "./BaseController";

export class UserController extends BaseController {
  constructor(private userInterface: UserInterface) {}

  public async getUsers(User: Request, res: Response) {
    let result = await this.userInterface.getAllUsers();
    return this.response.OK(res, result);
  }
}
Copied!

# Bind As Singleton Function

The bindAsSingletonFunction method binds an abstract interface class or name to a concrete function into the container that should only be resolved one time. Once a singleton binding is resolved, the same function instance will be returned on subsequent calls on the abstract interface class or name.

import { ServiceProvider } from "Elucidate/Support/ServiceProvider";
import { UserRepository } from "App/Repository/UserRepository";
import { AllUserInterface } from "App/Service/AllUserInterface";

export class AppServiceProvider extends ServiceProvider {
  /**
   * Register any application services.
   * @return void
   */
  public register() {
    this.bindAsSingletonFunction(AllUserInterface, () => {
      return new UserRepository.getAllUsers();
    });
  }
}
Copied!

# Bind As Class

The bindAsClass method binds an abstract interface class or name to a concrete class into the container that is resovled any time a call is made to the interface. Once the binding is resolved, the object instance will be returned on calls on the abstract interface class or name.

import { ServiceProvider } from "Elucidate/Support/ServiceProvider";
import { UserRepository } from "App/Repository/UserRepository";
import { AllUserInterface } from "App/Service/AllUserInterface";

export class AppServiceProvider extends ServiceProvider {
  /**
   * Register any application services.
   * @return void
   */
  public register() {
    this.bindAsClass(AllUserInterface, () => {
      return new UserRepository.getAllUsers();
    });
  }
}
Copied!

# Bind As Function

The bindAsFunction method binds an abstract interface class or name to a concrete function into the container that is resovled any time a call is made to the interface. Once the binding is resolved, the function instance will be returned on calls on the abstract interface class or name.

import { ServiceProvider } from "Elucidate/Support/ServiceProvider";
import { UserRepository } from "App/Repository/UserRepository";
import { AllUserInterface } from "App/Service/AllUserInterface";

export class AppServiceProvider extends ServiceProvider {
  /**
   * Register any application services.
   * @return void
   */
  public register() {
    this.bindAsFunction(AllUserInterface, () => {
      return new UserRepository.getAllUsers();
    });
  }
}
Copied!