|
| 1 | +### Discovery service |
| 2 | + |
| 3 | +The `DiscoveryService` provided by the `@nestjs/core` package is a powerful utility that allows developers to dynamically inspect and retrieve providers, controllers, and other metadata within a NestJS application. This is particularly useful when building plugins, decorators, or advanced features that rely on runtime introspection. By leveraging `DiscoveryService`, developers can create more flexible and modular architectures, enabling automation and dynamic behavior in their applications. |
| 4 | + |
| 5 | +#### Getting started |
| 6 | + |
| 7 | +Before using `DiscoveryService`, you need to import the `DiscoveryModule` in the module where you intend to use it. This ensures that the service is available for dependency injection. Below is an example of how to configure it within a NestJS module: |
| 8 | + |
| 9 | +```typescript |
| 10 | +import { Module } from '@nestjs/common'; |
| 11 | +import { DiscoveryModule } from '@nestjs/core'; |
| 12 | +import { ExampleService } from './example.service'; |
| 13 | + |
| 14 | +@Module({ |
| 15 | + imports: [DiscoveryModule], |
| 16 | + providers: [ExampleService], |
| 17 | +}) |
| 18 | +export class ExampleModule {} |
| 19 | +``` |
| 20 | + |
| 21 | +Once the module is set up, `DiscoveryService` can be injected into any provider or service where dynamic discovery is required. |
| 22 | + |
| 23 | +```typescript |
| 24 | +@@filename(example.service) |
| 25 | +@Injectable() |
| 26 | +export class ExampleService { |
| 27 | + constructor(private readonly discoveryService: DiscoveryService) {} |
| 28 | +} |
| 29 | +@@switch |
| 30 | +@Injectable() |
| 31 | +@Dependencies(DiscoveryService) |
| 32 | +export class ExampleService { |
| 33 | + constructor(discoveryService) { |
| 34 | + this.discoveryService = discoveryService; |
| 35 | + } |
| 36 | +} |
| 37 | +``` |
| 38 | + |
| 39 | +#### Discovering providers and controllers |
| 40 | + |
| 41 | +One of the key capabilities of `DiscoveryService` is retrieving all registered providers in the application. This is useful for dynamically processing providers based on specific conditions. The following snippet demonstrates how to access all providers: |
| 42 | + |
| 43 | +```typescript |
| 44 | +const providers = this.discoveryService.getProviders(); |
| 45 | +console.log(providers); |
| 46 | +``` |
| 47 | + |
| 48 | +Each provider object contains information such as its instance, token, and metadata. Similarly, if you need to retrieve all registered controllers within the application, you can do so with: |
| 49 | + |
| 50 | +```typescript |
| 51 | +const controllers = this.discoveryService.getControllers(); |
| 52 | +console.log(controllers); |
| 53 | +``` |
| 54 | + |
| 55 | +This feature is particularly beneficial for scenarios where controllers need to be processed dynamically, such as analytics tracking, or automatic registration mechanisms. |
| 56 | + |
| 57 | +#### Extracting metadata |
| 58 | + |
| 59 | +Beyond discovering providers and controllers, `DiscoveryService` also enables retrieval of metadata attached to these components. This is particularly valuable when working with custom decorators that store metadata at runtime. |
| 60 | + |
| 61 | +For example, consider a case where a custom decorator is used to tag providers with specific metadata: |
| 62 | + |
| 63 | +```typescript |
| 64 | +import { DiscoveryService } from '@nestjs/core'; |
| 65 | + |
| 66 | +export const FeatureFlag = DiscoveryService.createDecorator(); |
| 67 | +``` |
| 68 | + |
| 69 | +Applying this decorator to a service allows it to store metadata that can later be queried: |
| 70 | + |
| 71 | +```typescript |
| 72 | +import { Injectable } from '@nestjs/common'; |
| 73 | +import { FeatureFlag } from './custom-metadata.decorator'; |
| 74 | + |
| 75 | +@Injectable() |
| 76 | +@FeatureFlag('experimental') |
| 77 | +export class CustomService {} |
| 78 | +``` |
| 79 | + |
| 80 | +Once metadata is attached to providers in this way, `DiscoveryService` makes it easy to filter providers based on assigned metadata. The following code snippet demonstrates how to retrieve providers that have been tagged with a specific metadata value: |
| 81 | + |
| 82 | +```typescript |
| 83 | +const providers = this.discoveryService.getProviders(); |
| 84 | + |
| 85 | +const [provider] = providers.filter( |
| 86 | + (item) => |
| 87 | + this.discoveryService.getMetadataByDecorator(FeatureFlag, item) === |
| 88 | + 'experimental', |
| 89 | +); |
| 90 | + |
| 91 | +console.log( |
| 92 | + 'Providers with the "experimental" feature flag metadata:', |
| 93 | + provider, |
| 94 | +); |
| 95 | +``` |
| 96 | + |
| 97 | +#### Conclusion |
| 98 | + |
| 99 | +The `DiscoveryService` is a versatile and powerful tool that enables runtime introspection in NestJS applications. By allowing dynamic discovery of providers, controllers, and metadata, it plays a crucial role in building extensible frameworks, plugins, and automation-driven features. Whether you need to scan and process providers, extract metadata for advanced processing, or create modular and scalable architectures, `DiscoveryService` provides an efficient and structured approach to achieving these goals. |
0 commit comments