DI System — Aquilia Documentation
Comprehensive guide and documentation for DI System in the Aquilia framework. View API reference, examples, and implementation patterns.
Core Subsystems / Dependency Injection Dependency Injection Overview Aquilia's DI subsystem acts as the central nervous system of your web application. It integrates manifests, hierarchical scopes, request lifecycles, and controller resolution into a single O(1) lookup path completing in under 3µs. System Architecture Core Pillars , , , , , , , , , ].map((card, i) => ( ))} Module Map The DI system lives under aquilia/di/ and is composed of these modules: Module Contents `).replace(/^_/, '')}`}> ))} Registration Flow The Registry.from_manifests() pipeline processes manifests through four sequential phases before building the container: , , , , ].map((p, i) => ( ))} from aquilia.di import Registry # Typically called by the engine during startup: registry = Registry.from_manifests( manifests=[users_manifest, orders_manifest, payments_manifest], config=app_config, enforce_cross_app=True, # Strict in production ) # Build the root container container = registry.build_container() await container.startup() # Run lifecycle hooks Resolution Hot Path resolve_async() is the primary resolution method called on every request. It is optimized for <3µs cached lookups with an inlined token-to-key conversion path: # Simplified view of resolve_async internals: async def resolve_async(self, token, *, tag=None, optional=False): # 1. Inline token_to_key (avoid function-call overhead) # Uses _type_key_cache (dict) for O(1) type → string lookup key = self._type_key_cache.get(token) or self._token_to_key(token) # 2. Check cache first — O(1) dict lookup cache_key = f" : " if tag else key cached = self._cache.get(cache_key) if cached is not _SENTINEL: return cached # Usage inside Web Framework Aquilia promotes clean separation of concerns. Do not manually pull dependencies from the request container. Instead, use Constructor Injection to automatically wire services, repositories, and models. 1. Define and Annotate Services ") async def get_user(self, ctx): # Use constructor injected service directly user = await self.user_service.get_user(ctx.request.params["user_id"]) return ctx.json(user) Anti-Pattern Warning Do NOT resolve dependencies dynamically inside routes via await ctx.container.resolve_async(UserService). This hides dependencies, makes unit testing complex, and prevents compile-time dependency cycle and scope validation checks. Always prefer Constructor Injection. Provider Types at a Glance Provider Use Case Async Init `).replace(/^_/, '')}`}> ))} Error Taxonomy All DI errors inherit from DIError and include rich diagnostic messages with file locations, candidate lists, and suggested fixes: Error Trigger Suggested Fix `).replace(/^_/, '')}`}> ))} Structured faults at boot. The DI layer now raises structured DIFaults rather than bare ValueErrors. A manifest declaring an unknown scope fails fast with INVALID_SERVICE_SCOPE (always fatal, lists the valid scopes). When strict_service_registration is on, a service that fails to register raises SERVICE_REGISTRATION_FAILED and aborts boot; otherwise it logs a warning and continues. Invalid di config raises DI_CONFIG_INVALID. CLI Tooling The DI system provides five CLI commands for validation, visualization, and profiling: Command Description ))} Explore the DI Docs ))} Container )
Go to Homepage