How to Take Your API From RPC to Hypermedia in 7 Steps

Hypermedia seems not to be a popular option between API designers these days. On the other hand REST (or RESTful) API design is supposed to be the orthodoxy in API design and implementation.

This is not a surprise since REST, by simple abuse of the term, has become just a concept vaguely related to the use of ‘resources’ and a conventional mapping CRUD operations to HTTP methods.

But REST should be much more than that. Fielding’s thesis was an attempt of systematically describe the network architecture of the Web built on a few key components (HTTP, URI, HTML). The meaning of architecture in REST is just a process of imposing constraints over the many possible ways of building distributed network systems.

Each of these constraints limit the way we can build the system, but at the same time, they make the final result more reliable, extensible, decoupled and able to scale. On the other hand, these same constraints can have a negative impact in other aspects, like raw performance. They are conscious trade-offs.

When building RESTful APIs these days, most of the problems come from the lack of  reliability, fragility, coupling and the lack of scalability.These are the very same problems that REST architectural principles should help us to avoid.

There’s something wrong in our RESTful APIs.

A few months after the first Web server was bootstrapped by Tim Berners Lee at CERN, the Web was already composed of distributed servers linking information between multiple organisations. A couple of implementations of a generic client for the Web were already being written. Both things are still impossible to achieve in the Web of data APIs.

If we look again at the components of the Web, HTTP is the only one we truly embrace. URI and HTML (or a version of HTML for data), and their combined use as hypermedia are lacking in most APIs.

This post tries to explore how hypermedia can be used in API design to fix some of the issues we have mentioned before: fragility, coupling and lack of scalability.

Instead of just discussing abstract notions and enumerating technologies and standards, the approach will be slightly different. We’ll start with a fully RPC API, with almost no other constraints than using the HTTP protocol for data transport, and we will start adding REST constraints through different revisions, trying to understand the trade-offs involved in each small change.

The toy API we will be improving is just another variation of a ‘Todos’ service, where users can register and create and edit lists of Todo notes.

I will use RAML to describe the API, but I could use Swagger/OpenAPI, Blueprints or any other API documentation format.

API Version 0: RPC

The initial version of the API is just a list of RPC operations invoked over the HTTP protocol.

#%raml 1.0

title: Todos Service
baseUri: http://todosapp.com/api/version_0
mediaType: application/json

/usersServiceCreate:
  description: Creates a users
  post:
    body:
      properties:
        email: string
        name: string
    response:
      body:
        properties:
          id: string

/usersServiceList:
  description: Lists all Users
  post:
    response:
      body:
        type: array:
        items:
          properties:
            id: string
            email: string
            name: string

/usersServiceDelete:
  description: Creates a users
  post:
    body:
      properties:
        id: string

/todosServiceCreate:
  description: Creates Todos for a user
  post:
    body:
      properties:
        user_id: string
        todos:
          type: array
          items:
            properties:
              title: string
              description: string
    response:
      body:
        properties:
          id: string

/todosServiceList:
  description: Lists all Todos
  post:
    response:
      body:
        type: array
        items:
          properties:
            id: string
            user_id: string
            title: string
            description: string

/todosServiceDelete:
  description: Deletes todos
  post:
    body:
      id: string[]

There are only two REST restrictions in this design:

  • Client/server architecture: There’s a clear separation between the client side and server side of the service with a well defined boundary between them and clear separation of concerns.
  • Sateless architecture: all requests to the API include all the information required for the service to process the request. There are no dependencies between requests that can be issued in any particular order. Session state is kept in the client.

The API uses the HTTP protocol just as a transport layer for the invocation of remote functions in the server. The semantics of HTTP are ignored, all requests are bound to POST HTTP requests. It doesn’t take advantage of any of the features of the protocol, like caching headers, HTTP is just a convenient mechanism to invoke remote functions.

Antonio Garrote Principal Engineer at Mulesoft in the mornings, researching on RESTful semantic web services in the evenings. Clojure enthusiast all day long.

Comments