The query
part of a URL
seems to consist of key-value pairs separated by &
and associated by =
.
I've taken to always using jQuery's $.param()
function to URL-encode my query strings because I find it makes my code more readable and maintainable.
In the past couple of days I find myself calling the MediaWiki API but when cleaning up my working prototype with hard-coded URLs to use $.param()
I noticed some MediaWiki APIs include query parameters with keys but not values!
api.php ? action=query & titles=Main%20page & redirects
Notice the part &redirects
, which takes no value.
jQuery's $.param()
takes an object and since objects consist only of key-value pairs it's not possible to pass an object where one member has a key but no value.
That's fine so I assumed I could just pass some value in such as null
or undefined
or 0
but it seems all of these are treated alike. I find this surprising and I've been unable to spot anything in the MediaWiki API documentation about the reasoning behind this.
OK it's easy to work around in my case by building the URL string manually. My question is "Is this a quirk in the MediaWiki API? Or a quirk in the design of URL-encoding? Where should I read to understand the reasoning behind URL-encoded parameters that have no associated values?
Most likely what they are doing is just checking that the parameter is defined. By adding redirects
to the query string, that effectively is saying "redirects variable is true". So, adding redirects=0
is still defining that variable, and the MediaWiki API is noting that it is defined (not caring what the value is).
Your jQuery code will simply need to append that parameter (with any value, or no value) or omit it if you do not want it to be defined.
Just asking this question and getting some feedback from others prompted me to dig further too.
Wikipedia's "Query string" page in the section "Web forms" says:
- The field-value pairs are each separated by an equals sign. The equals sign may be omitted if the value is an empty string.
The query string is defined in section 3.4 of RFC 3986, but in fact the key-value pairs are not part of the standard, and are only briefly mentioned:
However, as query components
are often used to carry identifying information in the form of
"key=value" pairs and one frequently used value is a reference to
another URI, it is sometimes better for usability to avoid percent-
encoding those characters.
As you can see, nothing on the presence or absence of values for the keys.
As for jQuery, it turns out that two bug reports / feature requests have been filed about this behaviour in the past 15 months:
- Ticket #8653 "JQUERY.PARAM OUTPUTS "NULL" AND "UNDEFINED" IN THE QUERY STRING"
- Ticket #11329 ".PARAM() SHOULD RETURN EMPTY VALUES FOR NULL AND UNDEFINED"
Various proposals were made covering whether to convert param: null
and param: undefined
to param
or param=
.
In the end a fix has been included for the next release of jQuery, 1.8, which converts both null
and undefined
to param=
- the empty string.
This makes some kind of sense of course, but for the case of MediaWiki, which was not mentioned in the bug reports / feature requests, this does not help at all:
http://en.wikipedia.org/w/api.php?action=query&titles=Main%20page&redirects=
returns
<?xml version="1.0"?>
<api>
<query>
<redirects>
<r from="Main page" to="Main Page" />
</redirects>
<pages>
<page pageid="15580374" ns="0" title="Main Page" />
</pages>
</query>
</api>
To sum up:
The standards don't define what should be done here, leaving it up to the implementations. The MediaWiki API did one thing, jQuery initially overlooked it, then when it was pointed out, did a different thing. The two parties don't seem to be aware of each other.
A gap in the spec has led to incompatible interpretations ... but they're not hard to work around.
Well, if you make a little test webserver in python or ruby or something and request a url with query string like ?something
, generally you will see the params come in as something=nil
(or similar).
MediaWiki is written in PHP, so it might be handled a little differently, but it seems to me you should be safe just doing $.params( { redirects: null } )
and it will simply not check the value since it doesn't need one. Alternatively just construct it yourself by appending the correct string.