# 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);
};
}
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 AppServiceProvicer extends ServiceProvider {
/**
* Register any application services.
* @return void
*/
public register() {
this.singleton(UserService);
}
}
# Bind As Transient
The transient
method binds a class into the container that 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 AppServiceProvicer extends ServiceProvider {
/**
* Register any application services.
* @return void
*/
public register() {
this.transient(UserService);
}
}
# 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 AppServiceProvicer extends ServiceProvider {
/**
* Register any application services.
* @return void
*/
public register() {
this.bindAsSingletonClass(UserInterface, UserService);
}
}
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) {}
getUsers = async (User: Request, res: Response) => {
let result = await this.userInterface.getAllUsers();
return this.response.OK(res, result);
};
}
# 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 AppServiceProvicer extends ServiceProvider {
/**
* Register any application services.
* @return void
*/
public register() {
this.bindAsSingletonFunction(AllUserInterface, () => {
return new UserRepository.getAllUsers();
});
}
}
# 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 AppServiceProvicer extends ServiceProvider {
/**
* Register any application services.
* @return void
*/
public register() {
this.bindAsClass(AllUserInterface, () => {
return new UserRepository.getAllUsers();
});
}
}
# 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 AppServiceProvicer extends ServiceProvider {
/**
* Register any application services.
* @return void
*/
public register() {
this.bindAsFunction(AllUserInterface, () => {
return new UserRepository.getAllUsers();
});
}
}