Context & DI

Last Updated: May 19, 2025

This document describes the backend context and dependency injection (DI) system in the Typus Development Framework.

Overview

The Typus Development Framework uses a centralized context and dependency injection system to manage application state, services, and component lifecycle. This approach promotes:

  • Loose coupling between components
  • Testability through easy dependency mocking
  • Singleton management for shared resources
  • Automatic component registration via decorators

Dependency Injection

The framework uses TSyringe for dependency injection, enhanced with custom decorators for automatic component registration.

DI Container

Services

Controllers

Repositories

Modules

Other Services

Component Registration

Components are automatically registered using decorators:

@Service()
export class UserService extends BaseService {
  // Service implementation
}

@Controller()
export class UserController extends BaseController {
  constructor(
    @inject(UserService) private userService: UserService
  ) {
    super();
  }
  // Controller implementation
}

Dependency Resolution

Dependencies are resolved automatically when components are instantiated:

// In a module
const controller = container.resolve(UserController);
const service = container.resolve(UserService);

Global Context

The framework maintains a global context with shared resources:

  • Logger - Global logging instance
  • Prisma - Database client
  • Config - Application configuration

These resources are accessible throughout the application:

// Access global logger
this.logger.info('Message');

// Access global prisma client
const users = await this.prisma.user.findMany();

Singleton Management

Services are registered as singletons by default, ensuring that only one instance exists throughout the application lifecycle:

// In core/decorators/component.ts
container.registerSingleton(name, target);

Core services are explicitly registered as singletons during application initialization:

// In Application.ts
private registerSingletons(): void {
  container.registerSingleton(DslService);
  container.registerSingleton(DynamicRouterService);
  // Other core services
}

Module Context

Each module maintains its own context, including:

  • Base path - The module's API base path
  • Controller - The module's controller instance
  • Service - The module's service instance
  • Router - Express router for the module
// In a module class
constructor() {
  const basePath = 'users';
  const controller = container.resolve(UserController);
  const service = container.resolve(UserService);
  
  super(basePath, controller, service);
}

Request Context

Each request has its own context, including:

  • User - The authenticated user (if any)
  • Validated data - Data that has passed validation
  • Request-specific metadata - Headers, params, query, etc.
// In a controller method
async getUser(req: Request, res: Response) {
  const { id } = req.params;
  const user = req.user; // Authenticated user
  const validatedData = this.getValidatedData(req);
  
  return await this.userService.getUser(id);
}

Benefits

The context and DI system provides several benefits:

  1. Simplified component creation - No need to manually wire dependencies
  2. Consistent component lifecycle - Components are created and destroyed consistently
  3. Centralized resource management - Shared resources are managed in one place
  4. Improved testability - Dependencies can be easily mocked for testing
  5. Reduced boilerplate - Decorators handle registration and injection

Best Practices

  1. Use decorators for component registration
  2. Inject dependencies through constructor parameters
  3. Access global context through base classes
  4. Avoid circular dependencies by designing clear component hierarchies
  5. Use interfaces for dependency contracts when appropriate

WARNING

Failed to fetch dynamically imported module: https://typus.dev/assets/RecursiveNavItem-Cep7andh.js

{ "stack": "AppError: Failed to fetch dynamically imported module: https://typus.dev/assets/RecursiveNavItem-Cep7andh.js\n at https://typus.dev/assets/index-DS79FI73.js:315:420\n at dn (https://typus.dev/assets/vue-vendor-Ct83yDeK.js:13:1385)\n at We (https://typus.dev/assets/vue-vendor-Ct83yDeK.js:13:1455)\n at Ws.t.__weh.t.__weh (https://typus.dev/assets/vue-vendor-Ct83yDeK.js:14:7364)\n at jt (https://typus.dev/assets/vue-vendor-Ct83yDeK.js:13:1866)\n at v (https://typus.dev/assets/vue-vendor-Ct83yDeK.js:14:4019)\n at https://typus.dev/assets/vue-vendor-Ct83yDeK.js:14:4097" }