FastAPI
Engin ships with a FastAPI integration that is available under the engin.extensions.fastapi
module. The integration allows one to write idiomatic FastAPI code whilst leveraging Engin
for Dependency Injection and modularising the application.
Note
There is also a fastapi example in the Github repo if you want to see it in action.
Setup
To run an empty FastAPI server with Engin, simply use the FastAPIEngin class and
provide an instance of a FastAPI application:
from engin import Supply
from engin.extensions.fastapi import FastAPIEngin
from fastapi import FastAPI
import uvicorn
app = FastAPIEngin(Supply(FastAPI()))
if __name__ == "__main__":
uvicorn.run(app)
The FastAPIEngin instance is just a thin wrapper on top of the FastAPI application and
exposes the normal ASGI application interface and therefore can be run by uvicorn or
other server implementations. Under the hood it will just pass calls to the FastAPI
instance that you provided.
Tip
It is also easy to integrate Engin with an existing FastAPI application by using the
engin_to_lifespan function in the engin.extensions.asgi module.
Dependency Injection
FastAPI comes with its own simple dependency injection system which allows you inject
depenendencies into a route by declaring a parameter with a special type hint of the form
Annotated[T, Depends(func)]. For example if we wanted to inject an instance of
SomeClass:
async def make_some_class():
return SomeClass(a=1, b=2)
@app.get("/")
async def read_items(some_class: Annotated[SomeClass, Depends(make_some_class)]):
# do something with some_class
return "hello"
Engin ships with a similar marker, called Inject, which can be used to inject
dependencies it has providers for, for example if Engin provided SomeClass instead:
@app.get("/")
async def read_items(some_class: Annotated[SomeClass, Inject(SomeClass)]):
# do something with some_class
return "hello"
The Inject marker can be used anywhere that Depends can be used. This can be useful as
FastAPI dependencies can have per request lifecycle, for example if we wanted to have a
reusable SQL session per request, we could use a nested dependency:
from typing import Annotated, AsyncIterable
from engin.extensions.fastapi import Inject
async def database_session(
database: Annotated[Database, Inject(Database)]
) -> AsyncIterable[Session]:
with database.new_session() as session:
yield session
session.commit()
@app.post("/{id}")
async def add_item(session: Annotated[Session, Depends(database_session)]):
session.add(MyORMModel(...))
Attaching Routers to Engin
The idiomatic way to declare an APIRouter is as a module level variable, for example:
from fastapi import APIRouter
users_router = APIRouter(prefix="/users")
@users_router.get("/{user_id}")
def get_user(user_id: int) -> dict[str, Any]:
return {"id": user_id, "name": "Rakim"}
To attach this to our FastAPIEngin, we need to provide it. The recommended way to do
this is to use Supply as the router is already instantiated. We also need to add the
APIRouter to our FastAPI application, we can do this in the provider for FastAPI.
from engin.extensions.fastapi import FastAPIEngin
from fastapi import FastAPI
from api import users_router
def create_fastapi_app(api_routers: list[APIRouter]) -> FastAPI:
app = FastAPI()
for api_router in api_routers:
app.include_router(api_router)
return app
app = FastAPIEngin(Provide(create_fastapi_app), Supply([users_router]))
Info
Notice that the users_router is supplied in a list, as we want to be able to
support multiple APIRouters as our application grows.
Or similarly, we could use a block instead:
from engin import Block, provide
from engin.extensions.fastapi import FastAPIEngin
from fastapi import FastAPI
from api import users_router
class AppBlock(Block):
options = [Supply([users_router])]
@provide
def create_fastapi_app(self, api_routers: list[APIRouter]) -> FastAPI:
app = FastAPI()
for api_router in api_routers:
app.include_router(api_router)
return app
app = FastAPIEngin(AppBlock())
Graphing Dependencies
Engin provides dependency visualisation functionality via the engin graph script. When
working with a FastAPI application this can be used to visualise API Routes along with
their respective dependencies.

Visualisation of the FastAPI example's dependency graph.
Note that due to the split between Engin's dependency injection framework and FastAPI's,
resolving API Routers and their dependencies is slightly harder for Engin. Due to this
there is currently a limitation where Engin will only be aware of APIRouters that have
been provided using Supply and not via Provide or @provide in a Block.