Skip to content

Commit 72bd020

Browse files
Merge branch 'vahidvdn-docs/discovery-service'
2 parents 894e698 + ca3e085 commit 72bd020

File tree

4 files changed

+120
-1
lines changed

4 files changed

+120
-1
lines changed
+99
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
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.

src/app/homepage/menu/menu.component.ts

+4
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,10 @@ export class MenuComponent implements OnInit {
7575
title: 'Lifecycle events',
7676
path: '/fundamentals/lifecycle-events',
7777
},
78+
{
79+
title: 'Discovery service',
80+
path: '/fundamentals/discovery-service',
81+
},
7882
{
7983
title: 'Platform agnosticism',
8084
path: '/fundamentals/platform-agnosticism',
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import { ChangeDetectionStrategy, Component } from '@angular/core';
2+
import { BasePageComponent } from '../../page/page.component';
3+
4+
@Component({
5+
selector: 'app-discovery-service',
6+
templateUrl: './discovery-service.component.html',
7+
changeDetection: ChangeDetectionStrategy.OnPush,
8+
})
9+
export class DiscoveryServiceComponent extends BasePageComponent {}

src/app/homepage/pages/fundamentals/fundamentals.module.ts

+8-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { RouterModule, Routes } from '@angular/router';
44
import { SharedModule } from '../../../shared/shared.module';
55
import { AsyncComponentsComponent } from './async-components/async-components.component';
66
import { CircularDependencyComponent } from './circular-dependency/circular-dependency.component';
7+
import { DiscoveryServiceComponent } from './discovery-service/discovery-service.component';
78
import { DependencyInjectionComponent } from './dependency-injection/dependency-injection.component';
89
import { DynamicModulesComponent } from './dynamic-modules/dynamic-modules.component';
910
import { LifecycleEventsComponent } from './lifecycle-events/lifecycle-events.component';
@@ -84,7 +85,12 @@ const routes: Routes = [
8485
{
8586
path: 'circular-dependency',
8687
component: CircularDependencyComponent,
87-
data: { title: 'Circular Dependency' },
88+
data: { title: 'Circular dependency' },
89+
},
90+
{
91+
path: 'discovery-service',
92+
component: DiscoveryServiceComponent,
93+
data: { title: 'Discovery service' },
8894
},
8995
];
9096

@@ -102,6 +108,7 @@ const routes: Routes = [
102108
LifecycleEventsComponent,
103109
ModuleRefComponent,
104110
LazyLoadingModulesComponent,
111+
DiscoveryServiceComponent,
105112
],
106113
})
107114
export class FundamentalsModule {}

0 commit comments

Comments
 (0)