#2863 URI name only query params

SlimerDude Fri 12 Nov 2021

Hi, some REST APIs require that URI query params have NO value, such as /foo?m&n - but support for this in Fantom is limited.

I would like to see Uri.plusQuery() and Uri.encodeQuery() support null values in the given query Map, so Uris can be easily created and merged.

`foo`.plusQuery(["m":null, "n":null])            // --> /foo?m&n
`foo?a=b&m=bar`.plusQuery(["m":null, "n":null])  // --> /foo?a=b&m=bar&n

Changes to Uri.encodeQuery() to support this are minor (just a quick if statement), but I don't know what (if any) knock on changes to Uri there may be if the query section is now allowed to hold nulls.

What is the Fantom stance on name only query params?

I noted that the Java implementation for URI.encodeQuery() DOES already natively support this (by allowing null values in the given Map) but the Fantom signature DOES NOT.

static Str encodeQuery(Str:Str q)

I also note that the RFC URL in the Uri documentation is now obsolete (http://tools.ietf.org/html/rfc3986) and seems to have been moved to https://datatracker.ietf.org/doc/html/rfc3986.

brian Fri 12 Nov 2021

I vaguely remember using null to indicate no value, although I don't really love that design pattern. I guess its better than anything else.

What API are you working with where a query param value actually breaks thing?

SlimerDude Mon 22 Nov 2021

I vaguely remember using null to indicate no value

It's quite nice, as it differentiates between no value and an empty string:

`foo`.plusQuery(["bar":""])      // --> /foo?bar=
`foo`.plusQuery(["bar":null])    // --> /foo?bar

When combining queries, I envision values overriding non-values.

`foo?bar`.plusQuery(["bar":"hello"])  // --> /foo?bar=hello

What API are you working with

A customer is calling the eGauge API which returns 400 responses to certain query params with values, but I've had to work around this limitation myself in the past.

But it shouldn't matter which particular API or website requires it and whether they handle it correctly or not - I see the question as being more generic:

"Should Fantom handle name only query params or not?"


If so, the only other edge case I see that may need re-evaluating, is the query() method (which I've always thought a little odd as it alters param value data that the URI was constructed with - and this absolutely HAS caused issues in the past):

If a pair contains the "=", then it is split into a key and value, otherwise the value defaults to "true".

`?a=b;;c`.query                 =>  ["a":"b", "c":"true"]

To argue for the change, I would argue that `foo?c`.query.containsKey("c") is more correct than `foo?c`.query["c"] == "true".

andy Tue 23 Nov 2021

Allowing null seems intuitive to me on the encoding side - I would be in favor of this change:

`/foo`.plusQuery(["m":null, "n":null]) -> /foo?m&n

Pulling it back out as nullable is a bit more ambiguous - mixing up Map.get for Map.containsKey is going to trip alot of people up.

In hindsight maybe using an empty string "" would have been better than "true", since I do agree its awkward. But that would be a breaking change I don't think we would be able to make.

brian Tue 23 Nov 2021

I'm in agreement that it would be nice to have a consistent design that lets you omit the value in both encoding and decoding. But I really don't like using null. Using null as a special value in maps is ugly and error prone. And I would like to avoid breaking changes since we are already decoding value-less pairs to use "true".

Have you looked to see what other dictionary oriented languages do?

siloam Wed 15 Dec 2021

IMHO it could be added to provide compatibility with Java. Python is very dictionary oriented but parse_sq from urllib.parse module do not recognize such strings. Take a look. And yes, null is bad.

>>> parse_qs('http://in.pl?m&n')
{}
>>> parse_qs('http://in.pl?m=1&n=2')
{'http://in.pl?m': ['1'], 'n': ['2']}

Login or Signup to reply.