The API should serve an endpoint where a user can either provide a guid
, a path
or a code
. This is what the url scheme should look like:
api/locations?code={str}&guid={str}&path={str}
The current code is as follows:
@router.get("/api/locations")
def get_functional_locations(
guid: Optional[str] = None,
code: Optional[str] = None,
path: Optional[str] = None,
) -> Union[List[Locations], PlainTextResponse]:
if guid:
return ...
if path:
return ...
if code:
return ...
return PlainTextResponse(status_code=status.HTTP_400_BAD_REQUEST)
Is there another way to provide this multiple optional parameters and have an XOR that only allows the user to fill in exactly one parameter?
Firstly, I would ask, if you have three parameters that are mutually exclusive and all are ways to get the same information, shouldn't that be three different endpoints, e.g. api/locations/guid/{guid}
, api/locations/code/{code}
and api/locations/path/{path}
? It's usually preferable to have several smaller functions that do one thing.
If you however do want this, you can always write your own code for it, e.g. using a class as a dependency, here together with a pydantic root validator
from fastapi import Depends, HttpException
from pydantic import BaseModel, root_validator
class Params(BaseModel):
guid: str | None = None
code: str | None = None
path: str | None = None
@root_validator
def validate(cls, values):
if len([val for val in values.values() if val is not None]) != 1:
raise HTTPException(400, "Exactly one of guid, code, and path must be provided")
return values
@app.get("/api/locations")
def foo(params: Params = Depends()):
...