-
-
Notifications
You must be signed in to change notification settings - Fork 8.8k
Closed
Labels
Description
Description
Consider the following code:
from fastapi import FastAPI, APIRouter
app = FastAPI() # pylint: disable=invalid-name
user_router = APIRouter() # pylint: disable=invalid-name
item_router = APIRouter() # pylint: disable=invalid-name
@user_router.get("/")
def get_users():
return [{"user_id": "u1"}, {"user_id": "u2"}]
@user_router.get("/{user_id}")
def get_user(user_id):
return {"user_id": user_id}
@item_router.get("/")
def get_items(user_id):
return [{"item_id": "i1"}, {"item_id": "i2"}]
@item_router.get("/{item_id}")
def get_item(item_id, user_id):
return {"item": item_id}
app.include_router(user_router, prefix="/users")
app.include_router(item_router, prefix="/items")
app.include_router(item_router, prefix="/users/{user_id}/items")This creates the following routes:
- /users
- /users/{user_id}
- /items
- required query parameters: user_id
- /items/{item_id}
- required query parameters: user_id
- /users/{user_id}/items
- /users/{user_id}/items/{itemid}
whereas what I'd like is:
- /users
- /users/{user_id}
- /items
- optional query parameters: user_id
- /items/{item_id}
- optional query parameters: user_id
- /users/{user_id}/items
- /users/{user_id}/items/{itemid}
The obvious thing to do is this:
@item_router.get("/")
def get_items(user_id: str = None):
return [{"item_id": "i1"}, {"item_id": "i2"}]
@item_router.get("/{item_id}")
def get_item(item_id, user_id: str = None):
return {"item": item_id}But of course, that will break the route /users/{user_id}/items/{itemid}:
Traceback (most recent call last):
File "/usr/local/Cellar/python/3.7.4/Frameworks/Python.framework/Versions/3.7/lib/python3.7/multiprocessing/process.py", line 297, in _bootstrap
self.run()
File "/usr/local/Cellar/python/3.7.4/Frameworks/Python.framework/Versions/3.7/lib/python3.7/multiprocessing/process.py", line 99, in run
self._target(*self._args, **self._kwargs)
File "/Users/PLL740/.virtualenvs/hatch-api/lib/python3.7/site-packages/uvicorn/supervisors/statreload.py", line 28, in handle_fds
target(**kwargs)
File "/Users/PLL740/.virtualenvs/hatch-api/lib/python3.7/site-packages/uvicorn/main.py", line 307, in run
loop.run_until_complete(self.serve(sockets=sockets))
File "uvloop/loop.pyx", line 1451, in uvloop.loop.Loop.run_until_complete
File "/Users/PLL740/.virtualenvs/hatch-api/lib/python3.7/site-packages/uvicorn/main.py", line 314, in serve
config.load()
File "/Users/PLL740/.virtualenvs/hatch-api/lib/python3.7/site-packages/uvicorn/config.py", line 186, in load
self.loaded_app = import_from_string(self.app)
File "/Users/PLL740/.virtualenvs/hatch-api/lib/python3.7/site-packages/uvicorn/importer.py", line 20, in import_from_string
module = importlib.import_module(module_str)
File "/Users/PLL740/.virtualenvs/hatch-api/lib/python3.7/importlib/__init__.py", line 127, in import_module
return _bootstrap._gcd_import(name[level:], package, level)
File "<frozen importlib._bootstrap>", line 1006, in _gcd_import
File "<frozen importlib._bootstrap>", line 983, in _find_and_load
File "<frozen importlib._bootstrap>", line 967, in _find_and_load_unlocked
File "<frozen importlib._bootstrap>", line 677, in _load_unlocked
File "<frozen importlib._bootstrap_external>", line 728, in exec_module
File "<frozen importlib._bootstrap>", line 219, in _call_with_frames_removed
File "./hatch_api/test.py", line 34, in <module>
app.include_router(item_router, prefix="/users/{user_id}/items")
File "/Users/PLL740/.virtualenvs/hatch-api/lib/python3.7/site-packages/fastapi/applications.py", line 248, in include_router
responses=responses or {},
File "/Users/PLL740/.virtualenvs/hatch-api/lib/python3.7/site-packages/fastapi/routing.py", line 477, in include_router
name=route.name,
File "/Users/PLL740/.virtualenvs/hatch-api/lib/python3.7/site-packages/fastapi/routing.py", line 370, in add_api_route
dependency_overrides_provider=self.dependency_overrides_provider,
File "/Users/PLL740/.virtualenvs/hatch-api/lib/python3.7/site-packages/fastapi/routing.py", line 288, in __init__
self.dependant = get_dependant(path=self.path_format, call=self.endpoint)
File "/Users/PLL740/.virtualenvs/hatch-api/lib/python3.7/site-packages/fastapi/dependencies/utils.py", line 188, in get_dependant
), "Path params must have no defaults or use Path(...)"
AssertionError: Path params must have no defaults or use Path(...)
INFO: Stopping reloader process [37825]
Describe the solution you'd like
It would be nice if the semantics of route functions like
@router.restverb(...)
def router_fn(param: type = None)
could be enhanced such that the default value is disregarded if the param appears in the fully resolved path.
In other words, the semantics of (param: type = None) would become "this parameter should be optional anywhere it's not a path variable".
Describe alternatives you've considered
The current solution would be to just define the different functions by hand.
Additional context
None
Reactions are currently unavailable