# Providers

Basically, almost everything may be considered as a provider – service, factory, interceptors, and so on. All of them can inject dependencies, meaning, they can create various relationships with each other. But in fact, a provider is nothing else than just a simple class annotated with an @Injectable() decorator.

In controllers chapter, we've seen how to build a Controller, handle request and create a response. Controllers shall handle HTTP requests and delegate complex tasks to the providers.

The providers are plain javascript class and use one of these decorators on top of them. Here the list:

# Services

Let's start by creating a simple CalendarService provider.

import {Injectable} from "@tsed/common";
import {Calendar} from "../models/Calendar";

@Service()
export class CalendarsService {
  private readonly calendars: Calendar[] = [];

  create(calendar: Calendar) {
    this.calendars.push(calendar);
  }

  findAll(): Calendar[] {
    return this.calendars;
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

Note

and as the same effect. @Injectable accept options, @Service not. A Service is always configured as singleton.

Example with @Injectable

import {Injectable, ProviderScope, ProviderType} from "@tsed/common";
import {Calendar} from "../models/Calendar";

@Injectable({
  type: ProviderType.CONTROLLER,
  scope: ProviderScope.SINGLETON
})
export class CalendarsService {
  private readonly calendars: Calendar[] = [];

  create(calendar: Calendar) {
    this.calendars.push(calendar);
  }

  findAll(): Calendar[] {
    return this.calendars;
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

Now we have the service class already done, let's use it inside the CalendarCtrl:

import {BodyParams, Controller, Get, Post} from "@tsed/common";
import {Calendar} from "../models/Calendar";
import {CalendarsService} from "../services/CalendarsService";

@Controller("/calendars")
export class CatsController {
  constructor(private readonly calendarsService: CalendarsService) {
  }

  @Post()
  async create(@BodyParams() calendar: Calendar) {
    this.calendarsService.create(calendar);
  }

  @Get()
  async findAll(): Promise<Calendar[]> {
    return this.calendarsService.findAll();
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

Finally, we can load the injector and use it:

import {ServerLoader, ServerSettings} from "@tsed/common";
import {CalendarsCtrl} from "./controllers/CalendarsCtrl";
import {CalendarsService} from "./services/CalendarsService";

@ServerSettings({
  mount: {
    "/rest": [CalendarsCtrl]
  },
  componentsScan: [
    CalendarsService
  ]
})
export class Server extends ServerLoader {
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# Dependency injection

Ts.ED is built around the dependency injection pattern. TypeScript emit type metadata on the constructor which will be exploited by the to resolve dependencies automatically.

constructor(private calendarsService: CalendarsService) {}
1

# Scopes

All providers has a lifetime strictly dependent on the application lifecycle. Once the server is created, all providers have to be instantiated. Similarly, when the application shutdown, all providers will be destroyed. However, there are ways to make your provider lifetime request-scoped as well. You can read more about these techniques here.

# Binding configuration

All configuration set in or with can be retrieved with and decorators. Theses decorators can be used with:

and accept an expression as parameters to inspect the configuration object and return the value.

import {Constant, Value} from "@tsed/di";
import {Env} from "@tsed/core";

export class MyClass {
  @Constant("env")
  env: Env;

  @Value("swagger.path")
  swaggerPath: string;

  $onInit() {
    console.log(this.env);
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14

WARNING

return an Object.freeze() value.

NOTE

The values for the decorated properties aren't available on constructor. Use $onInit() hook to use the value.

# Custom providers

The Ts.ED IoC resolve relationships providers for you, but sometimes, you want to tell to the DI how you want to instantiate a specific service or inject different kind of providers based on values, on asynchronous or synchronous factory or on external library. Look here to find more examples.

# Override provider

Any provider (Provider, Service, Controller, Middleware, etc...) already registered by Ts.ED or third-party can be overridden by your own class.

import {OriginalService, OverrideProvider} from "@tsed/common";

@OverrideProvider(OriginalService)
export class CustomMiddleware extends OriginalService {
  public method() {
    // Do something
    return super.method();
  }
}
1
2
3
4
5
6
7
8
9

Just don't forgot to import your provider in your project !