Utilities for FastAPI
The Route Class​
A server built with FastAPI typically defines its functionality by:
- defining an
appinstance, potentially with a custom lifecycle - defining functions as HTTP endpoints attached to a router with the
@router.methoddecorator - Including routers in other routers, eventually in the app
- using
uvicorn(or equivalents) to start the app within__main__
streamlit-octostar-utils.api_crafter.fastapi extends point 2. and 3. by:
- Providing an abstract
Routeclass. Developers can inherit from this class inside which they can define one or more endpoints. This allows functions to be separated into their own classes thus keeping the main file clean - Extending the
@router.methoddecorator with the@Route.routedecorator, which takes as arguments aRouteinstance (typicallyself), a FastAPI routerrouter, plus the same arguments as the FastAPI decorator. This decorator allows dynamic binding of a function as a FastAPI route, where routes inside the sameRoutecan be directed to different FastAPI routers. This binding happens for all functions decorated with the@Route.routedecorator inside thedefine_routes()method, when theinclude_routes()method is called on theRouteinstance. This follows a syntax similar to FastAPI'srouter.include_router() - Providing an additional
@Route.include()decorator, which simply sets the underlying function as an attribute in the class instance. This effectively allows us to expose instance functions defined inside another function as class attributes
The structure of an endpoint is a class of type Route with a few different methods:
define_routes()is native to the Route class, and should be used to define one or more FastAPI routes (usually variants on the same computation) using the@Route.routedecorator. Routes defined here will be bound to the associated routers when callinginclude_routes().__init__()defines the base attributes for theRoute. Because of the new@Route.routedecorator, the endpoints can refer to self and therefore to any attributes defined in this constructor.
Thanks to this class we can do the following: instantiate an app plus one or more routers, instantiate one Route, call include_routes() on the route instance to bind its endpoints to the router(s), call include_router() on the app to include the routers into the whole app.