How can I make empty query parameters to be interpreted as missing value (and therefore default value is used) instead of empty string? For example, if I were to use optional int query param, empty string would find its way as value being passed and validation error for invalid int would be raised.
Sample code:
from fastapi import APIRouter
router = APIRouter()
@router.get("/test/", tags=["test"])
def test(q: int = None):
return {"q": q}
or
results in:
{
"detail": [
{
"loc": [
"query",
"q"
],
"msg": "value is not a valid integer",
"type": "type_error.integer"
}
]
}
Interesting, I can reproduce this with the latest fastapi, but not with fastapi~=0.49.0.
@phy25 I think it is somehow connected with this PR and therefore with versions of Starlette
same question here, any updates on this?:)
Hmm, yeah, it probably has to do with https://github.com/encode/starlette/pull/672.
~I think this would be a request for Starlette. To parse ?q and ?q= as q = None instead of q = "".~
~Do you wanna request it there?~
I'm seeing in Starlette that this is handled by Python's standard urlib.parse: https://docs.python.org/3/library/urllib.parse.html#urllib.parse.parse_qsl
And I'm actually not sure that reading that as None would be the correct behavior, as the URL is actually all a string.
It would make sense that something not provided would be None, and/or take its default value, but some query parameter that is passed in the URL, but without value, would kinda technically be an empty string.
I could think that not passing the parameter at all could make it have a default value, but passing the query parameter would set some value... The thing is that as URLs are strings, there's no simple notion of a None type.
I'm not really sure how to approach it here because I'm not totally convinced about any of the 2 approaches, but I think I'm inclined to think this "was kind of a bug" that is now "sort of fixed" :thinking:
@tiangolo thanks for the reply!
Actually, I'm not sure which approach is better either, but I think that there should be a way to handle this in both use-cases. Since use-case "empty query parameter (?q or ?q=) has value of empty string" is the default one, I am curios about how to achieve "empty query parameter (?q or ?q=) is missing (e.g. None & default value is used)"?
Appreciate your help, thanks!
@tiangolo thanks for the reply!
Actually, I'm not sure which approach is better either, but I think that there should be a way to handle this in both use-cases. Since use-case "empty query parameter (?q or ?q=) has value of empty string" is the default one, I am curios about how to achieve "empty query parameter (?q or ?q=) is missing (e.g. None & default value is used)"?
Appreciate your help, thanks!
Same requirements here, and handled with a middleware at last.
We can just drop those fields with blank values, which are empty strings or strings contain only whitespaces, default values will be handled by Query models.
# Add blank query parameters processing middleware
@app.middleware('http')
async def drop_blank_query_params_middleware(request: Request, call_next):
_scope = request.scope
if request.method != 'GET':
return await call_next(request)
if not _scope or not _scope.get('query_string'):
return await call_next(request)
def _process_query_params(query_params):
_query_params = QueryParams(query_params)
from urllib.parse import urlencode
return urlencode([
# using `_query_params.items()` will mistakenly process list parameters
(k, v) for k, v in _query_params._list if v and v.strip() # noqa
])
_scope['query_string'] = _process_query_params(_scope['query_string']).encode('latin-1')
return await call_next(Request(_scope, request.receive, request._send)) # noqa
However, as @tiangolo commented, this approach may not be correct, maybe it's not recommended. :)
Assuming the original issue was solved, it will be automatically closed now. But feel free to add more comments or create new issues.
Most helpful comment
Same requirements here, and handled with a middleware at last.
We can just drop those fields with blank values, which are empty strings or strings contain only whitespaces, default values will be handled by
Querymodels.However, as @tiangolo commented, this approach may not be correct, maybe it's not recommended. :)