Conversion Rules¶
This converter applies only source-grounded mappings found in local FastAPI/Lilya/Sayer repositories.
Rule Categories¶
Import and Constructor Rules¶
- FastAPI app/router imports map to Lilya app/router imports.
- Response/middleware import modules are mapped only when Lilya has direct equivalents.
- Unsupported constructor kwargs are removed and reported.
Routing Rules¶
include_router(...)becomesinclude(path=..., app=...).api_route(...)becomesroute(..., methods=[...]).trace(...)becomesroute(..., methods=["TRACE"]).- Router
prefix=is extracted and merged into route paths where deterministic.
Dependency Rules¶
- Signature defaults
Depends(dep)becomeProvide(dep)route dependencies +Provides()defaults. Annotated[..., Depends(dep)]metadata is normalized to Lilya dependency maps.- Decorator/constructor dependency lists are converted to dependency dictionaries.
Error and Middleware Rules¶
@app.exception_handler(ExceptionType)becomesapp.add_exception_handler(ExceptionType, handler).- FastAPI function middleware decorators are removed with explicit diagnostics.
- Class middleware imports/calls are preserved where direct Lilya mapping exists.
Complex Conversion Behaviors¶
Router Prefix Handling¶
FastAPI commonly combines router prefixes and include prefixes.
Converter behavior: - route paths receive extracted router prefixes, - include paths preserve explicit include prefixes, - dynamic combinations that cannot be resolved deterministically are reported.
Dependency Layering¶
Dependencies can exist simultaneously at: - app/router constructors, - include-router call sites, - route decorators, - route handler signatures.
Converter behavior: - merges dependency layers into Lilya route/include-compatible dependency dictionaries, - generates deterministic synthetic names where needed, - reports unsupported shapes.
Response Metadata Gaps¶
FastAPI metadata like response_model does not map 1:1 to Lilya route decorator arguments.
Converter behavior: - removes unsupported kwargs, - preserves executable handler code, - emits diagnostics for manual review.
Worked Dependency Example¶
FastAPI:
from typing import Annotated
from fastapi import Depends, FastAPI
def global_dep() -> str:
return "global"
app = FastAPI(dependencies=[Depends(global_dep)])
@app.get("/items")
async def items(
user: str = Depends(global_dep),
value: Annotated[int, Depends(global_dep)] = 1,
):
return {"user": user, "value": value}
Lilya:
from lilya.apps import Lilya as FastAPI
from lilya.dependencies import Provide, Provides
def global_dep() -> str:
return "global"
app = FastAPI(dependencies={"_global_dep": Provide(global_dep)})
@app.get(
"/items",
dependencies={"_global_dep": Provide(global_dep), "user": Provide(global_dep), "value": Provide(global_dep)},
)
async def items(user: str = Provides(), value: int = 1, *, _global_dep=Provides()):
return {"user": user, "value": value}
Worked Complex Example¶
FastAPI:
from typing import Annotated
from fastapi import APIRouter, Depends, FastAPI
def app_dep() -> str:
return "app"
def include_dep() -> str:
return "include"
def router_dep() -> str:
return "router"
def route_dep() -> str:
return "route"
app = FastAPI(openapi_url="/openapi.json", dependencies=[Depends(app_dep)])
router = APIRouter(prefix="/api", dependencies=[Depends(router_dep)], tags=["ignored"])
@router.api_route(
"/items/{item_id}",
methods=["GET", "POST"],
dependencies=[Depends(route_dep)],
response_model=dict,
)
async def item(
item_id: int,
token: Annotated[str, Depends(route_dep)],
extra: str = Depends(router_dep),
):
return {"id": item_id, "token": token, "extra": extra}
app.include_router(router, prefix="/v1", dependencies=[Depends(include_dep)], tags=["ignored"])
Lilya:
from lilya.apps import Lilya as FastAPI
from lilya.dependencies import Provide, Provides
from lilya.routing import Router as APIRouter
from typing import Annotated
def app_dep() -> str:
return "app"
def include_dep() -> str:
return "include"
def router_dep() -> str:
return "router"
def route_dep() -> str:
return "route"
app = FastAPI(dependencies={"_app_dep": Provide(app_dep)}, enable_openapi=True)
router = APIRouter()
@router.route(
"/api/items/{item_id}",
methods=["GET", "POST"],
dependencies={
"_route_dep": Provide(route_dep),
"_router_dep": Provide(router_dep),
"token": Provide(route_dep),
"extra": Provide(router_dep),
},
)
async def item(
item_id: int,
token: str,
extra: str = Provides(),
*,
_router_dep=Provides(),
_route_dep=Provides(),
):
return {"id": item_id, "token": token, "extra": extra}
app.include(path="/v1", app=router, dependencies={"_include_dep": Provide(include_dep)})
Operational Guidance¶
- Use
map rulesbefore conversion to inspect available mappings. - Use
map appliedafter conversion to audit which rules were triggered. - Treat diagnostics as required migration checklist items.