Ok, so perhaps I was a little bit OTT with the title of this blog post (but it got your attention, right?). What I actually mean is that JSON Sucks for hypermedia APIs, and I am going to tell you why. But before I do, I just want to point out that actually I think JSON is awesome for what it’s designed for – serialising an object. Objects naturally contain data structures like ints, strings, arrays and other objects – if all you need to do is represent those four things, you can’t go wrong with JSON. Seriously.
Hating XML is rather fashionable these days, so many API’s are appearing that are JSON representation only even when XML really is a better fit for purpose. When you’re designing a hypermedia API you’re not simply serialising an object. There are media types that add semantic meaning to JSON (application/hal+json, my own application/vnd.error+json (draft) and others) but really, XML is so much more expressive that using JSON actually makes your clients have to work harder to understand the meaning you’re trying to convey using an object serialisation format over a markup language.
XML gives you some stuff for free – ‘xml:lang’ for one. Put this on any element of your document and just the fact that your document is XML means that you can express elements in different (human) languages without having to update your media type.
Consider how this actually looks in XML vs JSON representation.
<error id="6"> <message>Something bad happened</message> </error> |
{ "error": { "id": 6, "message": "Something bad happened" } } |
This looks easy, right? Consider a future version of the api where we add support for multiple languages.
<error id="6" xml:lang="en"> <message>Something bad happened</message> <message xml:lang="de">Etwas schlimmes ist passiert</message> </error> |
{ "id": 6, "messages": [ { "lang": "en", "message": "Something bad happened" } { "lang": "de", "message": "Etwas schlimmes ist passiert" } ] } |
An alternative could be to key the message objects by language;
{ "id": 6, "messages": { "en": "Something bad happened", "de": "Etwas schlimmes ist passiert" } } |
You can see in both scenarios that “messages” has become an different type (string to array of objects, or string to object). We’ve changed the structure of the document and introduced an almost certain backwards compatibility (BC) break in our interface – all our clients now need to be updates to follow suit. We could leave “message” as it was, and add “messages” for the multilang version of the API but then we’re duplicating data and / or making the client have to work harder.
The XML version can continue as is and the client can simply ignore the additional languages until they’re updated to support them (if they ever need to).
Then there’s just the matter of basic human readability. It’s clear to see what’s going on in XML and not so much in JSON. This is a fairly simplistic example but extrapolate that out over a fairly complex representation of an object and you can see how JSON really isn’t always the best choice for representing resources.
Imagine the scenario where we had used the second option above as our JSON representation and we wanted to add in another attribute for each of the messages. See the problem? Anything we choose to do will cause a BC break and require clients to update (or result in duplication of elements to ‘version’ the api), meaning it’s very difficult to evolve the clients and servers independently.
So i’m not saying that JSON simply ‘sucks’. I’m just saying that when considering the formats you use for representing data in an API (when it comes to selecting the media type you want to use), think hard before just going with something based on JSON by default because it’s ‘easy’. It probably isn’t.
Especially not if you’re using Java! :P
Nice article.
My other two pet peeves with JSON are: 1) that it is (unnecessarily) difficult to validate, especially when compared to XML, and 2) that (for PHP, anyway) there is a distinct lack of stream parsers available for it.
Obviously, these so-called problems are easily solved by not validating your API I/O and just increasing the memory limit for your PHP processes…
So how about
Doesn’t force any old clients to update anything either. New users can just suffix the language code to the field(s) that is/are translated.
I’m pretty sure most people can live with the fact that the primary language (en) of the JSON is omitted since English is pretty much the defacto standard for any API.
Interesting. You got me thinking about how XML seems to have dropped off the charts for APIs Some things I thought of:
1) Re multilingual APIs. One option is to simply make the lang part of the URI (eg app.com/api/en/users/1 and app.com/api/de/users/1). I would argue that this could be a better design – coming from Symfony2 background where it encourages us to make the locale part of te URI.
2) I think in many cases JSON will result in smaller responses which is important when bandwidth is a concern. Also, by doing 1), you reduce the response size too.
3) Personally I actually think JSON is easier to read. Do you really think the XML is easier?
Cheers, Jon
@Remon: Ok you can hack your way around the problem – but the fact remains that you’re hands are very much more tied when you use JSON. What if you needed to add two or three chunks of data instead of just one? Yes you could flatten it all out but then your representation becomes clunky and difficult to work with. What if you have a variable number of items that you would normally represent in an array? It makes it more difficult for your client to parse if it’s all flattened out in the root object. Not very nice.
@Jon
1) Yes there’s better ways of handling multi lang (I would go for the Accept-Language / Content-Language HTTP headers in an API response like this – your suggestion of using the URI is fairly common in websites too (but using the preferred language setting in the browser included in the header I think is cleaner). The language example above was only really to show where JSON ends up being changed quite a lot, and XML stays almost the same in structure.
2) I’m not sure I agree. If you gzip your response (and you should) you’re going to get down to a fairly comparable size whether it’s JSON or XML. Do agree that for multi lang though, the decision of what language to present *should* happen on the server, rather than in the client.
3) Depends. For simple structures, not really. When you start getting more complicated (arrays of objects in arrays etc) the fact that XML is just a more expressive format means that you have fewer lines to traverse, so it can actually make it easier to understand.
You got a point. But, from my own experience with working with and making different APIs – the truth in reality is that a possible BC break is usually worth the simplicity you get when using JSON (in comparison to XML).
A good example here would be the Google’s history of their services external APIs. How they went all the way from Google Data API (super flexible, complex XML (AtomPub)) to JSON and how they’re still making the switch for some of their services.
なるほどとも思う JSON Sucks http://t.co/havdr80E
Could not agree more. Never really been an XML fanboy, but its just cleaner IMHO.
At first glance this example seemed to make perfect sense. But my gut feeling was that there was something wrong with that example itself. That example was fundamentally broken. The correct way to represent
Something bad happened
Etwas schlimmes ist passiert
as json is:
{
“error”: {
“-id”: “6”,
“-xml:lang”: “en”,
“message”: [
{
“#text”: “Something bad happened”
},
{
“-xml:lang”: “de”,
“#text”: “Etwas schlimmes ist passiert”
}
]
}
}
So my hunch is that the person who wrote the article was either oldschool or fundamentally biased against json. Usually if ppl are already biased then they start articles like saying it sucks and then write that they are not saying that. I’d say it was either misknowledge or clever trick of demagogy to support the bias.
@boicy Thanks for the chat! I was referring to this post earlier from 2012. I stand by it, but admit defeat :) http://t.co/D9wDXkbTI1
Why would you have json to return all that anyways. All you need is
{
“error”: {
“id”: 6,
“message”: “Something bad happened”
}
}
You don’t return multiple languages, you handle the language in the call.
http://someurl/api/getCustomer/102?lang=JP
And make it all default to english if no lang is specified.
JSON sucks for a lot of other reasons:
1. It’s a plain text format.
2. It’s not extensible. If you want to serialize/deserialize domain objects you have to write your own encoding/decoding layer.
3. It doesn’t support circular references.
4. It doesn’t support comments. (Really?!)
5. It’s overly popular and everyone wants to use it for everything, even though it sucks.
XML is not the ideal format for any wire transfer. Its bloated, clunky, expensive by all means.
Just got done using JSON in a java & web class in college this semester. Gotta say… not a fan. I remember xml being the new kid on the block back in the 00’s, and everyone went bat-shit for it, trying to shoe-horn it in everywhere and swap out “old stuff” with this new, fancy xml. Every new tech follows “new toy syndrome”, where folks go bananas trying to use it for everything from the thing it was meant for to things it wasn’t… all in an attempt to make it seem like a unified thing has finally arrived that will band-aid solve everyone’s problems.
Anyways, fast forward to me being back in college now for an IS degree (getting degree to support career I already have). It’s the 21st frickin century. I would think by now I could just write 1 line of code to tell it to get teh JSON data I’m pointing to, and a “json object” will automatically parse out and create a data structure per the JSON data I’m pulling. Right? RIGHT?!
No.
You have to get the JSON data. Then you have to refer to the first object in it. Then you have to refer to the subobject in it, then you have to refer to the subobject or array of that subobject…
If I had json data like this
{
“person”:{
“fname”: “bob”,
“lname”: “jones”,
“address”:{
“street”: “1313 13th st.”,
“city”: “whoville”,
“st”: “BB”
}
}
}
(or however it’s done for JSON .. and let’s say there were 100 people in the JSON file)…
I would ideally be able to load and use it in some simple fashion like this…
myJsonData = (something something).getJSONDataFrom(myJsonPlace)
String testVariable = “”;
for ( i = 0; i < myJsonData.length; i++ )
testVariable += myJsonData.person(i).fname + ", ";
I mean, the flipping JSON data gives the template for the data with field names… why can't the JSON data object just parse them out as attributes that can be referenced in … JSONdataobject.fieldname … fashion?
It's so annoying.
I had to type up 10-20 lines of code to use json data on various things when to me it seems like I should just be able to use 1 line of code to do this.
I don't see the point in JSON (or even XML) organizing data with field names and such when you have to still bend over backwards to parse it all out in your code instead of some object doing all that shit for you.
It's the 21st fricking century, and this is the best we can do? Really?!
My other issue with JSON is that to pull data from a JSON data store… you have to pull the WHOLE DATA STORE. If some idiot is trying to use JSON as a poor-man's SQL db to store 100k records… you have to pipe 100k records worth of data across the net to then sift through it to find what you want.
This is why SQL servers were created… toss one on a back-end data server, and let the web server tell it "look, end user just wants person records that have fname = 'Bob' … only give me those, and I'll use them to send back a web page."
The SQL server (MySQL, SQL Server, Oracle, SQLite, etc) do all the heavy-lifting to sift for ONLY what the end user needs… instead of dumping the ENTIRE DATA SOURCE (JSON) to the end-user and making javascript or some-such sift through it after-the-fact. It's just so much wasted bandwidth.
And if the JSON record source gets TOO BIG… it's just massive amounts of network traffic when you're running megabyte (or even gigabyte) JSON files back-n-forth everywhere just so an end-user can sift out specific things they need.