----- Original Message -----From: jefshockSent: Wednesday, March 28, 2012 4:56 PMSubject: 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/34and response...{"dog": {"uri": "/v1/dogs/34","id": 34,"name": "fido"}}
-MikeHaving 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.
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