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.