Dynamic method invocation for decoupled, modular NestJS applications.
MIT License
RegistryLib is a NestJS module that facilitates dynamic method invocation across unrelated modules. It allows developers to manage and invoke methods from different services at runtime without requiring direct imports or tight coupling, promoting clean, modular, and scalable code.
In large-scale NestJS applications, managing dependencies across various modules often leads to tightly coupled code, complex conditional logic, and difficulties in extending functionality. As new modules are added, the need to update dependencies and ensure seamless integration becomes cumbersome.
RegistryLib addresses these challenges by providing a centralized service that manages method invocation across modules. This reduces boilerplate code, simplifies module interactions, and allows for independent module development.
You can install RegistryLib using npm/yarn/pnpm:
npm:
npm install @diexpkg/registry
yarn:
yarn add @diexpkg/registry
pnpm:
pnpm install @diexpkg/registry
To start using RegistryLib in your NestJS application, follow these steps:
Import the RegistryModule: Include RegistryModule
in your main application module.
import { RegistryModule } from '@diexpkg/registry';
@Module({
imports: [RegistryModule],
})
export class AppModule {}
Register Services with @ServiceProvider
and @MethodProvider
Decorators:
@ServiceProvider
decorator on your module to register it with the registry. This is necessary for any module whose services you want to invoke dynamically.@MethodProvider
decorator on the service methods you want to expose. The string passed to @MethodProvider
should be a unique identifier for that service.import { Injectable, Module } from '@nestjs/common';
import { MethodProvider, ServiceProvider } from '@diexpkg/registry';
@MethodProvider('SimpleService')
@Injectable()
class SimpleService {
world(): string {
return 'world';
}
}
@ServiceProvider('SimpleModule')
@Module({ providers: [SimpleService] })
class SimpleModule {}
Invoke Methods Dynamically Using RegistryService
:
RegistryService
where needed and use it to dynamically call methods from registered services. The graph
property in RegistryService
represents the internal structure that holds the references to all registered services and their methods.import { Injectable, Logger } from '@nestjs/common';
import { RegistryService } from '@diexpkg/registry';
@Injectable()
class HelloService {
private readonly _logger = new Logger();
constructor(private readonly _registryService: RegistryService) {}
async hello(): Promise<string> {
const world = await this._registryService.graph.tryCall<SimpleService>({
keys: ['SimpleModule', 'SimpleService'],
method: 'world',
params: [],
});
this._logger.log(`Hello: ${world}`);
return world;
}
}
The RegistryService
is the central service that manages the registry of service methods and enables dynamic, runtime method calls. It builds a graph of all registered services and their methods during the application's initialization.
The @MethodProvider
decorator marks a service method that will be registered in the RegistryService
. The string passed to the decorator should uniquely identify the service across the application.
The @ServiceProvider
decorator registers a module and its services within the RegistryService
. Only modules that need their services to be invoked dynamically require this decorator.
RegistryLib
integrates seamlessly with NestJSs existing Dependency Injection system. It doesnt replace or modify NestJS's DI but extends it by providing a dynamic invocation mechanism, allowing methods to be called based on runtime conditions rather than compile-time imports. This adds flexibility to module interaction and service usage.
if/else
or switch
statements by dynamically invoking methods based on runtime conditions.RegistryLib is compatible with NestJS versions X.X.X and above. It has been tested with the following versions:
Make sure your project is using a compatible version of NestJS to avoid potential issues.