Define and implement core constructs such as Application and Component for LoopBack 4 framework
—
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Pending
The risk profile of this skill
The Component system in LoopBack Core provides a modular architecture for packaging and contributing functionality to applications. Components can declare controllers, providers, servers, lifecycle observers, services, bindings, and even sub-components, making applications highly composable and extensible.
The core interface that defines what resources a component can contribute to an application.
/**
* A component declares a set of artifacts so that they can be contributed to
* an application as a group
*/
interface Component {
/** An array of controller classes */
controllers?: ControllerClass[];
/** A map of providers to be bound to the application context */
providers?: ProviderMap;
/** A map of classes to be bound to the application context */
classes?: ClassMap;
/** A map of name/class pairs for servers */
servers?: { [name: string]: Constructor<Server> };
/** An array of lifecycle observer classes */
lifeCycleObservers?: Constructor<LifeCycleObserver>[];
/** An array of service or provider classes */
services?: ServiceOrProviderClass[];
/** An array of bindings to be added to the application context */
bindings?: Binding[];
/** An array of component classes */
components?: Constructor<Component>[];
/** Other properties */
[prop: string]: any;
}Usage Examples:
import { Component, ControllerClass, LifeCycleObserver } from "@loopback/core";
// Basic component with controllers
class ProductComponent implements Component {
controllers = [ProductController, CategoryController];
}
// Comprehensive component
class EcommerceComponent implements Component {
controllers = [
ProductController,
CategoryController,
OrderController
];
providers = {
'services.payment': PaymentServiceProvider,
'services.shipping': ShippingServiceProvider
};
classes = {
'repositories.product': ProductRepository,
'repositories.order': OrderRepository
};
servers = {
'webhook': WebhookServer
};
lifeCycleObservers = [
DatabaseMigrationObserver,
CacheWarmupObserver
];
services = [
EmailService,
LoggingService
];
bindings = [
Binding.bind('config.ecommerce').to({
currency: 'USD',
taxRate: 0.08
})
];
components = [
AuthenticationComponent,
ValidationComponent
];
}Function that mounts a component instance to an application, registering all declared resources.
/**
* Mount a component to an Application.
*/
function mountComponent(app: Application, component: Component): void;Usage Examples:
import { Application, mountComponent, Component } from "@loopback/core";
class MyComponent implements Component {
controllers = [UserController];
providers = {
'services.logger': LoggerProvider
};
}
const app = new Application();
const componentInstance = new MyComponent();
// Mount component manually
mountComponent(app, componentInstance);
// Typically done automatically when using app.component()
app.component(MyComponent); // This calls mountComponent internallyMap interface for organizing provider classes by binding key.
/**
* A map of provider classes to be bound to a context
*/
interface ProviderMap {
[key: string]: Constructor<Provider<BoundValue>>;
}Usage Examples:
import { Component, Provider, ProviderMap } from "@loopback/core";
// Email service provider
class EmailServiceProvider implements Provider<EmailService> {
value(): EmailService {
return new EmailService({
apiKey: process.env.EMAIL_API_KEY,
baseUrl: 'https://api.emailservice.com'
});
}
}
// Configuration provider
class AppConfigProvider implements Provider<AppConfig> {
value(): AppConfig {
return {
database: {
host: process.env.DB_HOST || 'localhost',
port: parseInt(process.env.DB_PORT || '5432')
},
redis: {
url: process.env.REDIS_URL || 'redis://localhost:6379'
}
};
}
}
// Component using provider map
class CoreServicesComponent implements Component {
providers: ProviderMap = {
'services.email': EmailServiceProvider,
'services.config': AppConfigProvider,
'services.logger': LoggerServiceProvider,
'services.metrics': MetricsServiceProvider
};
}Map interface for organizing regular classes by binding key.
/**
* A map of classes to be bound to a context
*/
interface ClassMap {
[key: string]: Constructor<BoundValue>;
}Usage Examples:
import { Component, ClassMap } from "@loopback/core";
// Repository classes
class UserRepository {
constructor(
@inject('datasources.db') private datasource: DataSource
) {}
async findById(id: string): Promise<User | null> {
// Repository implementation
return null;
}
}
class ProductRepository {
constructor(
@inject('datasources.db') private datasource: DataSource
) {}
async findByCategory(category: string): Promise<Product[]> {
// Repository implementation
return [];
}
}
// Component using class map
class RepositoryComponent implements Component {
classes: ClassMap = {
'repositories.user': UserRepository,
'repositories.product': ProductRepository,
'repositories.order': OrderRepository,
'services.cache': CacheService
};
}Components can include other components, enabling hierarchical composition and modularity.
Usage Examples:
import { Component } from "@loopback/core";
// Base authentication component
class AuthenticationComponent implements Component {
providers = {
'auth.strategy.jwt': JwtStrategyProvider,
'auth.strategy.oauth': OAuthStrategyProvider
};
services = [
TokenService,
UserService
];
}
// Authorization component that builds on authentication
class AuthorizationComponent implements Component {
components = [
AuthenticationComponent // Include authentication
];
providers = {
'auth.rbac': RoleBasedAccessControlProvider,
'auth.permissions': PermissionServiceProvider
};
}
// Main application component that includes everything
class AppComponent implements Component {
components = [
AuthorizationComponent, // This transitively includes AuthenticationComponent
LoggingComponent,
DatabaseComponent
];
controllers = [
AppController,
HealthController
];
}Components can contribute server implementations for different protocols.
Usage Examples:
import { Component, Server, LifeCycleObserver } from "@loopback/core";
class RestServer implements Server, LifeCycleObserver {
listening = false;
async start(): Promise<void> {
// Start REST server
this.listening = true;
}
async stop(): Promise<void> {
// Stop REST server
this.listening = false;
}
}
class GraphQLServer implements Server, LifeCycleObserver {
listening = false;
async start(): Promise<void> {
// Start GraphQL server
this.listening = true;
}
async stop(): Promise<void> {
// Stop GraphQL server
this.listening = false;
}
}
// Multi-protocol component
class ApiComponent implements Component {
servers = {
'rest': RestServer,
'graphql': GraphQLServer
};
controllers = [
RestApiController,
GraphQLController
];
lifeCycleObservers = [
ServerStartupObserver,
ServerHealthCheckObserver
];
}Components can contribute pre-configured bindings for complex setup scenarios.
Usage Examples:
import { Component, Binding, BindingScope } from "@loopback/core";
class DatabaseComponent implements Component {
bindings = [
// Database connection binding
Binding.bind('datasources.primary')
.toProvider(DatabaseConnectionProvider)
.inScope(BindingScope.SINGLETON),
// Connection pool configuration
Binding.bind('config.database.pool')
.to({
min: 2,
max: 10,
acquireTimeoutMillis: 60000,
createTimeoutMillis: 30000
}),
// Migration configuration
Binding.bind('config.database.migrations')
.to({
directory: './migrations',
autoRun: process.env.NODE_ENV !== 'production'
})
];
lifeCycleObservers = [
DatabaseMigrationObserver
];
}Components can contribute services and providers for application-wide functionality.
Usage Examples:
import { Component, ServiceOrProviderClass } from "@loopback/core";
// Service classes
class EmailService {
async sendEmail(to: string, subject: string, body: string): Promise<void> {
// Implementation
}
}
class SmsService {
async sendSms(to: string, message: string): Promise<void> {
// Implementation
}
}
// Provider for external API
class WeatherServiceProvider implements Provider<WeatherService> {
value(): WeatherService {
return new WeatherService(process.env.WEATHER_API_KEY);
}
}
// Communication services component
class CommunicationComponent implements Component {
services: ServiceOrProviderClass[] = [
EmailService,
SmsService,
WeatherServiceProvider,
NotificationService
];
providers = {
'services.communication.config': CommunicationConfigProvider
};
}interface ProviderMap {
[key: string]: Constructor<Provider<BoundValue>>;
}
interface ClassMap {
[key: string]: Constructor<BoundValue>;
}
type ControllerClass<T = any> = Constructor<T>;
type ServiceOrProviderClass<T = any> =
| Constructor<T | Provider<T>>
| DynamicValueProviderClass<T>;