# 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 a 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 {Service} 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;
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Note
and have the same effect. accepts options, does 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;
}
}
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 CalendarsController {
constructor(private readonly calendarsService: CalendarsService) {
}
@Post()
async create(@BodyParams() calendar: Calendar) {
this.calendarsService.create(calendar);
}
@Get()
async findAll(): Promise<Calendar[]> {
return this.calendarsService.findAll();
}
}
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 {Configuration} from "@tsed/common";
import {CalendarsCtrl} from "./controllers/CalendarsCtrl";
import {CalendarsService} from "./services/CalendarsService";
@Configuration({
mount: {
"/rest": [CalendarsCtrl]
},
componentsScan: [
CalendarsService
]
})
export class Server {
}
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 emits type metadata on the constructor which will be exploited by the to resolve dependencies automatically.
constructor(private calendarsService: CalendarsService) {}
# Scopes
All providers have a lifetime strictly dependent on the application lifecycle. Once the server is created, all providers have to be instantiated. Similarly, when the application shuts down, 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 configurations set with , or can be retrieved with and decorators. Theses decorators can be used with:
and accept an expression as parameter 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);
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
WARNING
returns 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 resolves 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();
}
}
2
3
4
5
6
7
8
9
Just don't forgot to import your provider in your project !
# Configurable provider v5.58.0+
Sometimes you need to inject a provider with a specific configuration to another one.
This is possible with the combination of and decorators.
import {Injectable, Opts, UseOpts} from "@tsed/di";
@Injectable()
class MyConfigurableService {
source: string;
constructor(@Opts options: any = {}) {
console.log("Hello ", options.source); // log: Hello Service1 then Hello Service2
this.source = options.source;
}
}
@Injectable()
class MyService1 {
constructor(@UseOpts({source: "Service1"}) service: MyConfigurableService) {
console.log(service.source); // log: Service1
}
}
@Injectable()
class MyService2 {
constructor(@UseOpts({source: "Service2"}) service: MyConfigurableService) {
console.log(service.source); // log: Service2
}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
WARNING
Using decorator on a constructor parameter changes the scope of the provider to ProviderScope.INSTANCE
.
← Controllers Model →
- Session & cookies
- Passport.js
- TypeORM
- Mongoose
- GraphQL
- Socket.io
- Swagger
- AJV
- Multer
- Serve static files
- Templating
- Throw HTTP Exceptions
- Customize 404
- AWS
- Jest
- Seq
- Controllers
- Providers
- Model
- Converters
- Middlewares
- Pipes
- Interceptors
- Authentication
- Hooks
- Injection scopes
- Custom providers
- Custom endpoint decorator
- Testing