Stop Writing REST API Clients.

Why do we keep writing REST API clients over and over again?

  Facebook, Twitter, LinkedIn, Youtube, Instagram, Dropbox, Yahoo ...

This doesn’t scale.


After several years of using and writing REST APIs, it becomes redundant to implement a client in whatever language you use when the need arises to integrate a new service into the application.

REST API best practices are pretty well known and it’s pretty straightforward to design one. You essentially define a list like GET /user, POST /status, GET /search and so on.

A REST API could be described in JSON. As an example, see the JSON below - describing part of the Facebook REST API.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
{
    "name": "fb",
    "api_root": "https://graph.facebook.com",
    "resources": {
        "/me": {
            "methods": [ "get" ],
            "params": [
                {
                    "fields": "optional"
                },
                {
                    "access_token": "required"
                }
            ]
        }
        ...other REST API resources here...
    }
}

The Facebook REST API can be described as a list of resources, with the corresponding HTTP methods to use and the parameters allowed in the request.

The snippet above describes the resource /me, which is located at the URL https://graph.facebook.com/me. The URL can be accessed using the HTTP verb GET, and it accepts two parameters - the optional fields param, and the required access_token param.

Outlining the REST API in JSON allows one to perform application-level request validation - for example it would be trivial to write validation code to make sure that we don’t try to accidentally send off a request to the resource without the access_token, since we know it would fail.

We could do the same with the Twitter REST API - see the JSON below.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
{
    "name": "twitter",
    "api_root": "https://api.twitter.com/1.1",
    "resources": {
        "/statuses/update.json": {
            "methods": [ "post" ],
            "params": [
                {
                    "status": "required"
                },
                {
                    "in_reply_to_status_id": "optional"
                },
                {
                    "lat": "optional"
                },
                {
                    "long": "optional"
                },
                {
                    "place_id": "optional"
                },
                {
                    "display_coordinates": "optional"
                },
                {
                    "trim_user": "optional"
                }
            ]
        }
        ...other REST API resources here...
    }
}

The JSON snippet above defines the Twitter /statuses/update resource (for posting tweets). The rest of the API resources are similarly defined.

Since the APIs are so easily defined in JSON, I whipped up a quick client using node.js that can talk to any REST API that can be defined in JSON similarly to the Facebook and Twitter specs above. I published the client on npm and put it on Github. I called it unio.

You can install it using npm install unio, and start making requests to the Facebook API (I will soon implement the Twitter API with it). You can also import arbitrary JSON specs that look like the ones above. Example usage below:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
var unio = require('unio')

var params = { q: 'coffee', access_token: 'FB_ACCESS_TOKEN' }

// use the Facebook REST API and make a search query

unio()
    .use('fb')
    .get('search', params, function (err, reply) {
        //...
    })

// use the Twitter REST API and post a tweet

unio()
    .use('twitter')
    .post('statuses/update', { status: 'hello world' }, function (err, reply) {
        //...
    })

// import a new REST API definition and query it

unio()
    .spec(jsonSpec)
    .use('my-new-api')
    .get('some/url', { foo: 'bar' }, function (err, reply) {
        //...
    })

The idea of describing a web service in a machine-readable format is not new. For example, there is Web Services Description Language, which is an XML language used to describe the functionality offered by a web service.

There is nothing inherently wrong with WSDL - it gets the job done and has been used widely in the past. I simply advocate that we use a simplified JSON spec like the one above to describe REST APIs - this allows us to implement clients like unio, making the time required to test, use and re-use REST services minimal.

No matter what, nothing changes - there is always something to be kept up to date. Generally, REST services publish API docs online and delegate the writing of the client code to you. Instead, I propose keeping the JSON spec up-to-date (and even auto-generate your documentation) to avoid having to keep multiple things up-to-date. Then use a client that can auto-generate the code to talk to the service. I’d rather spend the time keeping a JSON file up-to-date than write a new REST API client each time a new online service pops up. Less work, more time playing with APIs.

So I propose that we build a list of JSON documents describing as many REST APIs as possible. We can then import these specs as needed into a simple client like the one I wrote above, and start making HTTP requests without wasting time implementing yet another REST API client. To help out and add more JSON API specs, fork and submit a pull request on the Github page for unio. I invite anyone and everyone to message me and collaborate to add more!

Find me on: Github and Twitter.