Modules
Modules organize the application into cohesive blocks of functionality.
Modules are the building blocks of a Vela application. Each module groups related controllers and providers together, and can import or export functionality to other modules.
Defining a Module
The @Module() decorator accepts an options object with four properties:
| Property | Description |
|---|---|
providers | Providers to be instantiated and available within this module |
controllers | Controllers that belong to this module |
imports | Other modules whose exported providers are needed |
exports | Providers to make available to importing modules |
import { Module } from '@velajs/vela';
@Module({
providers: [SpiritsService],
controllers: [SpiritsController],
exports: [SpiritsService],
})
class SpiritsModule {}Root Module
Every application has a root module that serves as the entry point. Bootstrap it with VelaFactory.create():
import { VelaFactory } from '@velajs/vela';
@Module({
imports: [SpiritsModule, UsersModule],
})
class AppModule {}
const app = await VelaFactory.create(AppModule);Feature Modules
Split your application into feature modules to keep related functionality together:
@Module({
providers: [UsersService],
controllers: [UsersController],
exports: [UsersService],
})
class UsersModule {}
@Module({
imports: [UsersModule],
providers: [AuthService],
controllers: [AuthController],
})
class AuthModule {}The AuthModule imports UsersModule, which means UsersService (because it is exported) becomes available for injection inside AuthModule.
Imports and Exports
- Imports — bring in exported providers from other modules
- Exports — make providers available to modules that import this one
Only exported providers are shared. Providers that are registered but not exported remain private to their module.
Dynamic Modules
Dynamic modules allow you to create configurable modules at runtime. A dynamic module returns a DynamicModule object:
interface DynamicModule {
module: Type;
providers?: Provider[];
controllers?: Type[];
exports?: (Type | InjectionToken)[];
}forRoot / forFeature Pattern
Use static methods to create configurable modules:
@Module({})
class DatabaseModule {
static forRoot(url: string): DynamicModule {
return {
module: DatabaseModule,
providers: [
{ provide: 'DB_URL', useValue: url },
DatabaseService,
],
exports: [DatabaseService],
};
}
static forFeature(entities: Type[]): DynamicModule {
const repositories = entities.map((entity) => ({
provide: `${entity.name}Repository`,
useFactory: (db: DatabaseService) => db.getRepository(entity),
inject: [DatabaseService],
}));
return {
module: DatabaseModule,
providers: repositories,
exports: repositories.map((r) => r.provide),
};
}
}Use it in your root module:
@Module({
imports: [
DatabaseModule.forRoot('postgres://localhost/mydb'),
DatabaseModule.forFeature([User, Post]),
],
})
class AppModule {}Circular Dependencies
Vela detects circular module dependencies at startup and throws an error. If module A imports module B and module B imports module A, the application will fail to start with a clear error message. Restructure your modules or extract shared providers into a separate module to resolve this.
Providers
Providers are injectable services that encapsulate business logic.
Middleware
Middleware runs before route handlers, with access to the request context.
Last updated on