Lately, I have been in many discussions where I had to make a case for hypermedia. I have found that the easiest way to introduce folks to hypermedia is to just claim that their APIs are at a "lower maturity level" (usually L2) and point them to Richardon's Maturity Model.
What I have also found is that, while the general concept of hypermedia makes sense for some people, it is hard for them to understand what that means in practice *.
* I don't blame them. There is very little on the subject in concrete terms (e.g. existing robust hypermedia APIs working in production code in a reasonably large corporation).
I thought that, if I showed them what their APIs would look like as if they were web pages, they'd get insulted enough to re-consider :) So, here it goes :)
Level 0: The Swamp of POX
Very rarely I'd come across a L0 API in my daily job, but I understand there are a bunch of enterprise code that uses SOAP. At this level, your API calls go through one endpoint and you are only using one HTTP method.
POST / HTTP/1.1 Host: www.example.org Content-Type: application/soap+xml; charset=utf-8 Content-Length: 299 SOAPAction: "http://www.w3.org/2003/05/soap-envelope" <?xml version="1.0"?> <soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope"> <soap:Body> <m:ScheduleAppointment xmlns:m="http://www.example.org/doctors"> <m:DoctorId>123</m:DoctorId> </m:ScheduleAppointment> </soap:Body> </soap:Envelope>
This what your API looks like, seem from the perspective of the web for humans:
http://example.org/index.txt
- Tuesday, 05/02
- Wednesday, 05/03
If you'd like to make an appointment, please, take your browser window and append act=create and doc=123 and slot=05/02 to our web site!
Welcome to my website!
Here are some doctors available:
Mr. Jones and his ID is 123. He has the following available slots:
- Wednesday, 05/03
If you'd like to make an appointment, please, take your browser window and append act=create and doc=123 and slot=05/02 to our web site!
K THX BYE XOXO
As you could've imagined, all interactions with this website is via its root page. There is just index.txt and that HTTP servlet does it all.
It is also notable that the entire website is in a .txt file, as opposed to a hypermedia media type like .html. What that means is that the website is instructing you to manually construct their URLs to carry on. I know, right!
http://example.org/index.txt?act=create&doc=123&s=05/02
Because you are not using HTTP in its entirety (e.g. you are creating a reservation slot with a GET), you don't get the benefits that a HTTP client gives you (e.g. warning a user whether they want to re-submit the data when refreshing a page after a POST).
Level 1: Resources
This is a slightly more common case, but I still very rarely find this on my day job.
GET /doc/123/slots/05/02.txt?action=create HTTP/1.0 Host: example.comAt this level, you are breaking up your API in multiple resources but still using just one HTTP method.
http://example.org/index.txt
Because you are not using hypermedia (e.g. links), you are still making your users construct their URLs by hand. They get IDs from you, look at your documentation and construct the next step.
http://example.org/doc/123.txt
Hi! Welcome to doctor Jones appointment page! Here are the appointments available:
- Tuesday, 05/02
- Wednesday, 05/03
If you'd like to make an appointment, append /slots/ and the date you'd like to schedule!
I know, seriously, right!
Hi! Welcome to doctor Jones appointment page! Here are the appointments available:
- Tuesday, 05/02
- Wednesday, 05/03
If you'd like to make an appointment, append /slots/ and the date you'd like to schedule!
http://example.org/doc/123/slots/05/02.txt
Hi! Welcome to doctor Jones appointments for 05/02!
If you'd like to make an appointment, append a ?action=create to this page to create!
Really? OK, I guess ...
Hi! Welcome to doctor Jones appointments for 05/02!
If you'd like to make an appointment, append a ?action=create to this page to create!
http://example.org/doc/123/slots/05/02.txt?action=create
This is a step forward, albeit quite a small one. Breaking down your API into multiple resources gives you things like addressability (e.g. you can forward links to people now!) and a more scalable load balancing approach.Level 2: HTTP Verbs
Now, this is where I'm almost sure you are at if you are reading this. You pay your taxes, you eat your vegetables and you went to an ivy league school. You are trying your best to be RESTful and you have an open mind.You spent countless hours breaking up your resources into a layout that makes sense, each resource supports very specific verbs ("even PATCH and DELETE" you say, proudly!) and yet ... I'm comparing your API to a website circa 1990.
GET / HTTP/1.0 Host: example.com HTTP/1.0 200 OK Content-Type: text/json { "doctors": [{ "name": "Dr. Jones", "id": "123" }] }
The problem is ... you are using a .txt file, like JSON or XML.
This is what your API look like:
http://example.org/doc/123/slots/05/02.txt
The issue here is that you are using out-of-band information to tell users what your API affords. You are literally asking them to "read your page" and "construct a POST request" in English, rather than something that the browser can understand (e.g. a <form>).This applies to links (<a> tags) too, which you are making your clients construct by reading English.
http://example.org/doc/123/slots/05/02.txt
You don't run into double-submission problems anymore (as the browser is now aware that a POST is different than a GET, and hence will ask the user whether they really want to re-submit a non safe operation).
But your API still looks like it was built by a 1990-webmaster.
Level 3: Hypermedia
Welcome to the new world :) Or not so new, if you count the fact that this has been known since the invention of the web :)
Let me introduce you to two breakthrough technologies: <a> tags and <forms>!
What hypermedia media types (e.g. HTML) does is to intermingle data and control into the same message, providing a non-linear form of reading.
Now, instead of you having to explain to your users where to go next in English, you can create <a> tags to point them to the right place.
You can also use <forms> to allow write-transitions.
There is no manual your users need to use to browse your API. There is no out-of-band information: the message has both data and control to help you transition to the next place.
Let me introduce you to two breakthrough technologies: <a> tags and <forms>!
What hypermedia media types (e.g. HTML) does is to intermingle data and control into the same message, providing a non-linear form of reading.
Now, instead of you having to explain to your users where to go next in English, you can create <a> tags to point them to the right place.
You can also use <forms> to allow write-transitions.
There is no manual your users need to use to browse your API. There is no out-of-band information: the message has both data and control to help you transition to the next place.
GET / HTTP/1.0 Host: example.com HTTP/1.0 200 OK Content-Type: text/ld+json { "@context": "schema.org", "@type": "Clinic", "@id": "http://example.com/", "doctors": [{ "@type": "Doctor", "@id": "http://example.com/doctors/123", "name": "Dr. Jones", "appointments": { "@type": "AppointmentBook", "@id": "http://example.com/doctors/123/slots", "action": { "@id": "http://example.com/doctors/123/slots", "@type":"ScheduleAction" } } }] }This is what your API would look like at this stage:
http://example.org/index.html
Your users are now able to click on links to go to the next step, because browsers know how to interpret anchor tags.
http://example.org/doc/123/slots/05/02
Your users are now able to schedule appointments by filling a form, since your browser understand forms.
OK, but where do I go from here?
Just follow your nose :) There are plenty of trade-offs to be made here but at least you hopefully learned something new.And, honestly, L3 APIs still have a long way to go, so join us and come be part of the discussion!
You can find out more about this here:
- ROWS
- And related efforts
(Ha! You thought I would give you instructions on how to construct those URLs by hand didn't you?)