Top-level Nested JSON Object in REST… Or Not?

The question came up recently, in our REST representations in JSON, should we have a top-level nesting of objects?

{“user”:{“name”:”fred”}}

or just

{“name”:”fred”}

At previous shops, I’ve always had the top-level nested element. Usually that was an artifact of JAXB. But I think we can make it work either way. So we talked about it a bit, and I pointed out that the nested element is one way to handle polymorphic lists in JSON. Since JSON is untyped, polymorphic lists can be hard.

Polymorphic Lists in JSON

Inside the document, one thing we’re doing to enable polymorphic lists of items is to contain the lists inside properties. Since JSON is untyped, a client can’t tell how to unmarshal a list like:

{ “things”: [ {“name”:”Fred”}, {“color”:”red”}, {“value”:123} }

That’s a case where extra redundancy is necessary to help the client unmarshal the objects into the right classes. It just drops into mashalling libraries like Jackson with no additional work:

{ “things”: [{“person”:{“name”:”Fred”}}, {“balloon”:{“color”:”red”}}, {“voucher”:{“value”:123}}] }

I can’t really claim credit. I just found a site discussing the different approaches to polymoprhic lists in JSON, and also thought that one was the least trouble.

Using Metadata

The other approaches involved adding some sort of “type” property to the object. There’s a couple reasons I’m hesitant to get started on the “JSON metadata path”:

* There are some emerging standards for hypermedia based on JSON, and they have varying conventions for metadata properties. For example, some like to prefix the metadata properties with “_”, like “_link” or “_type” etc. Also, some of them push the metadata into a sub-object like “_meta: {…}” or somesuch.

* I’m a little worried that we get into the same cases with JSON metadata that we have with headers: that everyone wants to add their own. So a simple user object like {“name”:”Bob”; “id”:”http://…”} turns into a 1K blob of JSON with all the metadata fields.

The Answer

I eventually made the proposal that the top-level nested element isn’t necessary, using this strategy:

* Use plain JSON where the client knows the type of the object.

Top-level type is known because client requested a User resource /service/v1/users/1234

{“username”:”bobtompson”,”id”:”…”}

List of scalars (pardon my perl):

[1,2,3]

List of like objects

“namevalues”:[{“name”:”value”},{“name”:”value”}]

* When the client is not able to infer the type of the object, use the nested identifier
“vehicles”: [{“truck”:{“vroom”:”vroom”}}, {“car”:{“beep”:”beep”}}, {“spaceship”:{“fwoosh”:”fwoosh”}}}

* A REST purist would claim that the type is not known in ANY response. However, we can provide that information in content negotiation. So if the user has “Accepts: application/json”” they get:

Content-type: application/json
{“username”:”bobtompson”,”id”:”…”}

But if they request: “Accepts: vnd.expedia.api; type=User”

Content-type: vnd.expedia.api; type=User
{“username”:”bobtompson”,”id”:”…”}

(…and now the type is known because they requested it and we told them.)

Then we’ll just save implementation of the last part until someone asks for it. 😉

Advertisements

Leave a comment

Filed under open standards, opinionizing, REST

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s