[Feature Request]: Support using __call__ in add_api_route endpoint parameter
#10238
-
First Check
Commit to Help
Example Codeimport pathlib
from fastapi import FastAPI
import pydantic
import uvicorn
class Hello:
class Request(pydantic.BaseModel):
id: str
class Response(pydantic.BaseModel):
hello: str
def __init__(self, name: str) -> None:
self.name = name
async def __call__(self, request: Request) -> Response:
return self.Response(hello=f"{request.id} {self.name}")
app = FastAPI()
handler = Hello(name="test")
app.add_api_route("/hello", handler, methods=["POST"])
def run() -> None:
server_config = uvicorn.Config(
app=app,
host="localhost",
port=8080,
reload=True,
reload_dirs=[str(pathlib.Path.cwd())],
reload_includes=["*"],
server_header=False,
proxy_headers=True,
)
server = uvicorn.Server(config=server_config)
server.run()
run()DescriptionThe code above does not work, it raises A simple workaround is to pass in the This might be related: Kludex/starlette#886 This isn't a huge deal and probably shouldn't spend time on it, given the workaround is very simple, unless the implementation is trivial Operating SystemmacOS Operating System DetailsNo response FastAPI Version0.103.1 Pydantic Version2.3.0 Python Version3.10.7 Additional ContextNo response |
Beta Was this translation helpful? Give feedback.
Replies: 3 comments 1 reply
-
|
I could reproduce your problem. After some investigation (and learning), I've found this is not a FastAPI problem, it is a problem with the definition of the caller method, it shouldn't be Please, try again changing to: class Hello:
class Request(pydantic.BaseModel):
id: str
class Response(pydantic.BaseModel):
hello: str
def __init__(self, name: str) -> None:
self.name = name
def __call__(self, request: Request) -> Response:
return self.Response(hello=f"{request.id} {self.name}") |
Beta Was this translation helpful? Give feedback.
-
|
I've realized that you might really need an asynchronous call, I couldn't find a straightforward solution, but this might solve your problem: import asyncio
from fastapi import FastAPI
import pydantic
class Hello:
class Request(pydantic.BaseModel):
id: str
class Response(pydantic.BaseModel):
hello: str
def __init__(self, name: str) -> None:
self.name = name
async def __call__(self, request: Request) -> Response:
await asyncio.sleep(1)
return self.Response(hello=f"{request.id} {self.name}")
async def handler(request: Hello.Request) -> Hello.Response:
_handler = Hello(name="test")
return await _handler(request)
app = FastAPI()
app.add_api_route("/hello", handler, methods=["POST"]) |
Beta Was this translation helpful? Give feedback.
-
|
Thanks for the interest! So, the way you are declaring your Pydantic models as class attributes inside of a class is not really supported in Pydantic nor FastAPI. It would probably be better to refactor that. Is there any reason why you need the code with that structure? |
Beta Was this translation helpful? Give feedback.
Thanks for the interest! So, the way you are declaring your Pydantic models as class attributes inside of a class is not really supported in Pydantic nor FastAPI. It would probably be better to refactor that.
Is there any reason why you need the code with that structure?