Skip to main content

registerControllers()

What?

Instantiates and wires Controller classes that handle the logic for specific routes.

Why?

Controllers bridge the gap between HTTP requests and business logic. CoreServer needs to know about them to map route handlers (e.g., 'Account.login') to actual method calls.

How to use

public async initControllers() {
await this.registerControllers([
AccountController,
CartController,
OrderController
]);
}

Under the Hood: The Controller Registry

  1. Instantiation: Every controller is instantiated by the CoreServer, which passes itself (the server instance) to the controller's constructor.
  2. Map Storage: The framework stores these instances in a Map<string, BaseController>.
  3. Naming Convention: The key in the map is automatically derived by stripping "Controller" from the class name (e.g., AccountController becomes Account).

The Bigger Picture: Controllers as Orchestrators

Controllers are the glue of the server. They don't exist in isolation; they are the intersection of Routes (which trigger them) and Services (which they consume).

Connection to Services (Inward)

Controllers use the @Inject() decorator to pull services from the DI Container. Because registerServices() happens before registerControllers(), the services are already declared and ready to be resolved when the controller is instantiated.

export class AccountController extends BaseController {
@Inject()
private readonly accountService: AccountService; // Wired via DI
}

Connection to Routes (Outward)

Routes are defined as a static configuration array. Instead of passing an anonymous function, Archibald uses a String Handler pattern to link a route to a controller method.

// Route Configuration
{
method: RouteMethod.GET,
path: '/users/address',
handler: 'AccountController.getAddress' // Links to the registered instance
}

Under the Hood: String Resolution

When registerRoute encounters a string handler, it performs the following logic:

  1. Parsing: Splits the string by . to identify the controller key and the method name (e.g., ['AccountController', 'getAddress']).
  2. Lookup: Retrieves the controller instance from the internal controllers Map.
  3. Binding: Wraps the method call in a Hapi handler and uses .bind(controller). This is critical as it ensures that this inside the controller method correctly points to the controller instance, allowing access to its @Inject()ed services.

The Wiring Flow Diagram