Allow setting query parameters more conveniently Artyom Bologov (01 Aug 2026 19:09 UTC)
Re: Allow setting query parameters more conveniently Peter Bex (03 Aug 2026 11:37 UTC)
Re: Allow setting query parameters more conveniently Peter Bex (03 Aug 2026 11:44 UTC)
Re: Allow setting query parameters more conveniently Peter Bex (03 Aug 2026 11:50 UTC)
Re: Allow setting query parameters more conveniently Peter Bex (03 Aug 2026 11:53 UTC)

Re: Allow setting query parameters more conveniently Peter Bex 03 Aug 2026 11:37 UTC

On Sat, Aug 01, 2026 at 11:08:46PM +0400, Artyom Bologov wrote:
> Hi y’all, hi Duncan,
>
> set-iri-query! and update-iri-query are nice, but they’ll benefit from a
> more useful syntax adding structured query parameters. Say, something
> like
>
> (set-iri-query-param! iri (param-name string) (param-value any))
> (update-iri-query-param iri (param-name string) (param-value any))
>
> What do you think?

Hi Artyom,

Oh man... Query arguments are a huge can of worms.  In essence, query
strings are supposed to be completely opaque to the RFC URI specs.

Now when you have a HTML form, browsers will encode the data using
x-www-form-urlencoded and either put it in the request body for POSTs,
or append it to the URL in the query string for GETs.

The HTML 4 specification contains some details on how to
handle data as application/x-www-form-urlencoded
(http://www.w3.org/TR/html401/interact/forms.html#h-17.13.4.1).
There's also the XHTML XForms' specification
(http://www.w3.org/TR/xforms/#serialize-urlencode)

The latter is a more generalised form of the former, as it allows
the user to specify a custom separator character.  The HTML 4
spec also contains a recommendation
(http://www.w3.org/TR/html401/appendix/notes.html#h-B.2.2)
that semicolons should be used instead of ampersands as a separator.
However, it provides no mechanism to select the separator to use
when submitting a form, which makes it a pretty useless recommendation.
This recommendation also complicates matters on the server because one
would need to handle both form-generated GET query parameters and
hardcoded GET query parameters as specified in anchors.

There's also a 2006 Internet-Draft by Bjoern Hoehrmann that was
intended to standardize this, but it was allowed to expire in 2007:
http://ietfreport.isoc.org/idref/draft-hoehrmann-urlencoded
It was different in a few ways from the x-www-form-urlencoded type.
For example, www-form-urlencoded only pct-encoded the chars that
are not allowed in a query string, whereas x-www-form-urlencoded
pct-encodes *all* reserved chars, regardless of whether it is
necessary. There are servers which do not accept input that isn't
fully pct-encoded so in the uri-common CHICKEN egg we use strictly
x-www-form-urlencoded with a SRFI-39 parameter object that controls what
separator(s) to use when parsing an URI and also when serializing.

Note that popular web frameworks like Ruby on Rails and PHP complicate
matters even more by assigning semantics to the key names, in that a key
like "foo[]" can occur more than once which causes the values to be
collected into an array.  If there is no "[]" at the end of a key, IIRC
multiple occurrances are collapsed and the last occurrance of a
specific key simply clobbers all other values of that key.
I don't know what happens when you mix it, like in the query
"?foo=1&foo[]=2&foo=3&foo[]=4&foo[]=5".

And (again) IIRC, in at least Ruby on Rails you can also do something
like "foo[bar]=1" to get a map/hash table under "foo" with key "bar"
and value 1 underneath.

Note that especially this type of behaviour is pretty bad in a generic
URI parser, because it leads to data loss on re-serialization, so you
can't use this in e.g. URL shorteners or proxies.

In uri-common, I chose to turn queries into an alist, but keep
duplicates and attach *no* specific semantics to special characters.
This allows for lossless re-serialization while at the same time
allowing a web framework to attach special meaning to special characters
if it chooses to wrap the URI object.

So, to use my earlier example, "?foo=1&foo[]=2&foo=3&foo[]=4&foo[]=5" is
actually rejected as [] is not allowed unencoded (as per the "pchar"
production, which does not include "gen-delims", which has "[" and "]").
But if you percent-encode it as
"?foo=1&foo%5B%5D=2&foo=3&foo%5B%5D=4&foo%5B%5D=5",
it will return two "foo" and two "foo[]" keys, converted to symbols:

#;1> (import uri-common)
#;2> (uri-query (uri-reference "?foo=1&foo%5B%5D=2&foo=3&foo%5B%5D=4&foo=%5B%5D=5"))
((foo . "1") (|foo[]| . "2") (foo . "3") (|foo[]| . "4") (foo . "[]=5"))

Note that Ruby's built-in "cgi" module does something similar:

irb(main):001> require 'cgi'
irb(main):002> CGI.parse("foo=1&foo%5B%5D=2&foo=3&foo%5B%5D=4&foo%5B%5D=5")
=> {"foo"=>["1", "3"], "foo[]"=>["2", "4", "5"]}

I do not know where the behaviour in Rails comes from.

PHP behaves as follows:

php > parse_str('foo=1&foo%5B%5D=2&foo=3&foo%5B%5D=4%5B%', $res);
php > print_r($res);
Array
(
    [foo] => Array
        (
            [0] => 4
            [1] => 5
        )

)

Make of that what you will.

Note that the WHATWG URL standard does mention x-www-form-urlencoded:
https://url.spec.whatwg.org/#application/x-www-form-urlencoded

At least they acknowledge that it is "an aberrant monstrosity".

Cheers,
Peter