Skip to content

FastIoC

IoC/DI container for FastAPI with automatic type-based dependency injection

PyPI - Version Documentation License: MIT Support


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.