You will build a two-endpoint API and see dependency injection resolve a provider without registering it anywhere.
You need Python 3.12+ and Bustan 0.0.1.
Install#
pip install bustan==0.0.1
A provider#
Providers hold behaviour. Mark one injectable:
# app/tasks/service.py
from bustan import Injectable
@Injectable()
class TaskService:
def __init__(self) -> None:
self._tasks: dict[int, str] = {}
self._next_id = 1
def add(self, title: str) -> int:
task_id = self._next_id
self._tasks[task_id] = title
self._next_id += 1
return task_id
def all(self) -> dict[int, str]:
return dict(self._tasks)
A controller#
Controllers translate HTTP to calls on providers, and should contain almost no logic:
# app/tasks/controller.py
from bustan import Controller, Get, Post, Body
from .service import TaskService
@Controller("/tasks")
class TaskController:
def __init__(self, tasks: TaskService) -> None:
self.tasks = tasks
@Get("/")
async def list_tasks(self) -> dict[int, str]:
return self.tasks.all()
@Post("/")
async def create(self, title: str = Body()) -> dict[str, int]:
return {"id": self.tasks.add(title)}
TaskService arrives because the constructor annotation asks for it.
A module#
A module declares what it owns:
# app/tasks/module.py
from bustan import Module
from .controller import TaskController
from .service import TaskService
@Module(controllers=[TaskController], providers=[TaskService])
class TaskModule:
pass
And the root module composes them:
# app/main.py
from bustan import Module, Bustan
from .tasks.module import TaskModule
@Module(imports=[TaskModule])
class AppModule:
pass
app = Bustan(AppModule)
Run it#
uvicorn app.main:app --reload
$ curl -s localhost:8000/tasks/
{}
$ curl -s -X POST localhost:8000/tasks/ -d '{"title":"write docs"}' -H 'content-type: application/json'
{"id":1}
What you have#
- A provider the container constructs once and shares
- A controller that never constructs its own dependencies
- A module boundary you can move without touching either
Next#
- Share a provider between modules — see the how-to guides
- Understand how the container resolves things — see Explanation