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

Continued from page 6. 

A possible implementation of this solution is to introduce a new resource type Class in the RAML specification. This type will encode the the information of the RAML spec itself. With this resource type defined, we can introduce another new resource of type ApiDocumentation exposing the RAML specification information as yet another resource in the API with its own URI.

#%RAML 1.0

title: Todos Service
baseUri: http://todosapp.com/api/version_6
mediaType: application/json+ld

types:
  URI: string
  Operation:
    method:
      enum: [ GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS ]
    expects: Link
    returns: Link
  Link:
    properties:
      @id: URI
      operations: Operation[]
  Context:
    properties:
      @vocab: URI
  Class:
    @id: URI
    operations: Operation[]
    properties:
      @id: URI
      domain: URI
      range: URI
    links: Link[]
  Resource:
    @id: URI
    @type: URI
  ApiDocumentation:
    @id: URI
    @type: URI
    classes: Class[]
    entryPoint: URI

/spec:
  get:
    description: API specification
    200:
      body: ApiDocumentation
/:
  get:
    description: Entry point for the application
    responses:
      200:
        body: Resource

Now, if we try to retrieve an API resource, we will obtain a much small data graph in the resource representation:

{
  "@context": { "@vocab": "http://todosapp.com/api/vocab#" },
  "@id": "http://todosapp.com/api/version_6/#self",
  "@type": "http://todosapp.com/api/version_6/spec#EntryPoint",
  "users_url": { "@id": "http://todosapp.com/api/version_6/users#self" }
}

The @type keyword in JSON-LD is a way of denoting the type for a typed node in the encoded data graph and it will be expanded to the URI http://www.w3.org/1999/02/22-rdf-syntax-ns#type. If the client now follows the provided @type link, all meta-data for the resource will be retrieved from the server.

It is important to note that types are no longer strings, they are URIs pointing to resources in the same way properties are, that’s the reason we can now connect them with hyperlinks

curl -X GET "http://todosapp.com/api/version_6/spec#EntryPoint
{
  "@context": { "@vocab": "http://todosapp.com/api/vocab#" },
  "@id": "http://todosapp.com/api/version_6/spec#self",
  "@type": "http://todosapp.com/api/version_6/spec#ApiDocumentation",
  "entryPoint": { "@id":"http://todosapp.com/api/version_6/#self" },
  "classes": [
    {
      "@id": "http://todosapp.com/api/version_6/spec#EntryPoint",
      "operations": [
        {
          "method": "GET",
          "returns": { "@id": "http://todosapp.com/api/vocab#EntryPoint" }
        }
      ],
      "links": [
         {
           "@id": "http://todosapp.com/api/vocab#users_url",
            "operations": [
              {
                "method": "GET",
                "returns": { "@id": "http://todosapp.com/api/vocab#Collection" }
              },
              {
                "method": "POST",
                "expects": {
                  "@type": "http://todosapp.com/api/vocab#Class",
                  "properties": [
                    {
                      "@id": "http://todosapp.com/api/vocab#name",
                      "range": { "@id": "http://www.w3.org/2001/XMLSchema#String" }
                    },
                    {
                      "@id": "http://todosapp.com/api/vocab#email",
                      "range": { "@id": "http://www.w3.org/2001/XMLSchema#String" }
                    }
                  ]
                },
                "returns": { "@id": "http://todosapp.com/api/vocab#User" }
              },
            ]
        }
      ]
    }
  ]
}

Both graphs, the data and meta-data graph can be merged into a single unified data-graph in the client that can be queried in the same way as in previous versions.

This distinction between two related ‘planes’ of information, one for data and one for meta-data, is what technically is known as the distinction between the Tbox for terminological box and the Abox for assertional box. From the logical point of view, the first component contains the conceptualisation of the system, the semantics of the data model, the second component contains the data, regarded as assertions over the concepts defined in the Tbox.

API Version 7: Generic Hypermedia API

In the previous version we have transformed the meta-data in our RAML API description into resources and we have exposed them using REST principles to describe the semantics of our API.

Both kind of resources are linked and conform a single data graph that can be discovered and explored by any client that understand the semantics of the control hypermedia.

At this point we no longer need the RAML document, the only thing we require is the URI of the single ‘EntryPoint’ resource.

The main problem of version 6 of the API is that the vocabulary used to describe hypermedia control information and the semantics of the resource types is private to our API.

In order to build a generic hypermedia API client, a truly generic API browser, we would need a standard way describing that information, a common vocabulary for hypermedia in APIs.

Fortunately, an effort to standarised such a vocabulary is currently underway in the W3C. It is called Hydra.

Hydra provides a rich vocabulary for describing hypermedia in APIs. The vocabulary we have used up to version 6 is just a sub-set of Hydra.

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

Comments

Comments(4)

alexsmith84

Great article! I'm currently only learning but i do have some ideas for future projects and i feel like your tips will help me a lot! I'm currently trying to do something with doahomework.com API

jamesrogers84

This seems to look interesting, looking forward for more of these.