Module Builder — Aquilia Documentation
Comprehensive guide and documentation for Module Builder in the Aquilia framework. View API reference, examples, and implementation patterns.
Module Builder aquilia.config_builders.Module — Application unit configuration The Module class is a fluent builder for defining isolated application units within a workspace. Each module represents a self-contained logical boundary that groups controllers, services, routes, models, serializers, and middleware under a single, explicit configuration contract. ModuleConfig Dataclass The Module builder produces a ModuleConfig dataclass via .build(). This dataclass is what Workspace.to_dict() serializes into the final config. @dataclass class ModuleConfig: """Module configuration produced by Module.build().""" name: str = "" version: str = "0.1.0" description: str = "" fault_domain: str = "" route_prefix: str = "" depends_on: List[str] = field(default_factory=list) controllers: List[str] = field(default_factory=list) routes: List[str] = field(default_factory=list) services: List[str] = field(default_factory=list) providers: List[str] = field(default_factory=list) middlewares: List[str] = field(default_factory=list) socket_controllers: List[str] = field(default_factory=list) models: List[str] = field(default_factory=list) serializers: List[str] = field(default_factory=list) tags: List[str] = field(default_factory=list) auto_discover: Optional[str] = None database: Optional[Dict[str, Any]] = None def to_dict(self) -> Dict[str, Any]: """Convert to dictionary format.""" ... Field Type Default Description ))} Module Builder The Module class wraps ModuleConfig in a fluent builder pattern. Every method returns self for chaining. class Module: """Fluent module builder.""" def __init__(self, name: str, version: str = "0.1.0", description: str = ""): self._config = ModuleConfig( name=name, version=version, description=description, ) def build(self) -> ModuleConfig: """Build module configuration.""" return self._config .auto_discover() Tells the Aquilary discovery system to scan the specified directory for controllers, services, routes, models, and other components. This is the most common way to register components — you point the module at a directory and Aquilia finds everything. def auto_discover(self, path: str) -> "Module": """ Set auto-discovery path. The Aquilary discovery system will scan this directory for: - Controllers (classes inheriting from Controller) - Services (classes decorated with @service) - Routes (functions decorated with @route) - Models (.amdl files) - Serializers (classes inheriting from Serializer) """ self._config.auto_discover = path return self # Scan apps/users/ for all components Module("users").auto_discover("apps/users") # Combined with explicit registrations Module("users") .auto_discover("apps/users") .register_services("ExtraService") # Add extras not in the scan path .route_prefix() Sets a URL prefix for all controllers and routes in this module. Prefixed before the controller's own prefix attribute. def route_prefix(self, prefix: str) -> "Module": """Set URL prefix for all routes in this module.""" self._config.route_prefix = prefix return self # Example: Module prefix + Controller prefix # Module("users").route_prefix("/api/v1") # class UserController(Controller): # prefix = "/users" # # Final route: /api/v1/users/ .fault_domain() Assigns this module to a fault isolation domain. Faults raised within this module are scoped to its domain, enabling domain-specific error handlers and preventing fault propagation across module boundaries. def fault_domain(self, domain: str) -> "Module": """Set fault isolation domain.""" self._config.fault_domain = domain return self # Usage: Module("payments") .fault_domain("payments") # Faults scoped to "payments" domain .route_prefix("/payments") .depends_on() Declares dependencies on other modules. This is used for startup ordering and dependency validation — if module A depends on module B, B is initialized first. def depends_on(self, *modules: str) -> "Module": """Declare module dependencies.""" self._config.depends_on = list(modules) return self # Usage: Module("orders") .depends_on("users", "catalog", "payments") .route_prefix("/orders") .tags() Assigns OpenAPI tags to all controllers in this module. Tags are used for grouping endpoints in the Swagger UI and ReDoc documentation. def tags(self, *tags: str) -> "Module": """Set OpenAPI tags for this module.""" self._config.tags = list(tags) return self # Usage: Module("catalog") .tags("Products", "Categories", "Search") .route_prefix("/catalog") Registration Methods These methods explicitly register component names. They accept *args (variadic string names) and return self for chaining. Use these when auto-discovery is insufficient or when you need explicit control over what's registered. Method Signature Registers To ))} # All registration methods follow this pattern: def register_controllers(self, *names: str) -> "Module": """Register controller class names.""" self._config.controllers = list(names) return self def register_services(self, *names: str) -> "Module": """Register service class names.""" self._config.services = list(names) return self # ... same pattern for all others Module("users") .register_controllers("UserController", "ProfileController", "AdminController") .register_services("UserService", "AuthService", "TokenService") .register_providers("DatabaseProvider", "CacheProvider") .register_routes("health_check", "status") .register_sockets("ChatController") .register_middlewares("TenantMiddleware") .register_models("models/user.amdl", "models/profile.amdl") .register_serializers("UserSerializer", "ProfileSerializer") Note: Registration methods replace the list (they don't append). Calling .register_controllers("A") then .register_controllers("B") results in only ["B"]. Include all names in a single call. .database() Configures a module-specific database. This overrides the workspace-level database for all models and queries within this module. def database( self, url: str = "sqlite:///db.sqlite3", auto_connect: bool = True, auto_create: bool = True, auto_migrate: bool = False, migrations_dir: str = "migrations", **kwargs, ) -> "Module": Parameter Type Default Description ))} workspace = ( Workspace("multi-db-app") # Workspace-level default database .database(url="postgresql://main-db/app") # Module with its own database .module( Module("analytics") .route_prefix("/analytics") .database( url="postgresql://analytics-db/analytics", auto_connect=True, auto_create=True, pool_size=10, ) .register_models("models/analytics.amdl") ) # Module using the default database .module( Module("users") .route_prefix("/users") # No .database() → inherits workspace-level DB ) ) .build() & Serialization .build() returns the underlying ModuleConfig dataclass. This is called automatically by Workspace.module(). The ModuleConfig.to_dict() method serializes it for the config pipeline: # Module("users") # .route_prefix("/users") # .auto_discover("apps/users") # .fault_domain("users") # .tags("Users") # .register_controllers("UserController") # .register_services("UserService") # .build().to_dict() Complete Module Examples # Just a name and auto-discovery — Aquilia finds everything Module("blog").auto_discover("apps/blog") # Full control over what's registered Module("users", version="1.2.0", description="User management") .route_prefix("/api/v1/users") .fault_domain("identity") .depends_on("auth") .tags("Users", "Identity") .register_controllers("UserController", "ProfileController", "AvatarController") .register_services("UserService", "ProfileService", "EmailVerificationService") .register_providers("UserRepository", "ProfileRepository") .register_serializers("UserSerializer", "ProfileSerializer", "AvatarSerializer") .register_models("models/user.amdl", "models/profile.amdl") .register_middlewares("TenantIsolationMiddleware") .database( url="postgresql://identity-db/users", auto_migrate=True, pool_size=15, ) # Discover most things, explicitly add edge cases Module("orders") .auto_discover("apps/orders") # Finds controllers, services, etc. .route_prefix("/orders") .fault_domain("commerce") .depends_on("users", "catalog", "payments") .tags("Orders", "Commerce") .register_providers("StripePaymentProvider") # Not in apps/orders/ .register_middlewares("OrderValidationMiddleware") YAML Equivalent The same module configuration in YAML format: modules: - name: users version: "1.2.0" description: User management route_prefix: /api/v1/users fault_domain: identity depends_on: - auth tags: - Users - Identity auto_discover: apps/users controllers: - UserController - ProfileController services: - UserService - ProfileService models: - models/user.amdl - models/profile.amdl database: url: postgresql://identity-db/users auto_connect: true auto_migrate: true pool_size: 15 ← Workspace Builder Integrations )
Go to Homepage