DEV Community

Sumit Kadu
Sumit Kadu

Posted on

Using Json API Specifications to Design and Develop RESTful APIs

What is REST API

REST API is an API which conforms to the Representational State Transfer Architectural style. An API tells us how we can communicate with any service or system and what all operations we can perform on it.

Most commonly, REST APIs are developed and exposed over HTTP protocol. As its HTTP, it responds to the HTTP verbs i.e. GET, POST, PUT, DELETE etc. which is inherently the operations that we can perform using the APIs.

REST APIs are very commonly used to achieve communication between two systems or applications on any platform that support HTTP protocol such as Computers, Phones, Tablets, IoT devices and many more.

Any application that we see or use today on our phones or computers use an API behind the scenes which we usually do not know (or care) about. But it is the heart and soul of the application doing most of the heavy lifting behind the scenes. This makes APIs an integral part of any Architect’s or Developer’s life during and beyond the application development.

Sadly, (although with modern programming languages like .NET core, Java or NodeJS etc. which makes it easy to write an API service almost in minutes…) its hard to develop an API service which is performant, scalable, optimized and in general ticks all or most of the boxes for quality that we look for in API service.

Thankfully, there are frameworks/ architectural patterns and practices available in the community to enable us to design an API which ticks all the desired boxes. I will discuss one such pattern which I have used heavily, it is Json API specifications.

What is JSON API Specification

JSON API is a specification for how a client should request that resources be fetched or modified, and how a server should respond to those requests.

These are set of rules outlined to design REST APIs which when conformed to, can make your REST API a compliant JSON API. I would not get into entire specification here, as its already described on official site.

Why do we need a specification when we know how to write REST APIs

As REST APIs have been there for almost more than 2 decades, we may wonder why we really need to follow a specification to write an REST API.

Well, you don’t unless you came across one or more of situations in your API service:

  1. Developed an API service but it consumed too much of my time explaining usage and format of my APIs to my consumers who code their applications to call my API service.
  2. My API consumers often complain of too much data payload being returned in my API response which makes it hard for clients to parse and get only the needed data.
  3. API returns too many records with little control to consumers on any particular set of records they want to retrieve or a maximum number of records they want to retrieve.
  4. Releasing a new version of API results in heavy development and testing effort.
  5. API is not scalable or easily maintainable i.e. it’s hard to make changes without breaking existing API consumers.

_

Although, all of the above can be achieved by using REST Architectural principles and patterns but still we may often struggle to enforce a certain development standard or practice in our teams when multiple people are developing APIs in parallel (which is almost every time). In these situations, having a standard specification which is universally accepted and agreed upon by the community, makes it easy to explain and adopt by teams.
_

How Json APIs can help design scaleable and maintainable REST APIs

JSON API specifications details out set of rules in detail but I would like to list few features which are very commonly needed in almost every API and how JSON API specification helps in these:

Content Negotiation

It outlines responsibilities from Client and Server or both to negotiate content to be requested/ returned.

Clients and servers MUST send all JSON:API payloads using the JSON:API media type in the Content-Type header.

Clients and servers MUST specify the ext media type parameter in the Content-Type header when they have applied one or more extensions to a JSON:API document.

Clients and servers MUST specify the profile media type parameters in the Content-Type header when they have applied one or more profiles to a JSON:API document.

Uniform schema/ structure of the document

A JSON object MUST be at the root of every JSON:API request and response document containing data. This object defines a document’s “top level”.

A document MUST contain at least one of the following top-level members:
data: the document’s “primary data”.

errors: an array of error objects.

meta: a meta object that contains non-standard meta-information.
a member defined by an applied extension.
The members data and errors MUST NOT coexist in the same document.
A document MAY contain any of these top-level members:

jsonapi: an object describing the server’s implementation.

links: a links object related to the primary data.

included: an array of resource objects that are related to the primary data and/or each other (“included resources”).

Handling Parent/ Child data or linked data (and whether to return it in response)

To understand how Json API specification prescribes describing parent and child resource information, we need to first understand the document structure of the Json API document as described in below link:

Document Structure

Attribute relationships is used when describing related resources.

Link attribute in relationships structure can be used to directly get the related resource information. We may choose to either include data directly in data attribute in relationships or just provide a self, child or parent link to reduce payload in response and allow clients to fetch related resources as and when needed.

