Merge params with existing URL query parameters instead of replacing them

When a URL already contains query parameters and the `params` argument is
also provided, the existing query parameters are now merged with the new
ones instead of being silently dropped. This aligns with the behavior of
the `requests` library and matches user expectations.

Fixes #3621
This commit is contained in:
Varun Chawla 2026-02-08 15:02:07 -08:00
parent ae1b9f6623
commit 38fe19f18f
2 changed files with 11 additions and 3 deletions

View File

@ -396,7 +396,7 @@ class Request:
extensions: RequestExtensions | None = None,
) -> None:
self.method = method.upper()
self.url = URL(url) if params is None else URL(url, params=params)
self.url = URL(url) if params is None else URL(url).copy_merge_params(params)
self.headers = Headers(headers)
self.extensions = {} if extensions is None else dict(extensions)

View File

@ -232,10 +232,18 @@ def test_request_params():
request = httpx.Request("GET", "http://example.com", params={})
assert str(request.url) == "http://example.com"
# Params are merged with existing URL query parameters, not replaced.
request = httpx.Request(
"GET", "http://example.com?c=3", params={"a": "1", "b": "2"}
)
assert str(request.url) == "http://example.com?a=1&b=2"
assert str(request.url) == "http://example.com?c=3&a=1&b=2"
# Empty params preserves existing URL query parameters.
request = httpx.Request("GET", "http://example.com?a=1", params={})
assert str(request.url) == "http://example.com"
assert str(request.url) == "http://example.com?a=1"
# Params with overlapping keys override existing URL query parameters.
request = httpx.Request(
"GET", "http://example.com?a=1&b=2", params={"b": "3", "c": "4"}
)
assert str(request.url) == "http://example.com?a=1&b=3&c=4"