Best Practices: Response Formats in XML & JSON - use specific or generic root elements?

3,143 views
Skip to first unread message

jefshock

unread,
Mar 28, 2012, 10:56:57 AM3/28/12
to api-...@googlegroups.com
As many APIs do, ours will return XML or JSON. We have lots of data objects and are trying to standardize our response formats. So would love feedback on best practices you use or follow. (I have 3 specific questions at the bottom of the post).

For the following request...
GET /v1/dogs/34

and response...
{
    "dog": {
                   "uri": "/v1/dogs/34",
                   "id": 34,
                   "name": "fido"
              }
}

we're using the singular name of the resource as a root element, which converts easily to XML. I've seen lots of JSON responses without a singular root element, but in XML responses, there is usually a single root element.
<dog>
    <name>fido</name>
</dog>

What about collections?
GET /v1/dogs

{
    "count": 1,
    "dogs": [
                   { "uri": "/v1/dogs/34",
                     "id": 34,
                     "name": "fido" }
                ]
}

Again, we're using the resource name with our collection array as a root element along with some other details about the collection as a whole. Should there be a single root element? What about for XML?

I've seen API responses with a generic "results" root element in the response. So my specific questions are...

1) Should there always be a single root element in XML?
2) Is it best to use the resource name as a root element in the result or a generic root element?
3) If using the resource name as a root element, should it be singular for a specific resource and plural for collections?

Thanks in advance for your thoughts.



Jørn Wildt

unread,
Mar 28, 2012, 11:27:04 AM3/28/12
to api-...@googlegroups.com
Try taking a look at this (ongoing) discussion: https://groups.google.com/d/msg/hypermedia-web/V0hcWwQet3I/nIcGjbdTjxMJ - it starts out with a discussion about media-types and ends with a discussion of link-relations vs. inclusion of type information like your <dog> root element.
 
Have fun :-)
 
... and feel free to join the discussion.
 
The short version is: its a design choice, there is no right or wrong way - but its good to understand the reasons that lies behind the choices.
 
/Jørn

Mike Schinkel

unread,
Mar 28, 2012, 11:32:23 AM3/28/12
to api-...@googlegroups.com
----- Original Message -----
From: jefshock
Sent: Wednesday, March 28, 2012 4:56 PM
Subject: Best Practices: Response Formats in XML & JSON - use specific or generic root elements?

As many APIs do, ours will return XML or JSON. We have lots of data objects and are trying to standardize our response formats. So would love feedback on best practices you use or follow. (I have 3 specific questions at the bottom of the post).

For the following request...
GET /v1/dogs/34

and response...
{
    "dog": {
                   "uri": "/v1/dogs/34",
                   "id": 34,
                   "name": "fido"
              }
}
Having the "dog" element feels overly complicated, and it's implied. One of the benefits of JSON IMO is the reduced complexity compared to XML; why bring the same complexity XML requires when doing JSON?

And if the client really needs that complexity to differentiate from "cat", for example, it can wrap the response, as needed, for it's own use.

JMTCW.

-Mike

Greg Brail

unread,
Mar 29, 2012, 2:34:42 AM3/29/12
to api-...@googlegroups.com
As I think Jorn said, it's a design decision. I also have been involved in discussions about whether it makes more sense to make the XML and the JSON formats identical, or if it makes sense to make each one "idiomatic" for its own realm, so that you return what a programmer in each environment expects.

IMHO a JSON API response is an object, or an array of objects -- that's how a programmer will use it. So if you GET a "dog" you expect a "dog" object and not a generic object that has a member called "dog".

OTOH, an XML response is an XML document, XML documents aren't 1-1 mappings to programming-language objects, and XML doesn't leave us a lot of options. The question of, "Should there always be a single root element in XML?" has only one correct answer -- "yes." If there's not a single root element then it's not XML. Programmers versed in XML expect that they'll get back a document with a single root element of type "Dog" or "Dogs" or their tools will break.

Unfortunately, I know how hard it is to do this in practice. If you build an "XML first" API and try to convert it to JSON later, you'll end up with API responses that contain extra elements in the JSON that are not JSON-y. OTOH, if you build a "JSON first" API then you need extra info in order to convert it into JSON (although this conversion is easier than the other way around). One library that appears to do this reasonably well in Java is Jackson with its XML extensions -- you end up annotating your classes for JSON output and then you construct XML from that.

But my nirvana, at least for now, would be something like this:

GET /v1/dogs/34
Accept: application/json

{ "name" : "Fluffy", "size" : "little" }

GET /v1/dogs/34
Accept: application/xml

<Dog>
  <Name>Fluffy</Name>
  <Size>little</Size>
</Dog>

and the corresponding collections:

GET /v1/dogs
Accept: application/json

[ { "name" : "Fluffy", "size" : "little" },
  { "name" : "Rex", "size": "big" } ]

