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

Continued from page 7. 

We could rewrite our ApiDocumentation class to use Hydra to describe the API so any generic Hydra browser could consume it:

curl -X GET "http://todosapp.com/api/version_7/
{
  "@context": { "@vocab": "http://todosapp.com/api/vocab#" },
  "@id": "http://todosapp.com/api/version_7/#self",
  "@type": "http://todosapp.com/api/vocab#EntryPoint",
  "users_url": { "@id": "http://todosapp.com/api/version_7/users#self" }
}
curl -X GET "http://todosapp.com/api/version_7/spec#EntryPoint
{
  "@context": {
    "hydra": "http://www.w3.org/ns/hydra/core#"
  },
  "@id": "http://todosapp.com/api/vocab#self",
  "@type": "hydra:ApiDocumentation",
  "hydra:entryPoint": { "@id":"http://todosapp.com/api/version_7/#self" },
  "hydra:supportedClass": [

    {
      "@id": "http://todosapp.com/api/vocab#User",
      "@type": "hydra:Class",
      "hydra:supportedOperation": [
        {
          "hydra:method": "GET",
          "hydra:returns": { "@id": "http://todosapp.com/api/vocab#User" }
        },
        {
          "hydra:method": "DELETE"
        }
      ],
      "hydra:supportedProperty": [
        {
          "hydra:property": {
            "@id": "http://todosapp.com/api/vocab#name",
            "rdfs:range": "xsd:string"
          },
          "readonly": false,
          "required": false
        },
        {
          "hydra:property": {
            "@id": "http://todosapp.com/api/vocab#email",
            "rdfs:range": "xsd:string"
          },
          "readonly": false,
          "required": true
        },
        {
          "hydra:property": {
           "@id": "http://todosapp.com/api/vocab#todos",
           "@type": "hydra:Link",
           "hydra:supportedOperation": [
             {
               "hydra:method": "GET",
               "hydra:returns": { "@id": "hydra:Collection" }
             },
             {
               "hydra:method": "POST",
               "hydra:expects": { "@id": "http://todosapp.com/api/vocab#Todo" },
               "hydra:returns": { "@id": "http://todosapp.com/api/vocab#Todo" }
             },
           ]
          }
        }
      ]
    },

    {
      "@id": "http://todosapp.com/api/vocab#Todo",
      "@type": "hydra:Class",
      "hydra:supportedOperation": [
        {
          "hydra:method": "GET",
          "hydra:returns": { "@id": "http://todosapp.com/api/vocab#Todo" }
        },
        {
          "hydra:method": "DELETE"
        }
      ],
      "hydra:supportedProperty": [
        {
          "hydra:property": {
            "@id": "http://todosapp.com/api/vocab#title",
            "rdfs:range": "xsd:string"
          },
          "readonly": false,
          "required": true
        },
        {
          "hydra:property": {
            "@id": "http://todosapp.com/api/vocab#description",
            "rdfs:range": "xsd:string"
          },
          "readonly": false,
          "required": false
        },
        {
          "hydra:property": {
           "@id": "http://todosapp.com/api/vocab#user",
           "@type": "hydra:Link",
           "hydra:supportedOperation": [
             {
               "hydra:method": "GET",
               "hydra:returns": { "@id": "http://todosapp.com/api/vocab#User" }
             }
           ]
          }
        }
      ]
    },

    {
      "@id": "http://todosapp.com/api/vocab#EntryPoint",
      "@type": "hydra:Class",
      "hydra:supportedOperation": [
        {
          "hydra:method": "GET",
          "hydra:returns": { "@id": "http://todosapp.com/api/vocab#EntryPoint" }
        }
      ],
      "hydra:supportedProperty": [
         {
           "hydra:property": {
             "@id": "http://todosapp.com/api/vocab#users_url",
             "@type": "hydra:Link",
             "hydra:supportedOperation": [
              {
                "hydra:method": "GET",
                "hydra:returns": { "@id": "hydra:Collection" }
              },
              {
                "hydra:method": "POST",
                "hydra:expects": { "@id": "http://todosapp.com/api/vocab#User" },
                "hydra:returns": { "@id": "http://todosapp.com/api/vocab#User" }
              },
            ]
           }
        }
      ]
    }
  ]
}

Additionally, we will introduce another discovery mechanism in our server, we will include a HTTP Link header as described in RFC5988 and prescribed in Hydra recommendation draft to make clients aware of the location of the meta-data graph:

Link: <http://todosapp.com/api/vocab>; rel="http://www.w3.org/ns/hydra/core#apiDocumentation"

Now we have a truly generic hyper-media enabled API.

This is just a starting point. Since we have support for the same powerful architecture that powers the web in our API, we can use it to change the way we address a number of problems in APIs: client identity, authentication, ACLs, validation, API integration and clients collaboration, all these problems could be solved in a truly de-centralised and scalable just relying in the support for hypermedia and meta-data this architecture for building APIs enable.

This article was republished with  permission of the author. The original article can be viewed here.

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.