I am trying to setup a dependency that will accept a paramter from a Body or Query (it will be used as a dependency for POST and GET requests.
I need to be able to look for the env parameter in either the Body or Query. Something like this maybe:
def testFactory(env: str = Body(...) or Query(...)):
testDict = {
'testenv1' = TestObject1(),
'testenv2' = TestObject2()
}
return testDict.get(env)
I'm an amateur programmer, so please let me know if I'm just not doing it right!
This is my current workaround, but it feels like it could be better. Basically looking for this functionality in a single dependency function or class instead of 3
def testDict():
return {
'testenv1' = TestObject1,
'testenv2' = TestObject2
}
def qTestFactory(env: str = Query(...), testObject = Depends(testDict)):
return testObject.get(env)()
def bTestFactory(env: str = Body(...), testObject = Depends(testDict)):
return testObject.get(env)()
@taoofshawn here's an example of doing what I think you want to do:
from typing import Optional
import uvicorn
from fastapi import FastAPI, Depends, Query, Body, HTTPException
from starlette.status import HTTP_400_BAD_REQUEST
app = FastAPI()
def get_env(
query_env: Optional[str] = Query(None, alias="env"),
body_env: Optional[str] = Body(None, alias="env"),
) -> str:
if query_env is not None:
return query_env
if body_env is not None:
return body_env
raise HTTPException(
HTTP_400_BAD_REQUEST, detail="You must provide 'env' in body or query"
)
@app.get("/")
def test(env: str = Depends(get_env)):
return env
@app.post("/")
def test(env: str = Depends(get_env)):
return env
if __name__ == "__main__":
uvicorn.run(app)
However, I strongly recommend that you do not take this approach. There are a few problems here:
I recommend that you either just put this option in query (which you can do for both POST and GET) or have two different dependencies and select one per endpoint. Something like this:
import uvicorn
from fastapi import FastAPI, Depends, Query, Body
app = FastAPI()
def query_env(env: str = Query(...)) -> str:
return env
def body_env(env: str = Body(...)) -> str:
return env
@app.get("/")
def test(env: str = Depends(query_env)):
return env
@app.post("/")
def test(env: str = Depends(body_env)):
return env
if __name__ == "__main__":
uvicorn.run(app)
At that point it's less code to just include the params directly in your route rather than use a dependency. I am assuming you need a dependency so you can do something else with the env.
You're right, I think it would be better to keep "env" as a query parameter for all requests and just also accept a body for the other params for posts. I think it got (incorrectly) burned into my head somewhere to always use query for gets and form or body for posts.
thanks @dbanty !
Thanks for the help here @dbanty ! :bow:
Thanks for reporting back and closing the issue @taoofshawn :+1:
It would be convenient if fastapi did support this type of usage without having to create two separate duplicate path operators (just decorated differently). Something equivalent to "get_arguments" in tornado. Nevertheless, it's helpful to hear that the best approach currently is to define two separate path operators.
Maybe one could make a single pydantic class to represent the common input args and somehow reuse it for GET and POST's?
EDIT: okay maybe not a pydantic class, but maybe a dataclass which is a dependency?
@falkben if you are needing to put that in many places, yeah, you could just create a class dependency to get and store the alternative parameters.