FastIoC
IoC/DI container for FastAPI with automatic type-based dependency injection
Why FastIoC π€
FastIoC bridges the gap between Pythonβs dynamic nature and modern dependency injection patterns found in frameworks like .NET, Laravel, Spring Boot, and NestJS β with zero boilerplate and full FastAPI compatibility.
Features:
-
π§Ή Write cleaner, loosely coupled code while staying true to the βοΈβπ₯ Dependency Inversion Principle (SOLID - D) β with ABSOLUTELY ZERO boilerplate! β‘
-
βοΈ Enjoy hassle-free, automatic nested dependency resolution using Python type hints with flexible lifetimes: β»οΈ Singleton, π§Ί Scoped, and β¨οΈ Transient (inspired by .NET)
-
π Zero runtime overhead β everything is resolved at startup!
-
π€ 100% compatible & based on FastAPIβs native dependency injection β no black boxes, no magic πͺ
-
β»οΈ Singleton support with automatic cleanup on application shutdown π§Ή
-
π§ͺ Full support for FastAPI's
dependency_overrides
using type annotations β even with mock containers π -
π¦ Comes with the amazing
APIController
β the best class-based view (CBV) system ever seen in Python π -
π Two operation modes: standalone ποΈ and integrated π§©
-
π§ Comes with customizable hooks, detailed logs & ... π
Installation π₯
$ pip install fastioc
Usage π‘
A sample interface & implementation:
from typing import Protocol
# Define the interface π
class IService(Protocol):
def get_number(self) -> int: ...
# Implement concrete class ποΈ
class ExampleService(IService):
def __init__(self):
print("ExampleService created")
self.number = 42
def get_number(self) -> int:
return self.number
Standalone Mode ποΈ
from fastapi import FastAPI
from fastioc import Container # Import the Container
# Create container and register dependency π
container = Container()
container.add_scoped(IService, ExampleService) # Also available: add_singleton, add_transient
# Create FastAPI app and integrate it with the container πͺ
app = FastAPI()
container.injectify(app)
# Now your endpoints are injectified! π
@app.get('/')
def index(service: IService) -> int: # Only use the interface - no 'Depends' needed
return service.get_number() # 42 π€©
APIController π¦
from fastapi import FastAPI
from fastioc import Container
from fastioc.controller import APIController, get, post
# Create container & register dependencies π
container = Container()
container.add_scoped(IService, ExampleService)
# Define an example controller
class ExampleController(APIController):
config = { # APIRouter parameters (+ IDE Autocomplete π€©)
"prefix": '/example',
"tag": 'example',
"container": container # ! DO NOT FORGET
}
service: IService # Available in all endpoints!
@get('/read')
def read_example(self) -> int:
return self.service.get_number()
@post('/set')
def set_example(self) -> bool:
self.service.number = 24
return True
app = FastAPI()
app.include_router(ExampleController.router()) # Get router from controller and include it
- APIController endpoints are injectified so you can also resolve dependencies in each endpoint separately.
- You can also resolve dependencies in
__init__
of your controller. - Read more in the APIController documentation
Learn More π
Check out the π full documentation for advanced examples, architecture guides, best practices, and more.
Contributing π¬
Got an idea, found a bug, or want to improve FastIoC?
Feel free to open an issue or submit a pull request β contributions are always welcome π€
License βοΈ
This project is licensed under the MIT License β see the LICENSE file for details.