Skip to content

Endpoints

Maybe you are looking for…

To encapsulate endpoints completely in a single api.py file (see file naming conventions) we use a singleton router registry. You can import this registry like this:

from server.router_registry import registry

Each api.py file must declare its own FastAPI router and bind itself with the registry:

api.py
from fastapi import APIRouter
from server.router_registry import registry
router = APIRouter()
registry.register_router(router)
@router.get("/hello")
async def e_hello() -> str:
return {"message": "Hello, World!"}

In this way, we remove the direct dependency between the router and the FastAPI app. This allows us to dynamically discover routers, eliminating the need to manually bind them to the app.

Given that we have unique routers per api.py file, we follow a simple convention to avoid clashes between routes:

For example, in this api.py file:

  • Directorypresentation/
    • Directorygeneration/
      • api.py

We would declare and bind the router as follows:

api.py
from fastapi import APIRouter
from server.router_registry import registry
router = APIRouter(prefix="/presentation/generation")
registry.register_router(router)

Endpoints should be thin wrappers of business logic. Apart from input validation, they should not implement any meaningful code. Instead, we import functionality from other modules.

For example, this endpoint is not ideal.

api.py
@router.post("/add-numbers")
async def e_add_numbers(a: int, b: int) -> int:
return a + b

Instead, we should import the functionality from a module:

api.py
from modules.math import add_numbers
@router.post("/add-numbers")
async def e_add_numbers(a: int, b: int) -> int:
return add_numbers(a, b)

This way, we can change the implementation of the functionality without touching the endpoint. And, should we ever need the add_numbers function somewhere else, we can simply import it from the module, without having to change the endpoint or duplicate the code.