reinhardt-di
FastAPI-inspired dependency injection system for Reinhardt.
Overview
Provides a FastAPI-style dependency injection system with support for request-scoped and singleton-scoped dependency caching, automatic resolution of nested dependencies, and integration with authentication and database connections.
Delivers the FastAPI development experience in Rust with type-safe and async-first design.
Installation
Add reinhardt to your Cargo.toml:
[]
= { = "0.1.0-alpha.1", = ["di"] }
# Or use a preset:
# reinhardt = { version = "0.1.0-alpha.1", features = ["standard"] } # Recommended
# reinhardt = { version = "0.1.0-alpha.1", features = ["full"] } # All features
Then import DI features:
use ;
use ;
Note: DI features are included in the standard and full feature presets.
Core Concepts
Dependency Scopes
- Request Scope: Dependencies cached per request (default)
- Singleton Scope: Dependencies shared across the entire application
Automatic Injection
Types implementing Default + Clone + Send + Sync + 'static automatically implement the Injectable trait and can be used as dependencies.
Implemented Features ✓
Core Dependency Injection
Dependency Wrappers
reinhardt-di provides two wrapper types for dependency injection:
-
✓
Injected<T>Wrapper: Low-level dependency wrapper with metadataArc<T>wrapper with injection metadata (scope, cached status)Dereftrait for transparent access to inner valueresolve(&ctx)- Resolve with cache (default)resolve_uncached(&ctx)- Resolve without cache- Metadata access via
.scope()and.is_cached()methods - Direct control over dependency resolution
-
✓
Depends<T>Wrapper: High-level FastAPI-style builderDepends::<T>::new()- Cache enabled (default)Depends::<T>::no_cache()- Cache disabledresolve(&ctx)- Dependency resolutionfrom_value(value)- Generate from value for testing- More ergonomic API for most use cases
-
✓
OptionalInjected<T>Wrapper: Optional dependency wrapperOption<Injected<T>>for dependencies that may not be availableresolve(&ctx)- ReturnsOk(None)if dependency not found- Useful for optional features or fallback behavior
Recommendation: Use Depends<T> for most cases (more ergonomic). Use Injected<T> when you need direct control or metadata access.
-
✓ Injectable Trait: Define types that can be injected as dependencies
- Auto-implementation: For types implementing
Default + Clone + Send + Sync + 'static - Custom implementation: When complex initialization logic is needed
- Auto-implementation: For types implementing
-
✓ InjectionContext: Context for dependency resolution
- Builder pattern for context creation:
InjectionContext::builder(singleton).build() - Internal scope management (request and singleton)
- Generate new context per request
- Builder pattern for context creation:
-
✓ RequestScope: Caching within requests
- Type-based cache (using
TypeIdas key) - Thread-safe implementation (
Arc<RwLock<HashMap>>)
- Type-based cache (using
-
✓ SingletonScope: Application-wide caching
- Dependencies shared across all requests
- Thread-safe implementation
Advanced Features
-
✓ Dependency Caching: Automatic caching within request scope
- Same dependency is generated only once even when requested multiple times
- Cache is shared between nested dependencies
- Cache enable/disable control available
-
✓ Nested Dependencies: Dependencies can depend on other dependencies
- Automatic dependency graph resolution
- Circular dependency detection and error handling
-
✓ Dependency Overrides: Dependency overrides for testing
- Use different implementations for production and testing
- Application-level override management
- Support for overrides with sub-dependencies
-
✓ Provider System: Async factory pattern
Providertrait - Generic interface for providing dependenciesProviderFn- Function-based provider- Any async closure can be used as a provider
Error Handling
- ✓ DiError: Comprehensive error type
NotFound- Dependency not foundCircularDependency- Circular dependency detectionProviderError- Provider errorsTypeMismatch- Type mismatchScopeError- Scope-related errors
Integration Support
-
✓ HTTP Integration: Integration with HTTP requests/responses
- Dependency injection from requests
- Support for connection info injection
-
✓ WebSocket Support: Dependency injection into WebSocket connections
- Use
Depends<T>in WebSocket handlers
- Use
Advanced Dependency Patterns ✓
Generator-based Dependencies (yield pattern)
- Lifecycle Management: Setup/teardown pattern
- Context Manager: Automatic resource cleanup
- Error Handling: Cleanup execution even on errors
- Streaming Support: Streaming response support
- WebSocket Support: Integration with WebSocket handlers
use ;
Dependency Classes (Class-based dependencies)
- Callable Dependencies: Struct-based dependencies with call methods
- Async Callables: Async dependency method support
- Stateful Dependencies: Dependencies with internal state
- Method-based Injection: Flexible dependency construction
Parametrized Dependencies (Parameterized dependencies)
- Path Parameter Integration: Access to path parameters from dependencies
- Shared Parameters: Share path parameters between endpoints and dependencies
- Type-safe Extraction: Compile-time validated parameter passing
// Path parameter accessible in dependency
Schema Generation (Schema generation)
- Dependency Deduplication: Shared dependencies appear only once in schema
- Transitive Dependencies: Automatic caching of nested dependencies
- Schema Optimization: Efficient dependency graph representation
Security Overrides (Security overrides)
- Security Dependencies: OAuth2, JWT, and other authentication schemes
- Security Scopes: Scope-based access control
- Override Support: Test-friendly replacement of security dependencies
// Security dependency with scopes
Usage Examples
Basic Usage with Depends<T>
use ;
use Arc;
async
Basic Usage with Injected<T>
use ;
use Arc;
async
Custom Injectable Implementation
use ;
Nested Dependencies
Dependency Overrides for Testing
Cache Control
// Cache enabled (default) - Returns the same instance
let config1 = new.resolve.await?;
let config2 = new.resolve.await?;
// config1 and config2 are the same instance
// Cache disabled - Creates new instance each time
let config3 = no_cache.resolve.await?;
let config4 = no_cache.resolve.await?;
// config3 and config4 are different instances
Architecture
Type-Based Caching
Dependency caching is managed using type (TypeId) as the key. This allows dependencies of the same type to be automatically cached.
Scope Hierarchy
SingletonScope (Application level)
↓ Shared
InjectionContext (Request level)
↓ Holds
RequestScope (In-request cache)
Thread Safety
- All scopes are thread-safe using
Arc<RwLock<HashMap>> Injectabletrait requiresSend + Sync- Safe to use in async code
Testing Support
The testing framework includes a comprehensive test suite:
- Unit Tests: Unit tests for each component
- Integration Tests: Integration tests ported from FastAPI test cases
- Feature Tests:
- Automatic Injectable implementation tests
- Circular dependency detection tests
- Cache behavior tests
- Dependency override tests
- Nested dependency tests
Performance Considerations
- Lazy Initialization: Dependencies are not generated until needed
- Cache Efficiency: Same dependency is generated only once within request scope
- Zero-Cost Abstractions: Low-overhead design leveraging Rust's type system
- Arc-based Sharing: Efficient instance sharing using
Arc
Comparison with FastAPI
| Feature | FastAPI (Python) | reinhardt-di (Rust) |
|---|---|---|
| Basic DI | ✓ | ✓ |
| Request Scope | ✓ | ✓ |
| Singleton Scope | ✓ | ✓ |
| Dependency Caching | ✓ | ✓ |
| Nested Dependencies | ✓ | ✓ |
| Dependency Overrides | ✓ | ✓ |
yield Pattern |
✓ | ✓ |
| Type Safety | Runtime | Compile-time |
| Performance | Dynamic | Static & Fast |
macros
The macros module provides procedural macros for simplified dependency injection setup.
Features
Implemented ✓
#[injectable] - Struct Injection Registration
Mark a struct as injectable and automatically register it with the global registry.
Syntax:
Attributes:
`#[scope(singleton)]`- Singleton scope (default)`#[scope(request)]`- Request scope`#[scope(transient)]`- Transient scope (new instance every time)`#[no_inject]`- Exclude specific fields from automatic injection
Example:
use injectable;
#[injectable_factory] - Async Function Factory
Mark an async function as a dependency factory for complex initialization logic.
Syntax:
async
Attributes:
`#[scope(singleton)]`- Singleton scope (default)`#[scope(request)]`- Request scope`#[scope(transient)]`- Transient scope`#[inject]`- Mark function parameters for automatic injection
Example:
use injectable_factory;
use Arc;
async
Benefits of Using Macros
- Reduced Boilerplate: Automatically implements
`Injectable`trait - Scope Management: Declarative scope configuration
- Type Safety: Compile-time verification of dependencies
- Automatic Registration: Global registry integration without manual setup
- Async Support: Native async/await support in factory functions
Usage Patterns
Simple Struct Injection
use ;
use Arc;
async
Factory with Nested Dependencies
use ;
use Arc;
async
params
Features
Implemented ✓
Core Extraction System
FromRequesttrait: Core abstraction for asynchronous parameter extractionParamContext: Management of path parameters and header/cookie names- Type-safe parameter extraction: Extraction from requests with compile-time type checking
- Error handling: Detailed error messages via
ParamError
Path Parameters (path.rs)
Path<T>: Extract single value from URL path- Support for all primitive types:
i8,i16,i32,i64,i128,u8,u16,u32,u64,u128,f32,f64,bool,String - Transparent access via
Deref:*pathorpath.0 - Value extraction via
into_inner()method
- Support for all primitive types:
PathStruct<T>: Extract multiple path parameters into struct- Supports any struct implementing
DeserializeOwned - Automatic type conversion using URL-encoded format (
"42"→42)
- Supports any struct implementing
Query Parameters (query.rs)
Query<T>: Extract parameters from URL query string- Flexible deserialization using
serde - Support for optional fields (
Option<T>)
- Flexible deserialization using
- Multi-value query parameters (
multi-value-arraysfeature):?q=5&q=6→Vec<i32>- Automatic type conversion: string → numeric, boolean, etc.
- JSON value-based deserialization
Headers (header.rs, header_named.rs)
Header<T>: Extract value from request headers- Support for
StringandOption<String> - Runtime header name specification via
ParamContext
- Support for
HeaderStruct<T>: Extract multiple headers into struct- Header name lowercase normalization
- Automatic type conversion using URL-encoded
HeaderNamed<N, T>: Compile-time header name specification- Type-safe header names via marker types:
Authorization,ContentType - Support for
StringandOption<String> - Custom header name definition via
HeaderNametrait
- Type-safe header names via marker types:
Cookies (cookie.rs, cookie_named.rs)
Cookie<T>: Extract value from cookies- Support for
StringandOption<String> - Runtime cookie name specification via
ParamContext
- Support for
CookieStruct<T>: Extract multiple cookies into struct- RFC 6265-compliant cookie parsing
- URL-decoding support
CookieNamed<N, T>: Compile-time cookie name specification- Type-safe cookie names via marker types:
SessionId,CsrfToken - Support for
StringandOption<String> - Custom cookie name definition via
CookieNametrait
- Type-safe cookie names via marker types:
Body Extraction (body.rs, json.rs, form.rs)
Body: Extract raw request body as bytesJson<T>: JSON body deserialization- Type-safe deserialization using
serde_json - Access via
Derefandinto_inner()
- Type-safe deserialization using
Form<T>: Extract application/x-www-form-urlencoded form data- Content-Type validation
- Deserialization using
serde_urlencoded
Multipart Support (multipart.rs, requires multipart feature)
Multipart: Multipart/form-data support- Streaming parsing using
multercrate - File upload support
- Iteration via
next_field()
- Streaming parsing using
Validation Support (validation.rs, requires validation feature)
Validated<T, V>: Validated parameter wrapperWithValidationtrait: Fluent API for validation constraints- Length constraints:
min_length(),max_length() - Numeric ranges:
min_value(),max_value() - Pattern matching:
regex() - Format validation:
email(),url()
- Length constraints:
ValidationConstraints<T>: Chainable validation buildervalidate_string(): String value validationvalidate_number(): Numeric validation- Support for combining multiple constraints
- Type aliases:
ValidatedPath<T>,ValidatedQuery<T>,ValidatedForm<T> - Integration with
reinhardt-validators
License
Licensed under the BSD 3-Clause License.