Marco Roy
Marco Roy

Reputation: 5243

How to send NULL in HTTP query string?

I'm developing an API that can accept the main three data types as values to query string parameters: boolean, string & numeric (integer or float). By default, everything is retrieved a string (I don't think there's a way around that), but the parameters are configured with a type so that I convert them to the proper type.

I now need to start accepting NULL as a value, for all three data types, but I'm not sure what is the best way to do so.

Some people seem to accept no value as NULL (?param, without =), but that is no quite working for me:

  1. I'm already accepting that as true for booleans, although that could be changed.
  2. It is received as an empty string, which is a valid value for the string data type.

So, here are the only two options I can see, none of which are working for me:

  1. Use a constant, like "NULL" or "~". That works for booleans & numbers, but not for strings, as that might be the desired string value.
  2. Use an empty value. Once again, that can work for booleans & numbers, but not for strings, as that might be the desired string value.

Seems like using a constant might be my only choice, and to avoid issues that constant can be forbidden from strings. But is that really the only viable option? I wish there were a better way. :(

Edit: I just had another idea that might work, but I'm not sure how it would be perceived. I think it definitely breaks standards, and a lot of people would most likely not like it, but would fix my issue better than any other solution so far. Basically, the idea would be to use JSON, which supports native data types. I'm not having this issue with POST requests because they're using JSON.

So the idea would be to take JSON in the query string, basically allowing an alternative query string that would override the standard HTTP one. Something like: ?_json={"foo":"bar","param":null} instead of ?foo=bar&param=~. Or maybe even take over the query string entirely: ?{"foo":"bar","param":null}.

Upvotes: 51

Views: 131794

Answers (4)

Testo Testini
Testo Testini

Reputation: 2240

In your use case that is more clear after the edit I would go surely for the ?_json= parameter, there is nothing wrong with it and since everything works for POST as you write there is no doubt that is better than inventing a generic binding protocol through request parameters (application/x-www-form-urlencoded). I personally have been using two parameters to support also other content types like XML, one $rqc carries the content like your _json and one $rqct carries the content-type, eg:application/json

Said that, I think JSON works well because it allows 4 possibilities for a string property:

  1. filled {"param":"foo"}
  2. empty {"param":""}
  3. absent {}
  4. null {"param":null}

A request parameter instead can have only 3:

  1. filled ?param=foo
  2. empty ?param= or ?param (Server API usually does not differentiate the 2 cases)
  3. absent ?

The 4th possibility, an explicit null, can be handy for partial updates: if one updates only the fields present in the request JSON object; you cannot easily express that with a request parameter.

However if you don't do partial updates you may consider an absent parameter as a null value, but you need to know all parameters allowed for that endpoint, that is not always possible without a schema or other specification (a class to bind to); since you say that you associate parameters to types you probably have it.

The fact that ASP.NET (I learn it now from the answers) does not differentiate between empty and absent parameter reminds me that is often dangerous to allow an empty string and/or treat it differently from an absent/null string, for example because for Oracle an empty string is converted to null, so is not valid for a NOTNULL column (in mysql is ok), see null vs empty string in Oracle.

So if you don't need to support the difference between empty and null/absent string you may also consider the empty parameter as null.

If instead you want to recreate point 4. of JSON {"param":null} with request parameters you must use a convention, like passing %00 as suggested in the answers or using the null marker parameter I propose later.

If the purpose is to create something generic I wouldn't use %00 because some servers may have some parameters sanitization mechanism enabled: if it refuses %00 (as it probably should) then the convention can not work. I checked now and JSOUP removes all in the range %00-%0F. Maybe also ASP.net does by default, see Special character causes "A potentially dangerous Request.Form value"

A more HTML-ish approach could be using an extra null marker parameter whose name is obtained by the original parameter with a suffix, eg: from param it could be param$null: if the parameter is present then the bound value is null, whatever the value of param, it is like putting a unset checkbox before a text input and un-setting the bound value when is checked. Furthermore if you have some way to annotate a parameter/property to support this syntax you might limit the check to those parameters (probably less than 1% of total) and for all the others treat empty parameter and absent parameter in the same way: binding it to a null value.

Upvotes: 5

Kylar
Kylar

Reputation: 9324

Send a URLEncoded NULL value (%00) for any thing that you're specifically setting to null. It should be correctly URL Decoded.

Upvotes: 41

enthusiast
enthusiast

Reputation: 999

or just don't send any value. leave query param value empty in your get request url.. like -

API URL/?foo=&some_other_param=value

in the API foo will be received as null

Upvotes: 10

Ariel
Ariel

Reputation: 1

With IIS and C#, I send it this way:

?param=#

Upvotes: -10

Related Questions