Is it possible to call another route by using all usual FastAPI functionality?
Example:
@router.get("/something")
async def get_something(
something_id: int = Query(
1,
description="Some description"
),
full: bool = Query(
False,
description="Some description"
)
):
# ... do some database queries or whatever
return {"something_id": something_id, "full": full}
@router.get("/two_somethings")
async def get_two_somethings(
something_id_1: int = Query(
1,
description="Some description"
),
something_id_2: int = Query(
2,
description="Some description"
),
):
one = await get_something(something_id_1)
two = await get_something(something_id_2)
return {"one": one, "two": two}
If I query /something?something_id=1234, the boolean full is properly filled. If I call /two_somethings?something_id_1=1234$something_id_2=2345, the full argument in the function get_something is not resolved and has its unprocessed default value of a Query object.
If requesting above /two_somethings, the print would say
{'something_id': 1, 'full': Query(default=False, description='Some description', extra={})}
This is a constructed problem, but I stumbled upon it and wondered. A solution is certainly to create a separate non-route function that does the business logic of get_something and call that one in get_two_somethings, but then I lose the nice input and output checking of the individual get_something calls. Is there a solution?
You can call the route functions directly, but if you do so, you lose the dependency injection. In particular, if the functions have default values of a type like Query(...) or Depends(dependency_func), you have to provide values, as the "defaults" are not actually valid, and are not substituted based on the request unless called by FastAPI.
As you noted, the easiest way to accomplish this might be to separate the shared business logic into a reusable function.
There are other patterns you could use, such as a class-based dependency, that might enable you to refactor the code in a way you find more reusable, but it would probably require a larger refactor than would be ideal. But right now I'm not sure there is currently a good way to accomplish the pattern you would like to use here directly.
(It's not an unreasonable request, but I'm not sure how much complexity would need to be added to the dependency injection logic to make it possible. My guess is it would be more than it's probably worth, sadly.)
Ok thank you for clarification, that is what I suspected.
Thanks for the help here @dmontagu ! :cake: :bowing_man:
Thanks @sschiessl-bcp for reporting back and closing the issue :+1: