# Services
The decorator @Service()
declares a new service that can be injected in an other service or controller on their constructor()
.
All services annotated with @Service()
are constructed one time.
# Configuration
You must add the services
folder on componentsScan
attribute in your server settings as follow :
import {Configuration} from "@tsed/common";
@Configuration({
mount: {
"/rest": `./controllers/**/**.js`
},
componentsScan: [`./services/**/**.js`],
customServiceOptions: {}
})
export class Server {}
2
3
4
5
6
7
8
9
10
# Decorators
# Declaring a service
Create a new file in your services folder. Create a new Class definition and add the @Service()
annotation on your class.
import {Configuration, Injectable, Constant} from "@tsed/di";
import {OnInit, BeforeRoutesInit, OnRoutesInit, AfterRoutesInit, OnServerReady} from "@tsed/common";
@Injectable()
export class MyService implements OnInit, BeforeRoutesInit, OnRoutesInit, AfterRoutesInit, OnServerReady {
@Constant("customServiceOptions", {})
private settings: any;
public getSettings() {
return this.settings;
}
}
2
3
4
5
6
7
8
9
10
11
12
Finally, inject the service to another service:
import {Injectable} from "@tsed/di";
import {MyService} from "./MyService";
@Injectable()
export class FooService {
constructor(private myService: MyService) {}
}
2
3
4
5
6
7
Or to another controller:
import {Controller, Inject} from "@tsed/di";
import {MyService} from "./MyService";
@Controller("/rest")
class MyController {
@Inject()
service: MyService;
// OR from constructor
constructor(private myService: MyService) {}
}
2
3
4
5
6
7
8
9
10
11
# Override a Service
The decorator OverrideProvider gives you the ability to override some internal Ts.ED service like the ParseService .
Example usage:
import {OverrideProvider} from "@tsed/di";
import {SomeService} from "@tsed/common";
@OverrideProvider(SomeService)
class CustomService extends SomeService {
// do something
}
2
3
4
5
6
7
# Lifecycle Hooks
Ts.ED 2.x introduces a new Lifecycle Hooks on the service that follows the Hooks. This lifecycle hooks that provide visibility into these key life moments and the ability to act when they occur.
A service that uses one of the phases of the lifecycle can add a number of things and can be completely autonomous. This is the case with the example of the socket server (See the section How to integrate Socket.io).
These schemes resume the order hooks called by Ts.ED:
Each interface has a single hook method whose name is the interface name prefixed with $
. For example, the OnInit
interface has a hook method named $onInit()
(old name $onInjectorReady
) that Ts.ED calls when all services are built.
import {Hooks} from "@tsed/common";
import {Injectable, OnInit, Configuration} from "@tsed/di";
@Injectable()
export class MyService implements Hooks, OnInit {
private settings = {};
constructor(@Configuration() private configuration: Configuration) {
this.settings = this.configuration.get<any>("customServiceOptions");
}
$onInit(): Promise<any> | void {}
$beforeRoutesInit(): Promise<any> | void {}
$afterRoutesInit(): Promise<any> | void {}
$onReady(): Promise<any> | void {}
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
it's also possible to handle $onDestroy
hook when a service, or a controller is
annotated with @Scope('request')
:
import {Injectable, Scope, OnDestroy} from "@tsed/di";
@Injectable()
@Scope("request")
export class MyService implements OnDestroy {
$onDestroy() {
console.log("Service destroyed");
}
}
2
3
4
5
6
7
8
9
Hook | Purpose and Timing |
---|---|
$onInit | Respond after Injector has initialized all Services in the registry. |
$beforeRoutesInit | Respond before loading the controllers. The middlewares and filters are already built. |
$afterRoutesInit | Respond after the controllers build. |
$onReady | Respond when the server is ready. At this step, Http.Server or/and Https.Server object is available. The server listen the port. |
$onDestroy | Respond when a Service or Controller is destroyed (uniquely when class is annotated with @Scope('request') . |
Interfaces are optionals
The interfaces are optionals for JavaScript and Typescript developers from a purely technical perspective. The JavaScript language doesn't have interfaces. Ts.ED can't see TypeScript interfaces at runtime because they disappear from the transpiled JavaScript.
Nonetheless, it's good practice adding interfaces to TypeScript directive classes in order to benefit from strong typing and editor tooling.
Last Updated: 10/24/2024, 6:33:40 AM
Other topics
- Session & cookies
- Passport.js
- Keycloak
- Prisma
- TypeORM
- MikroORM
- Mongoose
- GraphQL
- GraphQL WS
- Apollo
- TypeGraphQL
- GraphQL Nexus
- Socket.io
- Swagger
- AJV
- Multer
- Serve static files
- Templating
- Serverless HTTP
- Seq
- OIDC
- Stripe
- Agenda
- Terminus
- Serverless
- Server-sent events
- IORedis
- Vike
- Jest
- Vitest
- Controllers
- Providers
- Model
- JsonMapper
- Middlewares
- Pipes
- Interceptors
- Authentication
- Hooks
- Exceptions
- Throw HTTP Exceptions
- Cache
- Command
- Response Filter
- Injection scopes
- Custom providers
- Lazy-loading provider
- Custom endpoint decorator
- Testing
- Customize 404