Welcome to NestJs Travel Series
Modular
Modules in NestJs are the basic elements for building and organizing business units. Decorative module @Module() is used to declare the meta-information of the module:
- Which service providers are exported by this module
- Which dependency modules are imported into this module
- Which controllers are provided in this module
Each NestJs has at least one follow module, which is defined by app.module.ts. The root module generally does not put specific business logic, the specific business logic should sink to each sub-business module to do.
For example, we develop a mall system, which has the following business modules:
- Order Center
- User Center
- Payment Center
- Commodity Center
- Logistics Centre
Then we can define the following module structure:
|-- app.module.ts |-- order |-- order.module.ts |-- services |-- order.service.ts |-- controllers |-- order.controller.ts |-- user |-- user.module.ts |-- services |-- user.service.ts |-- controllers |-- user.controller.ts |-- pay |-- pay.module.ts |-- services |-- wepay.service.ts |-- alipay.service.ts |-- pay.service.ts |-- controller |-- pay.controller.ts ...
Modularization has the following advantages:
- Business Low Coupling
- Clear boundary
- Easy to sort out errors
- Easy to maintain
Module declaration and configuration
@ Module() decorative classes are module classes. The typical usage of this decorative device is as follows:
@Module({ providers: [UserService], controllers: [UserController], imports: [OrderModule], exports: [UserService] }) export class UserModule { }
Name of parameter | Explain |
---|---|
proviers | List of service providers. This module is available and can be injected automatically. |
controllers | Controller list, available in this module, for binding routing access |
imports | The module imported by this module, if the service provider of other modules needs to be used, must import other modules here. |
exports | The service provider exported by this module can only be used in other modules by the service provider defined here |
Module Reexport
There are the following uses in ts:
// a.ts export interface A { }
// index.ts export * from './a';
We can use the following code directly when we use it. Aspect encapsulation
import {A} from './index'
Modules in NestJs have similar usage, for example, we define two basic modules, which are basically imported together when they are used. At this time, we encapsulate them into a CoreModule through module re-export, and import them directly into CoreModule elsewhere.
@Module({ providers: [CommonService], exports: [CommonService] }) export class CommonModule {}
@Module({ providers: [Util], exports: [Util] }) export class UtilModule {}
@Module({ imports: [CommonModule, UtilModule], exports: [CommonModule, UtilModule] }) export class CoreModule {}
Module Initialization and Dependency Injection
If you need to run some logic when the module is instantiated and the logic has external dependencies, you can handle it in the following way
import { Module } from '@nestjs/common'; import { UserController } from './user.controller'; import { UserService } from './user.service'; @Module({ controllers: [UserController], providers: [UserService], }) export class catsModule { constructor(private readonly userService: UserService) { // No @Inject // Call userService } }
Global module
All the modules defined above need to be imported manually. If some modules are highly usable, such as tool modules, then they can be declared as global modules.
Global modules can be declared using @Global().
import { Module } from '@nestjs/common'; import { UserController } from './user.controller'; import { UserService } from './user.service'; @Global() @Module({ controllers: [UserController], providers: [UserService], }) export class catsModule { }
Dynamic module
All of the above definitions are static modules. If we need to declare our modules dynamically, such as database modules, I will return to the module only after the connection is successful. At this time, we need to use dynamic modules to process.
The module definition is returned using the module name. forRoot() method, which defines the dynamic module.
@Module({ providers: [DatabaseProvider] }) export class DatabaseModule { static async forRoot(env: string) { const provider = createDatabaseProvider(env); // Connecting different databases according to environment variables return { module: DatabaseModule, providers: [provider], exports: [provider] } } }
// user.module.ts @Module({ imports: [DatabaseModule.forRoot('production')] }) export class UserModule {}
Posture in production environment
There is a module example of the mall system above. When our business module is developed, we need to register it with AppModule to take effect. This is also a good example. It's a bit like plug-in. When we need to drop a business, the business code will not move and we can cancel the registration in AppModule.
@Module({ imports:[UserModule,GoodsModule,OrderModule,PayModule] }) export class AppModule {}
Ending
Modular system is another important feature of NestJs, which I think is based on DDD idea. Each module is a separate domain business and can be developed independently by a group. Multiple modules can be developed at the same time. If there is a dependency problem, you can first expose the module and the response interface. Others call your interface normally. When the implementation class is developed, NestJs will automatically inject the implementation class, and the caller's code will not be changed.
If you feel you have gained something, please share it with more friends who need it. Thank you.
If you want to exchange more knowledge about NestJs, welcome to join the discussion!