Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Root object or no? What is the best practice for API responses?

What is the best practice for JSON response data, nest the object within a parent object and include the root keypath or not?

{
    "activity": {
        "id": 20,
        "description": "a nice walk",
        "time_occurred": "2013-07-15T22:10:23Z",
        "duration": 45,
        "distance": 4.24,
        "location":"McDonalds"
    }
}

OR

{
    "id": 20,
    "description": "a nice walk",
    "time_occurred": "2013-07-15T22:10:23Z",
    "duration": 45,
    "distance": 4.24,
    "location":"McDonalds"
}

Seems like most HTTP frameworks (RestKit, GSON, etc) can handle either case, but I'd love to have a definitive answer on which approach is better and why. I feel like the first approach is more descriptive, which is always good, but the second approach is more lightweight and you should already know what object to map to based on the url path.

Note: I'm asking with specific reference to mobile app backends.

like image 691
Kyle Clegg Avatar asked Aug 23 '13 20:08

Kyle Clegg


2 Answers

a) Root key that describes the resource/collection

This has the benefit of extra context in the response. The root key describes the resource or collection. I personally like this approach because it's obvious what the response document is describing -- you may argue that it's obvious from the endpoint, but this isn't always the case.

b) No root key that describes the resource/collection

This approach is more common in the wild. APIs that need to be high availability and fast will often strip out unnecessary data from the response document to reduce server load and request size. This typical of popular APIs that others look at when designing their own, and so you see it emulated for APIs that don't operate under the same conditions.

I don't buy the argument that lack of a root key makes the response easier to work with. It's an insignificant amount of effort to fetch data from a JSON object nested one level deep.

c) Root key is "data"

When this question was posted, the JSON API specification had not yet reached v1.0 which means breaking changes were likely to occur. If you view their (stable) specification now, you'll see that their stance on the root key has changed.

The proposal for v1.0 Release Candidate 2 changed the top-level key to "data".

Primary resources MUST now appear under the top-level "data" key.

Take for example this singular resource

{
  "data": {
    "type": "articles",
    "id": "1",
    "attributes": {
      "title": "The best article of all time",
      "author": "Kanye West"
    }
 }

I couldn't find the reason behind this, but I suspect it's because of consistency. No matter the resource, one can always fetch data from the document response because the top-level members are consistent, assuming the API follows the JSON API v1.0 specification.

like image 150
Dennis Avatar answered Sep 28 '22 19:09

Dennis


Looks like both sides have traction.

In Favor of root elements

According to JSONAPI.org

Its root key MUST be the same as the root key provided in the server's response to GET request for the collection.

For example, assuming the following request for the collection of photos:

GET /photos

HTTP/1.1 200 OK
Content-Type: application/json

{
  "photos": [{
    "id": "1",
    "title": "Mustaches on a Stick"
  }]
}

In favor of no root element

Twitter does not when it uses a settings object

{
    "always_use_https": true, 
    "discoverable_by_email": true, 
    "geo_enabled": true, 
    "language": "en", 
    "protected": false, 
    "screen_name": "theSeanCook", 
    "show_all_inline_media": false, 
    "sleep_time": {
        "enabled": false, 
        "end_time": null, 
        "start_time": null
    }, 
    "time_zone": {
        "name": "Pacific Time (US & Canada)", 
        "tzinfo_name": "America/Los_Angeles", 
        "utc_offset": -28800
    }, 
    "trend_location": [
        {
            "country": "United States", 
            "countryCode": "US", 
            "name": "Atlanta", 
            "parentid": 23424977, 
            "placeType": {
                "code": 7, 
                "name": "Town"
            }, 
            "url": "http://where.yahooapis.com/v1/place/2357024", 
            "woeid": 2357024
        }
    ], 
    "use_cookie_personalization": true
}

Instagram uses a combination of data and metadata, but does not use a root user object

{
  "meta":  {
    "code": 200
  },
  "data":  {
    "username": "obama",
    "bio": "",
    "website": "",
    "profile_picture": "http://images.ak.instagram.com/profiles/anonymousUser.jpg",
    "full_name": "",
    "counts":  {
      "media": 30,
      "followed_by": 113,
      "follows": 130
    },
    "id": "2082346"
  }
}
like image 34
jpotts18 Avatar answered Sep 28 '22 21:09

jpotts18