Uri.setQueryParams() doesn't seem to overwrite existing params
invadergir opened this issue · comments
Hi, I was attempting to use Uri.setQueryParams() and noticed it doesn't behave according to the comments:
/** Creates maybe a new `Self` with the specified parameters. The entire
* [[Query]] will be replaced with the given one.
*/
This munit test passes on 0.23.19-RC3 and 0.23.4 (in a test project that imports http4s), and I would expect it to fail:
test("setQueryParams() will overwrite any existing query parameters if they exist") {
val uri = Uri.unsafeFromString("http://example.com/a/b/c?m=5&n=6")
val origQP = Map("m" -> Seq("5"), "n" -> Seq("6"))
assertEquals(uri.query.multiParams, origQP)
val uriSetQP = uri.setQueryParams(Map("X" -> Seq("10")))
val reallyExpected = Map("X" -> Seq("10")) // we only expect the new QPs to be set, the others lost
val expected = origQP ++ reallyExpected // this is what we actually get, see below:
assertEquals(uriSetQP.query.multiParams, expected )
}
Thanks! I guess the bug is here?
My humble opinion is that we better need to fix the scaladoc and add a new method rather than change the behaviour of that function.
Yeah, I wouldn't disagree. It looks like it's been working this way since v0.20.0. dd7e192
Just fyi: there's another method that modifies query parameters in Uri
: withQueryParams
:
scala> val uri = uri"https://typelevel.org?foo=123&bar=456"
val uri: org.http4s.Uri = https://typelevel.org?foo=123&bar=456
scala> uri.setQueryParams(Map("bar" -> Seq("789"), "car" -> Seq("abc")))
val res2: org.http4s.Uri = https://typelevel.org?foo=123&bar=456&bar=789&car=abc
scala> uri.withQueryParams(Map("bar" -> "789", "car" -> "abc"))
val res4: org.http4s.Uri = https://typelevel.org?foo=123&bar=789&car=abc
So neither of those two methods does replace query parameters completely.
It seems that the only way to get them replaced is uri.copy(query = ...)
, which may not be that bad but...
Now compare to a Request
's header methods:
withHeaders
– replaces all the headers in a request.putHeaders
– actually, just adds given headers to existing ones.addHeader
– does the same thing asputHeaders
but just for a single header.
So in my opinion, current naming conventions in the library are quite confusing and inconsistent.
withSomething
– may or may not replace everything;setSomething
– despite its name, may append stuff instead of replacing it;putSomething
,addSomething
– well, not always obvious from their names too.
Moreover, although the withSomething
version is quite ubiquitous, but it may have different behavior. Whereas other names like set
, put
, add
, etc may or may not exist in every particular model.
Perhaps, it would be nice if the naming consistency could be addressed in 1.x version at least, wdyt?