Services & Dependency Injection
You are reading the documentation for version 2 of FoalTS. Instructions for upgrading to this version are available here. The old documentation can be found here.
#
DescriptionServices are useful to organize your code in domains. They can be used in a wide variety of situations: logging, interaction with a database, calculations, communication with an external API, etc.
#
ArchitectureBasically, a service can be any class with a narrow and well defined purpose. They are instantiated as singletons.
#
Use & Dependency InjectionYou can access a service from a controller using the @dependency
decorator.
Example:
When instantiating the controller, FoalTS will provide the service instance. This mechanism is called dependency injection and is particularly interesting in unit testing (see section below).
In the same way, you can access a service from another service.
Example:
Dependencies are injected after the instantiation of the controller/service. So they will appear as
undefined
if you try to read them inside a constructor. If you want to access the dependencies when initializing a controller/service, refer to theboot
method.
Circular dependencies are not supported. In most cases, when two services are dependent on each other, the creation of a third service containing the functionalities required by both services solves the dependency problem.
#
Testing servicesServices are classes and so can be tested as is.
Example:
#
Services (or Controllers) with DependenciesIf your service has dependencies, you can use the createService
function to instantiate the service with them.
Example:
A similar function exists to instantiate controllers with their dependencies:
createController
.
In many situations, it is necessary to mock the dependencies to truly write unit tests. This can be done by passing a second argument to createService
(or createController
).
Example:
#
Injecting other InstancesTo manually inject instances into the identity mapper, you can also provide your own ServiceManager
to the createApp
function (usually located at src/index.ts
).
src/index.ts (example)
Note: Interfaces cannot be passed to the
set
method.
src/controllers/api.controller.ts (example)
#
Abstract ServicesIf you want to use a different service implementation depending on your environment (production, development, etc.), you can use an abstract service for this.
logger.service.ts
Warning: the two properties must be static.
console-logger.service.ts (concrete service)
- YAML
- JSON
- JS
The configuration value can be a package name or a path relative to the
src/
directory. If it is a path, it must start with./
and must not have an extension (.js
,.ts
, etc).
a random service
#
Default Concrete ServicesAn abstract service can have a default concrete service that is used when no configuration value is specified or when the configuration value is local
.
#
Usage with Interfaces and Generic ClassesInterfaces and generic classes can be injected using strings as IDs. To do this, you will need the @Dependency
decorator.
src/services/logger.interface.ts
src/services/logger.service.ts
src/index.ts (example)
src/controllers/api.controller.ts (example)
ServiceManager
#
Accessing the In very rare situations, you may want to access the ServiceManager
which is the identity mapper that contains all the service instances.