Dependency Injection
Mach includes a dependency injection system for providing services to controllers.
Instead of constructing a controller’s dependencies manually, you can register them with AppBuilder and receive them through the controller’s constructor.
Register a Service
Section titled “Register a Service”Services are registered on the application builder.
For example:
mach::AppBuilder builder;
builder.addSingleton<UserService>();addSingleton<T>() registers a single instance of T that can be provided to controllers.
A service only needs to be registered before the application is built. The order in which services are registered does not matter.
Inject a Service into a Controller
Section titled “Inject a Service into a Controller”Controllers receive dependencies through constructor injection:
class UsersController final : public mach::ControllerBase {public: inline static constexpr std::string_view route = "/users";
explicit UsersController(UserService& userService) : m_userService(userService) {}
mach::Reply<std::string> getUsers() { return ok(m_userService.getUsers()); }
static void configure(mach::ControllerBuilder<UsersController>& builder) { builder.mapGet("/", &UsersController::getUsers); }
private: UserService& m_userService;};When Mach creates UsersController, it resolves UserService from the dependency injection container and passes it to the constructor.
Register Controller Dependencies
Section titled “Register Controller Dependencies”The dependencies required by a controller are declared when the controller is registered:
mach::AppBuilder builder;
builder.addSingleton<UserService>();builder.addController<UsersController, UserService>();
auto app = builder.build();The dependency list tells Mach which registered services should be passed to the controller constructor.
All required services must be registered by the time the application is built.
Multiple Dependencies
Section titled “Multiple Dependencies”A controller can receive multiple services through its constructor:
class UsersController final : public mach::ControllerBase {public: UsersController(UserService& userService, AuditService& auditService) : m_userService(userService), m_auditService(auditService) {}
static void configure(mach::ControllerBuilder<UsersController>& builder) { // ... }
private: UserService& m_userService; AuditService& m_auditService;};Register both services and list them when registering the controller:
builder.addSingleton<UserService>();builder.addSingleton<AuditService>();
builder.addController<UsersController, UserService, AuditService>();The order of the dependency template arguments must match the order of the controller constructor parameters.
Complete Example
Section titled “Complete Example”class UserService {public: std::string getUserName() const { return "Alice"; }};
class UsersController final : public mach::ControllerBase {public: inline static constexpr std::string_view route = "/users";
explicit UsersController(UserService& userService) : m_userService(userService) {}
mach::Reply<std::string> getUser() { return ok(m_userService.getUserName()); }
static void configure(mach::ControllerBuilder<UsersController>& builder) { builder.mapGet("/", &UsersController::getUser); }
private: UserService& m_userService;};
int main() { mach::AppBuilder builder;
builder.addSingleton<UserService>(); builder.addController<UsersController, UserService>();
auto app = builder.build();
return app.run();}The controller declares the services it needs through its constructor, while the application builder provides the registrations Mach uses to construct it.
You’ve now covered the core controller workflow: creating controllers, defining actions, binding request bodies, returning results, and injecting dependencies.