Example resource with related resources information and link attribute schema:

// ...
{
  "type": "articles",
  "id": "1",
  "attributes": {
    "title": "Rails is Omakase"
  },
  "relationships": {
    "author": {
      "links": {
        "self": "http://example.com/articles/1/relationships/author",
        "related": "http://example.com/articles/1/author"
      },
      "data": { "type": "people", "id": "9" }
    }
  },
  "links": {
    "self": "http://example.com/articles/1"
  }
}
// ...
Enter fullscreen mode Exit fullscreen mode

For managing for complex related documents, we can make use of compound documents specification as described in below link

Compound Documents

Pagination

It is a most common use case we encounter when designing GET endpoints which returns list of data. To improve API performance, we must use pagination to provide control to clients to request only certain number of items rather than all especially when we have thousands of items to return.

The page query parameter is reserved for pagination. Servers and clients SHOULD use these parameters for pagination operations.

/?page[offset]=0&page[limit]=10

The following keys MUST be used for pagination links in the response which can be used by clients to make subsequence calls to fetch subsequent information.

  • first: the first page of data
  • last: the last page of data
  • prev: the previous page of data
  • next: the next page of data

Filtering/ Sorting

An endpoint MAY support sort query parameter in its request and accept one or multiple parameters value with comma separated.

GET /people?sort=age,name HTTP/1.1

Sparse Field sets

A client MAY request an endpoint to return only specific fields in response. This comes in handy in particular when we are using API endpoints which return many fields in response and we are interested in only a few. The Json API specification helps in specifying only fields that we want to see in response.

For example,

GET /articles?include=author&fields[articles]=title,body&fields[people]=name HTTP/1.1 Accept: application/vnd.api+json

Error Handling

Its very common to receive errors when working with API endpoints. These errors could be server errors or could be application errors. When working with APIs it becomes very important to speak common error language to communicate errors back to the client else it is very difficult to understand what went wrong.

Json API specifications prescribes set of rules for organizing and returning error information in response.

When a server encounters multiple problems for a single request, the most generally applicable HTTP error code SHOULD be used in the response. For instance, 400 Bad Request might be appropriate for multiple 4xx errors or 500 Internal Server Error might be appropriate for multiple 5xx errors.

Error objects provide additional information about problems encountered while performing an operation. Error objects MUST be returned as an array keyed by errors in the top level of a JSON:API document.

An error object MAY have the following members, and MUST contain at least one of:

id: a unique identifier for this particular occurrence of the problem.

links: a links object that MAY contain the following members:

about: a link that leads to further details about this particular occurrence of the problem. When deference, this URI SHOULD return a human-readable description of the error.

type: a link that identifies the type of error that this particular error is an instance of. This URI SHOULD be dereferencable to a human-readable explanation of the general error.

status: the HTTP status code applicable to this problem, expressed as a string value. This SHOULD be provided.

code: an application-specific error code, expressed as a string value.

title: a short, human-readable summary of the problem that SHOULD NOT change from occurrence to occurrence of the problem, except for purposes of localization.

detail: a human-readable explanation specific to this occurrence of the problem. Like title, this field’s value can be localized.

source: an object containing references to the primary source of the error. It SHOULD include one of the following members or be omitted:

pointer: a JSON Pointer [RFC6901] to the value in the request document that caused the error [e.g. "/data" for a primary data object, or "/data/attributes/title" for a specific attribute]. This MUST point to a value in the request document that exists; if it doesn’t, the client SHOULD simply ignore the pointer.

parameter: a string indicating which URI query parameter caused the error.

header: a string indicating the name of a single request header which caused the error.

meta: a meta object containing non-standard meta-information about the error.

Developing JSON API and consuming through client application

After knowing about JSON API specifications, we may think about increased complexity it brings not just about writing an API endpoint that conforms to these specifications but also additional efforts needed to consume it on the client side.

Thankfully, there are many libraries available which can be used to create or migrate existing REST APIs to conform to JSON API specifications and client libraries which can easily parse the JSON API document and help reduce effort needed on the client side.

Below are the available libraries by programming language:

Server Libraries

Client Libraries

Reference

JSON:API — Latest Specification (v1.1) (jsonapi.org)


Moved from medium.com

Top comments (0)