Building APIs With JSON API

Introduction

In this post we will explore the JSON API format and how it can be used to make interacting with your API consistent and easy. Modern applications usually consume a central API that can be used across many different interfaces, i.e., a web app, iOS/android app, and desktop app. Many times our JSON data structure isn’t formally specified and therefore can lead to more internal network code. Not to mention can be a point of confusion when working on a team of developers, which is often the case. Building APIs with JSON API enforces a standard format for our request/response body payload and by following shared conventions can increase productivity.

Building APIs With JSON API

 

What does JSON API get us?

Recently we started moving more of our frontend React development from using Backbone as its data counterpart to using a Flux architecture. With a small library we build in house (still backed by Backbone for now, but that’s on its way out) we can define Flux stores that hold models, collections, or sometimes just shared component state that is not persisted to the backend.

Here at Revelry we became a bit dissatisfied with the way our data graph was represented in a traditional set of single-resource JSON services. JSON API improves on this in a number of ways.

The frontend needs to know much less about the data types and relationships in advance.

We no longer need to know that the response from /orgs/15 contains an Organization model. It tells us that it gave us type ‘org’ with ID 15. It also tells us that it has a relationship ‘members’ with a URI /orgs/15/members.

You can ask a JSON API, in your request, to include relationships. So from the previous example, I can tell it to include ‘members’. Having fewer follow-up requests takes some load off the server and makes the experience for users feel faster.

Filtering, sorting, and paginating data becomes easier.

It is good practice for a web service call to never return unbounded data (give me everything in this collection). The JSON API spec makes it relatively easy to include filter/sort/paginate functionality in any request.

What does it look like?

This is the format that makes it all tick (example taken from jsonapi.org):

{
  "links": {
    "self": "http://example.com/posts",
    "next": "http://example.com/posts?page[offset]=2",
    "last": "http://example.com/posts?page[offset]=10"
  },
  "data": [{
    "type": "posts",
    "id": "1",
    "attributes": {
      "title": "JSON API paints my bikeshed!"
    },
    "relationships": {
      "author": {
        "links": {
          "self": "http://example.com/posts/1/relationships/author",
          "related": "http://example.com/posts/1/author"
        },
        "data": { "type": "people", "id": "9" }
      },
      "comments": {
        "links": {
          "self": "http://example.com/posts/1/relationships/comments",
          "related": "http://example.com/posts/1/comments"
        },
        "data": [
          { "type": "comments", "id": "5" },
          { "type": "comments", "id": "12" }
        ]
      }
    },
    "links": {
      "self": "http://example.com/posts/1"
    }
  }],
  "included": [{
    "type": "people",
    "id": "9",
    "attributes": {
      "first-name": "Dan",
      "last-name": "Gebhardt",
      "twitter": "dgeb"
    },
    "links": {
      "self": "http://example.com/people/9"
    }
  }, {
    "type": "comments",
    "id": "5",
    "attributes": {
      "body": "First!"
    },
    "links": {
      "self": "http://example.com/comments/5"
    }
  }, {
    "type": "comments",
    "id": "12",
    "attributes": {
      "body": "I like XML better"
    },
    "links": {
      "self": "http://example.com/comments/12"
    }
  }]
}

Notice our author links object contains two sets of links. The self link points to the actual relationship itself and allows us to do things like remove/edit the related data. The related link is one that, if requested, would return the related resource as the primary data. This structure is self-documenting and allows the client side developer to fetch, update, and destroy related data without knowing the particular endpoints beforehand. Just as a browser traverses the web through a network of links, so can our client side app traverse through our relation data. This idea is illustrated through level 3 of the Richardson Maturity Model.

Conclusion

The JSON API specification is gaining traction as major frameworks start to adapt the standard. Ember Data 2.0 has been rewritten to make us of the JSON API format along with efforts to include the format in the rails-api gem and ActiveModel::Serializers. It will be exciting to see how JSON API spec holds up now that it is being applied to real-world problems. For more details on the full JSON API spec, go read it. As specs go, it’s pretty easy to follow.

One more thing if you’re on Rails

The jsonapi-resources gem is absolutely fantastic and will make writing your backend a joy.

More Posts by Jarrod Rotolo: