As an empty string is not valid JSON it would be incorrect for JSON.parse('') to return null because "null" is valid JSON. e.g.
JSON.parse("null");
returns null. It would be a mistake for invalid JSON to also be parsed to null.
While an empty string is not valid JSON two quotes is valid JSON. This is an important distinction.
Which is to say a string that contains two quotes is not the same thing as an empty string.
JSON.parse('""');
will parse correctly, (returning an empty string). But
JSON.parse('');
will not.
Valid minimal JSON strings are
The empty object '{}'
The empty array '[]'
The string that is empty '""'
A number e.g. '123.4'
The boolean value true 'true'
The boolean value false 'false'
The null value 'null'
As an empty string is not valid JSON it would be incorrect for JSON.parse('') to return null because "null" is valid JSON. e.g.
JSON.parse("null");
returns null. It would be a mistake for invalid JSON to also be parsed to null.
While an empty string is not valid JSON two quotes is valid JSON. This is an important distinction.
Which is to say a string that contains two quotes is not the same thing as an empty string.
JSON.parse('""');
will parse correctly, (returning an empty string). But
JSON.parse('');
will not.
Valid minimal JSON strings are
The empty object '{}'
The empty array '[]'
The string that is empty '""'
A number e.g. '123.4'
The boolean value true 'true'
The boolean value false 'false'
The null value 'null'
Use try-catch to avoid it:
var result = null;
try {
// if jQuery
result = $.parseJSON(JSONstring);
// if plain js
result = JSON.parse(JSONstring);
}
catch(e) {
// forget about it :)
}
Best Practices to send for Empty Values of a JSON API?
Send empty object if json string is null
export - How can I create an empty JSON object? - Mathematica Stack Exchange
What is the minimum valid JSON?
What do you choose? Getting lots of conflicting answers.
-
Null
-
Undefined (Omitted from JSON)
-
Empty of that type?
-
String = ""
-
Number = 0
-
Boolean = false
-
Array = []
-
Object = {}
-
CMS JSON API to be consumed by JS Framework Frontend
You can define your own object and tell Mathematica to interpret it as JSON object.
Dummy export to load relevant contexts:
In[1]:= ExportString["", "JSON"];
Tell Mathematica to interpret JSONObject symbol as possible head of JSON objects:
In[2]:= ClearAll[JSONObject]
System`Convert`JSONDump`$JSONObjectHead = JSONObject;
Now you can use JSONObject anywhere in exported expression:
In[4]:= ExportString[JSONObject[], "JSON"]
Out[4]= {}
In[5]:= ExportString[{"a" -> JSONObject[]}, "JSON"]
Out[5]= {"a" : {}}
In[6]:= ExportString[JSONObject["a" -> JSONObject["b" -> Null]], "JSON"]
Out[6]= {"a" : {"b" : null}}
How it works
Internally export to JSON is handled by System`Convert`JSONDump`exportJSON function which is just a wrapper for System`Convert`JSONDump`iexportJSON. The latter calls System`Convert`JSONDump`toString which does the real conversion and, among others, includes following definitions (System`Convert`JSONDump` context removed from symbol names):
toString[x_?($JSONObjectHead =!= List && MatchQ[#1, $JSONObjectHead[]]&), `t_Integer] := {}
toString[x_?($JSONObjectHead =!= List && Head[#1] === $JSONObjectHead && Length[#1] =!= 0&), t_Integer] := toString[List @@ x, t]
that use $JSONObjectHead.
How to find out, how exporting works
You can start by tracing evaluation of export expression:
TracePrint[
ExportString["mySpecialString", "JSON"],
_[___, "mySpecialString", ___]
]
You'll find that System`Convert`JSONDump` context looks interesting. For fast overview of it's symbols you can look at:
Names["System`Convert`JSONDump`*"] // TableForm
Real fun will start if you use this great spelunking tool:
Get["https://raw.githubusercontent.com/szhorvat/Spelunking/master/Spelunking.m"]
Pick a function, from printed trace that looks promising:
Spelunk["System`Convert`JSONDump`exportJSON"]
and dig deeper by clicking on links to functions that you see in the trace.
About spelunking tool I learned from one of halirutans answers.
For newer versions exporting an empty Association does what you want:
ExportString[<||>, "JSON"]
Newer Versions means >= 10.1, 10.0.x versions did export empty Associations to empty lists, of course the new behavior is a much better match for the distinction of JavaScript empty lists and objects in Mathematica...
As mentioned by Kuba in a comment the export format "JSON" has some deficiancies which are overcome by the export format "RawJSON" which seem to work better than "JSON" in many respects, especially when working with Associations...
Kubas example where "JSON" gives an error while "RawJSON" works as intendes was:
ExportString[<|"test" -> <||>|>, "RawJSON"]
At the time of writing, JSON was solely described in RFC4627. It describes (at the start of "2") a JSON text as being a serialized object or array.
This means that only {} and [] are valid, complete JSON strings in parsers and stringifiers which adhere to that standard.
However, the introduction of ECMA-404 changes that, and the updated advice can be read here. I've also written a blog post on the issue.
To confuse the matter further however, the JSON object (e.g. JSON.parse() and JSON.stringify()) available in web browsers is standardised in ES5, and that clearly defines the acceptable JSON texts like so:
The JSON interchange format used in this specification is exactly that described by RFC 4627 with two exceptions:
The top level JSONText production of the ECMAScript JSON grammar may consist of any JSONValue rather than being restricted to being a JSONObject or a JSONArray as specified by RFC 4627.
snipped
This would mean that all JSON values (including strings, nulls and numbers) are accepted by the JSON object, even though the JSON object technically adheres to RFC 4627.
Note that you could therefore stringify a number in a conformant browser via JSON.stringify(5), which would be rejected by another parser that adheres to RFC4627, but which doesn't have the specific exception listed above. Ruby, for example, would seem to be one such example which only accepts objects and arrays as the root. PHP, on the other hand, specifically adds the exception that "it will also encode and decode scalar types and NULL".
There are at least four documents which can be considered JSON standards on the Internet. The RFCs referenced all describe the mime type application/json. Here is what each has to say about the top-level values, and whether anything other than an object or array is allowed at the top:
RFC-4627: No.
A JSON text is a sequence of tokens. The set of tokens includes six structural characters, strings, numbers, and three literal names.
A JSON text is a serialized object or array.
JSON-text = object / array
Note that RFC-4627 was marked "informational" as opposed to "proposed standard", and that it is obsoleted by RFC-7159, which in turn is obsoleted by RFC-8259.
RFC-8259: Yes.
A JSON text is a sequence of tokens. The set of tokens includes six structural characters, strings, numbers, and three literal names.
A JSON text is a serialized value. Note that certain previous specifications of JSON constrained a JSON text to be an object or an array. Implementations that generate only objects or arrays where a JSON text is called for will be interoperable in the sense that all implementations will accept these as conforming JSON texts.
JSON-text = ws value ws
RFC-8259 is dated December 2017 and is marked "INTERNET STANDARD".
ECMA-262: Yes.
The JSON Syntactic Grammar defines a valid JSON text in terms of tokens defined by the JSON lexical grammar. The goal symbol of the grammar is JSONText.
Syntax JSONText :
JSONValue
JSONValue :
JSONNullLiteral
JSONBooleanLiteral
JSONObject
JSONArray
JSONString
JSONNumber
ECMA-404: Yes.
A JSON text is a sequence of tokens formed from Unicode code points that conforms to the JSON value grammar. The set of tokens includes six structural tokens, strings, numbers, and three literal name tokens.
It is good programming practice to return an empty array [] if the expected return type is an array. This makes sure that the receiver of the json can treat the value as an array immediately without having to first check for null. It's the same way with empty objects using open-closed braces {}.
Strings, Booleans and integers do not have an 'empty' form, so there it is okay to use null values.
This is also addressed in Joshua Blochs excellent book "Effective Java". There he describes some very good generic programming practices (often applicable to other programming langages as well). Returning empty collections instead of nulls is one of them.
Here's a link to that part of his book:
http://jtechies.blogspot.nl/2012/07/item-43-return-empty-arrays-or.html
"JSON has a special value called null which can be set on any type of data including arrays, objects, number and boolean types."
"The JSON empty concept applies for arrays and objects...Data object does not have a concept of empty lists. Hence, no action is taken on the data object for those properties."
Here is my source.
Old question - but its the top result when you search for 'json stringify empty string' so I'll share the answer I found.
This appears to be a bug in certain versions of IE8, where empty DOM elements return a value which looks like an empty string, evaluates true when compared to an empty string, but actually has some different encoding denoting that it is a null value.
One solution is to do a replace whenever you call stringify.
JSON.stringify(foo, function(key, value) { return value === "" ? "" : value });
See also http://blogs.msdn.com/b/jscript/archive/2009/06/23/serializing-the-value-of-empty-dom-elements-using-native-json-in-ie8.aspx
now the esiest solution for this problem is, to pack the "document.getElementById('id').value" expression in the constructor of the String class:
JSON.stringify({a:new String(document.getElementById('id').value)}); -> {"a":""}
i can't find the primary problem, but with this, it's working well in Internet Explorer as well in FireFox.
i'm not very happy with this dirty solution, but the effort is not to much.
JSON library: https://github.com/douglascrockford/JSON-js/blob/master/json2.js
TLDR; Remove null properties
The first thing to bear in mind is that applications at their edges are not object-oriented (nor functional if programming in that paradigm). The JSON that you receive is not an object and should not be treated as such. It's just structured data which may (or may not) convert into an object. In general, no incoming JSON should be trusted as a business object until it is validated as such. Just the fact that it deserialized does not make it valid. Since JSON also has limited primitives compared to back-end languages, it is often worth it to make a JSON-aligned DTO for the incoming data. Then use the DTO to construct a business object (or error trying) for running the API operation.
When you look at JSON as just a transmission format, it makes more sense to omit properties that are not set. It's less to send across the wire. If your back-end language does not use nulls by default, you could probably configure your deserializer to give an error. For example, my common setup for Newtonsoft.Json translates null/missing properties to/from F# option types only and will otherwise error. This gives a natural representation of which fields are optional (those with option type).
As always, generalizations only get you so far. There are probably cases where a default or null property fits better. But the key is not to look at data structures at the edge of your system as business objects. Business objects should carry business guarantees (e.g. name at least 3 characters) when successfully created. But data structures pulled off the wire have no real guarantees.
Going with an empty string is a definitive no. Empty string still is a value, it is just empty. No value should be indicated using a construct which represents nothing, null.
From API developer's point of view, there exist only two types of properties:
- required (these MUST have a value of their specific type and MUST NOT ever be empty),
- optional (these MAY contain a value of their specific type but MAY also contain
null.
This makes it quite clear that when a property is mandatory, ie. required, it can never be null.
On the other hand, should an optional property of an object not be set and left empty, I prefer to keep them in the response anyway with the null value. From my experience it makes it easier for the API clients to implement parsing, as they're not required to check whether a property actually exists or not, because it's always there, and they can simply convert the response to their custom DTO, treating null values as optional.
Dynamically including/removing fields from the response forces including additional conditions on the clients.
Either way, whichever way you choose, make sure you keep it consistent and well documented. That way it really does not matter what you use for your API, as long as the behaviour is predictable.