GET /v1/dogs
Accept: application/xml

<Dogs> 
  <Dog>
    <Name>Fluffy</Name>
    <Size>little</Size>
  </Dog>
  <Dog>
    <Name>Rex</Name>
    <Size>big</Size>
  </Dog>
</Dogs>
--
Gregory Brail  |  Technology  |  Apigee

Jørn Wildt

unread,
Mar 29, 2012, 3:39:02 AM3/29/12
to api-...@googlegroups.com
One more comment ... should the XML root element be domain specific or generic - is it "<Dog>" or "<Data>"?

If you accept the fact that JSON works fine without a domain/type specification in the root element then it should work fine too for XML - right? Usualy people are happy with this:


  GET /v1/dogs/34
  Accept: application/json

  { "name" : "Fluffy", "size" : "little" }

But they will object to this(below) with an argument like "But how should we know the type of the data?" (been there myself):

  GET /v1/dogs/34
  Accept: application/xml

  <Data>
    <Name>Fluffy</Name>
    <Size>little</Size>
  </Data>

... but the type is not required in JSON, right, so its not required in XML either :-) This is the approach of the generic HAL format.

/Jørn

Duncan Cragg

unread,
Mar 29, 2012, 5:37:19 AM3/29/12
to api-...@googlegroups.com
Heya!

The Object Network approach is this:

GET /on/uid-123-34.json

{ "is": [ "dog", "animal", "contact" ], "fullName" : "Fluffy",
"breed": "poodle" }

Firstly, I'm making a point that you have a Hypermedia API here, by
obfuscating the URLs! Now you have to look at the content to know the
type. I think you /shouldn't/ drop the type info altogether in the JSON,
thus relying on the client knowing that it followed a 'dog' link to
guess the type implicitly. Be self-descriptive and declarative - it'll
at least help with debugging and when saving objects to files!

Putting '.json' on the end can also help with debugging and when the URL
is used to name a downloaded or uploaded file. I'd use that instead of
conneg, too, as it's more out in the open, more familiar, better
supported. The argument against this is that, if you have JSON and XML
versions, that 'creates two resources' for a single logic object, but
that's just an abstract non-problem in practice. In the code, you just
use the extension when the data is on its way out of the server, to
serialise it appropriately. And no client actually /wants/ to hold a
logical resource URL and then decide 'hmm, I think I'd like the ... XML
version, this time!'

Instead of wrapping everything in a single type tag, I have a /list/ of
types under "is" - in this case, we can borrow "fullName" from the
"contact" type - a mixin that you can't get with the single-type
wrapping approach.

This also has the benefit that you can just navigate into the object
looking for things you recognise without even knowing the
server-presumed, fixed, single type of the object.
_ _ _ _ _ _ _ _ _ _ _ _

XML isn't in the Object Network, but off the top of my head, I'd
consider doing it this way:

GET /on/uid-123-34.xml

<object is="dog, animal, contact" fullName="Fluffy" breed="poodle" />
_ _ _ _ _ _ _ _ _ _ _ _

Lists of dogs in the Object Network approach:

GET /on/uid-654.json

{ "is": [ "dog", "animal", "contact", "list" ]
"list": [ "/on/uid-123-34.json", .. ]
}

Note how I've again assumed we want a hypermedia API! You can inline
things in the search interface, which I'll come to below..
_ _ _ _ _ _ _ _ _ _ _ _

Again, no XML in the ObNet, but I'd go with:

GET /on/uid-654.xml

<list is="dog, animal, contact" >
<a href="/on/uid-123-34.xml" />
:
</list>

Again, you know you're generating XML, so when you serialise the link,
add '.xml' on the end. Make everyone's life easier with a line of code!
_ _ _ _ _ _ _ _ _ _ _ _

So, search. I POST a query to the collection being queried, with "is:
query" to flag that you're not trying to create a new entry:

POST /on/uid-654.json

{ "is": [ "dog", "query" ], "breed" : "poodle" }

{ "is": [ "dog", "list" ]
"list": [ "/on/uid-123-34.json", .. ]
}

The query is like a template for matching objects - "fill in the data
you know you want back in the result entries" - here "breed".

Finally, inlining the results - add a "results" hash with params on the
search, including sort order, pagination, etc. And "inline":

POST /on/uid-654.json

{ "is": [ "dog", "query" ], "results": { "inline": true }, "breed" :
"poodle" }

{ "is": [ "dog", "list" ]
"list": [
{ "is": [ "dog", "animal", "contact" ], "fullName" : "Fluffy",
"breed": "poodle" }
]
}
_ _ _ _ _ _ _ _ _ _ _ _

Happy to field constructive critical comments on any of this! :-)

Cheers!

Duncan

Reply all
Reply to author
Forward
0 new messages