Unfortunately, all the packages wrapping FastAPI in classes, like fastapi-utils and fastapi-class seem to be deprecated, so I would suggest using FastAPI directly.
The underlying problem is, that FastAPI uses decorators like @app.get(...), which don't work well in classes.
Inheritance
So based on Kostiantyn's answer, I have written a little example using FastAPI as base class:
from typing import Any
import uvicorn
from fastapi import FastAPI
from starlette.responses import HTMLResponse, JSONResponse
class App(FastAPI):
def __init__(self, **extra: Any):
super().__init__(**extra)
self.add_api_route("/", self.get_root, methods=["GET"], include_in_schema=False)
self.add_api_route("/version", self.get_version, methods=["GET"])
@staticmethod
async def get_root() -> HTMLResponse:
return HTMLResponse('<meta http-equiv="Refresh" content="0; url=\'/docs\'" />')
async def get_version(self) -> JSONResponse:
return JSONResponse({"FastAPI version": self.version})
if __name__ == "__main__":
url = "https://stackoverflow.com/q/65446591/5538913"
app = App(
title="FastAPI from class",
description=f"Source: <a href='{url}'>Stack Overflow</a>",
)
uvicorn.run(app, host="127.0.0.1", port=8000)
This way the App and its routes can be configured easily, you can even define websockets with self.add_api_websocket_route etc.
Composition
Another approach would be to define a serve method in your class and implement the endpoints there:
import asyncio
from typing import Optional
import uvicorn
from fastapi import FastAPI
from fastapi.responses import HTMLResponse, JSONResponse
class MyClass:
def __init__(self):
self.version = "0.0.1"
url = "https://stackoverflow.com/q/65446591/5538913"
self.app = FastAPI(
title="FastAPI from class",
description=f"Source: <a href='{url}'>Stack Overflow</a>",
)
self.serving_task: Optional[asyncio.Task] = None
async def serve(self):
app: FastAPI = self.app
@app.get("/", include_in_schema=False)
async def _get_root():
"""
Redirect to /docs
"""
return HTMLResponse('<meta http-equiv="Refresh" content="0; url=\'/docs\'" />')
@app.get("/version")
async def _get_version() -> JSONResponse:
return JSONResponse({"MyClass version": self.version, "FastAPI version": app.version})
# serve
config = uvicorn.Config(app, host="127.0.0.1", port=8000)
server = uvicorn.Server(config)
await server.serve()
if __name__ == "__main__":
instance = MyClass()
asyncio.run(instance.serve())