When I work with Ruby on Rails, I always look for conventions to follow as it makes it easy to get things done. This means I have less code to manage and it also helps new developers to understand the code better.
However, in the past I’ve found it harder to follow conventions around API payloads and I’m often left wondering “What is my front-end team expecting the payload format to be?” It would be a huge help if something could guide the process in resolving these conflicts.
Ta Da… JSON-API is here.
JSON-API speeds up the development process by guiding the way we structure an API. Developers who have worked on Ruby on Rails or Ember and remember the idea of “convention over configuration” will find JSON-API quite similar.
The Old Way
I love the way Rails understands nested forms for associated models. The conventions are usually compelling enough to convince any team to implement it “the Rails way”. However it can be painful to create a matching payload on the frontend. JSON-API resolves the conflicts by advising how requests should be sent from the client to fetch or modify a resource and how the servers should send back the responses.
Let’s take an example where I need to GET an existing user record with its related contacts. Here I have a User with a “has_many :contacts” relationship, and two possible solutions:
I can add a new top-level key to return user contacts.
<code class="language-json">
{
"user":{
"id":"2",
"name":"Jane Doe",
"email":"jane.doe@gmail.com"
},
"contacts":[
{
"id":"1",
"name":"Contact Name",
"mobile":"+91-9191919191",
"user_id":"1"
}
]
}
What if I combine the contacts information with the existing response?
<code class="language-json">
{
"user":{
"id":"2",
"name":"Jane Doe",
"email":"jane.doe@gmail.com",
"contacts":[
{
"id":"1",
"name":"New Contact",
"phone_number":"+91-9191919191"
}
]
}
}
How do you verify which approach is better to use? And what will my frontend pals think about the response structure? I’m sure there are cases for either approach but it can be tricky to decide up-front.
The New Way
Let’s follow JSON-API rules to create the User response that returns all of the necessary details about the object and its relationships:
<code class="language-json">
{
"data":{
"id":"1",
"type":"users",
"links":{
"self":"http://localhost:3000/users/1"
},
"attributes":{
"name":"Jane Doe",
"email":"jane@doe.com"
},
"relationships":{
"contacts":{
"links":{
"self":"http://localhost:3000/users/1/relationships/contacts",
"related":"http://localhost:3000/users/1/contacts"
},
"data":[
{
"type":"contacts",
"id":"1"
}
]
}
}
},
"included":[
{
"id":"1",
"type":"contacts",
"links":{
"self":"http://localhost:3000/contacts/1"
},
"attributes":{
"name":"New Contact",
"mobile":"+91-9191919191",
"address":"Address line 1",
"email":"new_contact@gmail.com"
},
"relationships":{
"user":{
"links":{
"self":"http://localhost:3000/contacts/1/relationships/user",
"related":"http://localhost:3000/contacts/1/user"
}
}
}
}
]
}
We know from past experience that by agreeing on sensible a standardization, developers like us can focus better on the design of the application without getting bogged down in the specifics of the implementation. These conventions encourage the teams to use the JSON-API standards to build API products without conflicts, rather than reinventing the wheel by defining their own API protocols every time.
JSON-API provides conventions for the following:
- Represent a single resource or a collection of resources with relationship
- Include primary and related resources in a single document
- Links for resources, relationships and paginated collections
- CRUD for resources and relationships
- Sort, filter and paginate resources
- Error status with details
Here is a sample Rails 5 application with JSON-API. I used the gem “jsonapi_resource” which provides us “JSONAPI::Resources” to easily support JSON-API spec.
“ActiveModel::Serializers” don’t deserialize JSON API. They do not focus on the resources. This gem overcomes the problem. It is not fully compatible with Rails 5. We’ve forked the gem and submitted PR to contribute to make it a little better.
If you’re wondering whether JSON-API will gain enough community traction to be a useful standard, these statistics from the github repo give us a hint of the direction it’s heading in:
- 3437 stargazers on the JSON-API spec
- 387 Forks
- 1 Watchers
- 141 Contributors
Where to find out more
You may find the following websites interesting to further understand the usefulness of JSON-API:
- JSON-API parser available in Ruby
- One lightweight JSON-API engine available here that exposes data via RESTful routes
- http://jsonapi.org
- https://github.com/json-api/json-api
- https://github.com/cerebris/jsonapi-resources
- http://www.cerebris.com/blog/2015/06/04/jsonapi-1-0/