What Your API Would Look Like As A WebPage

... or, do you really want to write your API in .txt?

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.

Content-Type: application/soap+xml; charset=utf-8
Content-Length: 299
SOAPAction: ""
<?xml version="1.0"?>
<soap:Envelope xmlns:soap="">
    <m:ScheduleAppointment xmlns:m="">

This what your API looks like, seem from the perspective of the web for humans: 
Welcome to my website!

Here are some doctors available:

Mr. Jones and his ID is 123. He has the following available slots:

- 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!


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! 
Appointment slot created!

Please, don't reload this page, or else we'll create another appointment! Just go away :)

Thanks for your business!

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

At this level, you are breaking up your API in multiple resources but still using just one HTTP method.
Hi Welcome to our website! Here is our directory of doctors:

- Mr. Jones and his ID is 123.

If you'd like to make an appointment, please, take your browser window and append doc/ and the doctor ID to our web site!

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.

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 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 ...
Appointment slot created! Thanks!

Please, don't reload this page, or else we'll create another appointment! Just go away :)

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

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:
If you'd like to make an appointment, send a POST request to this page to create! As parameters, send a slot=7pm or 8pm which are available!

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


This applies to links ( tags) too, which you are making your clients construct by reading English.
Appointment slot created! Thanks! Feel free to reload this page, your browser will know what to do and ask you if you want to re-submit the data!

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: tags and !

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 tags to point them to the right place.

You can also use 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

HTTP/1.0 200 OK
Content-Type: text/ld+json
  "@context": "",
  "@type": "Clinic",
  "@id": "",
  "doctors": [{
    "@type": "Doctor",
    "@id": "",
    "name": "Dr. Jones",
    "appointments": {
      "@type": "AppointmentBook",
      "@id": "",
      "action": {
        "@id": "",

This is what your API would look like at this stage:
Hi! Welcome to our website!

Here is a list of our doctors:

- Doctor Jones, appointments

Your users are now able to click on links to go to the next step, because browsers know how to interpret anchor tags. 
Welcome to Doctor Jones appointments list! If you'd like to create an appointment, fill the following form:
Patient's name: 

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:

(Ha! You thought I would give you instructions on how to construct those URLs by hand didn't you?)