Paradigm X

Vision quests of a soulhacker

A Brief Guide of (RESTful) SOA, Part II

In the first part of this series we have discussed the core concepts of RESTful architectural style and gives some guideline in how to define the system and prepare for defining the APIs specs, which will be covered in this part.

Level III: Define and Tune the API

Defining API specs is the most important part of all and it’s a continuous progress in the whole lifecycle, mostly documentation oriented. A simple and neat document collaboration platform is very useful. I suggest facilitating tools such as MediaWiki or Markdown + GitHub etc. Then you can follow these sections below.

3.1 API Basics

Use one or two pages to list basic information of the API system, including (but not constrained to):

  • General: general style and policy, versioning, request and response methods, i18n, etc.
  • Authorisation: step by step tutorial on connecting to the service (see section 3.2 below).
  • Request: all acceptable request formats w/ examples.
  • Response: response format w/ examples, error codes.
  • Misc: rate limits, auditing, etc.

3.2 One Token to Rule Them All

Remember that for most developers using your APIs the most tricky part is the authentication and authorisation. For some reasons (compromise of security, performance and convenience) most web service systems use token to identify service clients. Here are some fundamental concepts:

  • Service, or the platform is the system hold the key resources and make resources accessible via some open APIs.
  • Client, or app is client application sending request to the service.
  • Each of every client should register itself on the service platform and gain a pair of CLIENT_ID and CLIENT_SECRET to identify itself.
  • After registration apps can request tokens from the platform
  • There are 2 types of services in most platform: (A) services related to a specific user in the platform; (B) services independent to users. They need different kinds of tokens:
    • For type (A): app should use its CLIENT_ID/CLIENT_SECRET, correlated user’s ID and expected access profile (commonly called ‘scope’) to request the access token.
    • For type (B): app should use its CLIENT_ID/CLIENT_SECRET and scope to request the access token.
  • As long as the access token issued to the app, app can use it to request designated service APIs, until the token expires or revoked by platform or app or the user.

In many cases the platform cannot issue type (A) token to an app unless correlated user explicitly approve the request. That’s where OAuth-like mechanisms make sense. In such cases, when platform receives request for issuing a token to some user, it will redirect the user to a page showing Approve/Decline buttons and continue the flow after the user explicitly approve the request. For detail info about the widely uses OAuth v2 protocol refer to the official IETF RFC6749 document.

A platform should choose mechanism wisely and make the flows (app registration, token issuing/revoking/managing, etc.) clean, flexible and friendly to all potential client apps. Useful tutorials about all these flows are required.

3.3 API Taxonomy

An API taxonomy can help to organise all APIs. It gives you and your clients’ developers very clean and structural view of your continuously evolving APIs. It also gives you a way to normalise the API endpoints’ URI patterns.

API taxonomy is highly dependent to the business. But some general rules certainly helps:

  1. The response objects, which are defined in the first part of this article, are usually the first dimension of the taxonomy.
  2. The second dimension is usually related to the API URI patterns, which will described below.

So let’s look at some typical RESTful URI patterns.

  • Object
    • /:type e.g. /user: Request this URI by POST will create a new object of designated type and return the object if succeeded.
    • /:type/:id e.g. /user/2234: Request this URI by GET PUT DELETE will fetch, change or delete designated object.
  • Query
    • /:type/:catalog e.g. /user/all /user/query?name=foo: Return one or more objects of designated type (using criteria in query string if needed).
  • Aspect or Attribute
    • /:type/:id/:aspect e.g. /user/1532/friends /user/1532/pets: Return zero or more objects of some type related to designated object. In our examples, user #1532’s friends should be zero or more user objects, and user #1532’s pets should be zero or more pet objects.
  • Action
    • /:type/:id/:action e.g. /user/1532/follow /user/1532/report: Perform certain action (follow somebody or report them as spam) to designated object.

As you can see, The last pattern is not so RESTful. A far more RESTful way to do things like following somebody may be: define an object type relationship and provide POST /relationship (with user A and B as parameters) to add a new relationship.

All I can say is that both ways will work fine in most systems and I leave the decision up to you.

Using object type and pattern as two dimensions of the API taxonomy is a very good start point. Almost all RESTful web service systems can put API endpoints into a matrix like below:

Object Query Aspect Action
user search friends pets follow
pet search cats dogs master cousins gift
house search residents  

Well, some special APIs will be hard to classify. Here are the most commonly used two (we won’t discuss more, just list them here):

  • compound: combine several API requests into a batch and response the batch results altogether.
  • realtime or stream: stream realtime activity logs to the client, which needs very different mechanism to work out.

3.4 API Specs

For every endpoints in the API matrix you need a consistent and clean spec which follows these rules:

  • Endpoint: basic info for calling the endpoint (complete URI, HTTP verbs, security options, etc.).
  • Parameters: list of all parameters, each of which should include name, example, description, required or optional and other useful information.
  • Response: all data fields in the response data. Each fields can be some plain value or a pre-defined business object structure, as described in the first part of this article.
  • Examples: clickable examples of calling this endpoint (see section 3.5 below).

Here is a good documentation example from foursquare platform: create a check-in.

3.5 Test the Specs

To give app developers’ and yourself a better life, you need an API test console from the first day. It can be a command line tool or a GUI tool or, the easiest and most convenient way, a browser based tool. In the test console user can input token and API endpoint, choose HTTP verb, input parameters and get 100% real response data, in nicely formatted JSON format. It can save tons of time and money. Have a look at foursquare’s online API explorer for some real world example.

Further more, an automatic regressive testing solution should be considered as early as possible. Web services are entries of your business and API implementation will surely be in a continuously developing progress. After any changes a series of strict tests must be automatically executed to confirm that all APIs are still working as intended. Use a high productivity dynamic language such as Ruby or Python to write a simple but complete client lib for your APIs and build test case for every defined API endpoints. Personally I like Ruby w/ RSpec but many other languages and frameworks also work fine.

To be continued…

In the final part of this series we will talk about implementation of the API specs.