OHM, the mediatype for REST/HATEOAS powered by OpenAPI
Tags: rest, openapi, hateoas, hypermedia
Published: 2020-11-10 15:42:20


Today I'd like to present the draft of the OHM format, a new media type for Hypermedia/REST level 3 applications that relies on [OpenAPI](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.3.md) to describe the Hypermedia controls.

# Description of the OHM format

TL;DR : the format is called OHM for Openapi-HyperMedia. Its mediatype is `application/ohm+json` and the definition is :
```json
{
  "content": <JSON representation of the resource>,
  "controls": <An OpenAPI Specification (OAS) in JSON format containing the possible operations from this state>
}
```

... and that's it. Have you already seen a format definition as small as this one ?


For instance a OHM message for a `Person` resource which has a collection of `Address` could look like this:
```json
{
  "content": {
    "firstName": "Jane",
    "lastName": "Doe"
  },
  "controls": {
    "openapi": "3.0.1",
    "info": {
      "title": "rest",
      "version": "0.0.1"
    },
    "paths": {
      "/api/addresses/1": {
        "get": {
          "summary": "John Doe's address"
        }
      }
    }
  }
}
```
The content field contains the information describing a Person called Jane Doe in the usual `application/json` media type. And the `controls` field is an OAS with a link to Jane Doe's address. An OHM client can then be used to navigate from the Person to its address without prior knowledge of the path, method, arguments, etc... that must be used.

It's also possible to use OHM to describe write operations:
```
GET /api/orders/106
```
```json
{
  "content": {
    "id": 106,
    "product": "Licensed Concrete Keyboard",
    "cost": 571.0,
    "customer": {
      "id": 1,
      "name": "Ricky Swift"
    }
  },
  "controls": {
    "openapi": "3.0.1",
    "paths": {
      "/api/orders/106": {
        "put": {
          "summary": "Update order 106",
          "requestBody": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Order"
                }
              }
            }
          }
        },
        "delete": {
          "summary": "Delete order 106"
        }
      },
      "/api/customers/1": {
        "get": {
          "summary": "Get this order's customer (id=1)"
        }
      }
    },
    "components": {
      "schemas": {
        "Order": {
          "type": "object",
          "properties": {
            "cost": {
              "type": "number",
              "example": 571.0
            },
            "customer": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "integer",
                  "example": 1
                }
              }
            }
          }
        }
      }
    }
  }
}
```
This is a classical CRUD resource where a PUT operation can be used to update the resource or a DELETE one to remove it. We can note that OpenAPI helps to fully describe the expected request body of the PUT operation and its media type.

The rest of this post will explain how to use this format to build better APIs truly embracing REST concepts with HATEOAS.

# OHM is a media type for REST

First, what is a true REST application (also called REST level 3)? If you already know, you can skip this whole chapter. But I talk with a lot of people who say they do REST APIs but don't realize that what they do is actually good old RPC (Remote Procedure Call) over HTTP.

[Quoting Roy Fielding](https://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven), the inventor of REST:
> "What needs to be done to make the REST architectural style clear on the notion that hypertext is a constraint? In other words, if the engine of application state (and hence the API) is not being driven by hypertext, then it cannot be RESTful and cannot be a REST API."

![What if I told you your API is not REST ?](https://dev-to-uploads.s3.amazonaws.com/i/7s3svchge2tkpn7lh1rm.jpg)

A key constraint of REST is thus to use Hypermedia As The Engine Of Application State (HATEOAS). It was at the core of the [REST dissertation](https://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm) and even in the name "REpresentational State Transfer" and that's what makes this architectural style so unique. HATEOAS means that messages received from the server contain all the necessary information to drive the application. That's exactly how navigation works with HTML documents : you go from one state to the other using links and forms. So REST is used everyday when you go on the Web and navigate HTML documents with your browser. But never when you call a Web service through an HTTP+JSON API...

OHM provides HATEOAS support through the `controls` field. If we compare with HTML, it's the equivalent of anchor links (GET) and forms (POST). But as it relies on OpenAPI, it can use all the HTTP methods. The `content` field is the equivalent of all the divs and CSS that contain the representation of a resource. In a sense, OHM is a format oriented towards machine (easy to parse) whereas HTML is oriented towards humans (with graphical information).

# When to use a REST approach with the OHM format ?

At the time of Roy Fielding's dissertation, the state of Web applications was fully residing in the server.
But with the advent of JavaScript in the browser and the mobile revolution, the state machine of the application has now moved inside the various clients and there's no need anymore to transfer the state transitions from the server. So we just expose Web services from the server and use them with RPC HTTP calls that we describe with OpenAPI.

![HTML vs HTTP RPC](https://dev-to-uploads.s3.amazonaws.com/i/llgxdp6g2qx19dg0ece7.png)

With a REST format such as OHM, you can put the state management of the application back into the server. This gives the possibility to share parts or the whole application logic between the different types of client (browser, mobile, ...). And you can evolve the application logic without having to update the client which is a major gain when working with native mobile apps.

![REST with OHM](https://dev-to-uploads.s3.amazonaws.com/i/sotj6umjl3h1hfxzl8uo.png)

The advantage compared to HTML is that the view is still built by the client and so it can be used with non-HTML clients such as native mobile ones.

There's also the case where we don't expose an application but a Web service. In that case the application stays in a client that we don't control and REST has maybe small advantage here. It provides a browsable API for the consumers so they can better understand the natural chaining of API calls but you could see that as a too small benefit compared to the additional work needed to add Hypermedia links.
Except if you use the same endpoints for both your applications and your services. In that case OHM will provide HATEOAS for the application and your clients can still get the service content in the `content` identical as if they where using the `application/json` mediatype.

Another advantage of using REST and OHM for Web services is that you can provide an endpoint that lists all the possible operations that are available for clients. A bit like if you provided a single HTML page with all the links and forms that exist on your Web site. With a shared semantic between the client and the API (for instance using the OpenAPI field `operationId`), you can create clients that build the URLs and requests dynamically and will adapt even if you change the URLs or the parameter disposition on the server. Of course, if non-REST clients use the API, it will still be needed to version the API and ensure backward compatibility for these clients.

It's not the primary intent of OHM to provide full automation and interoperability between systems. Although this can certainly be built by adding vocabularies on top with things like JSON-LD. I'd be very interested to get opinions and ideas on this.

# The power of the OHM browser

One big advantage of a REST format such as OHM is that you can build generic clients that understand any application that support the media type. For instance, for OHM you can use the [OHM Browser](https://raw.githack.com/cbornet/swagger-ui/ohm/dist/) which is a modified swagger-ui that navigates the links when you execute instead of displaying the HTTP call response (the sample app it points to by default is hosted on Heroku free tier, so it can take a little time to wake up. Please be patient :sweat_smile:)

![OHM browser](https://dev-to-uploads.s3.amazonaws.com/i/8wiw0vfatnapwgbhsd7b.jpg)

You can test it with a [sample OHM application](https://rest-openapi-demo.herokuapp.com/api) built with JHipster that represents customers that have orders that you can create, read, update, delete with navigation links and that also supports pagination. The source code for this application is located [here](https://github.com/cbornet/sample-rest-app).

# How does OHM compare to other REST formats?

A lot of HATEOAS formats only support navigation links (GET) and not actions that modify the remote system (POST, PUT, ...). As it relies on OpenAPI, OHM supports all the common HTTP methods. It also fully describes the operation links, their call parameters and can embed documentation on how to use them in the messages.

OHM supports all the [H Factors](http://amundsen.com/hypermedia/hfactor/) described by Mike Amundsen.

You don't need to learn a new format if you already know OpenAPI.

There's a lot of Open-Source tools in the OpenAPI landscape that can be reused to support OHM. For instance the OHM-browser is based on swagger-ui, the sample app uses the OAS generated by Springfox, ...

It's relatively easy to transition an HTTP+JSON API to OHM by putting the former JSON response in the content field and adding the links progressively.

# Conclusion

I truly believe that REST can bring a lot to web applications. Hopefully, OHM makes it easy to adopt if you're familiar with OpenAPI. Don't hesitate to give it a try and show what you build with it !
The next steps for me will be to grow the eco-system starting by an helper Java library (which just needs to be extracted from the sample application code). I also think it should be possible to integrate with Spring-Hateoas so I'll have a look into that. Don't hesitate to reach me if you have a language of heart on which you would want to have a helper library. Oh, and I won't blame you if you continue to call RPC HTTP APIs as REST, everybody does it anyway :wink: !

You can follow me on [Twitter](https://twitter.com/cbornet_).

OHM links:
* The OHM specification: https://github.com/cbornet/ohm
* The OHM browser: https://raw.githack.com/cbornet/swagger-ui/ohm/dist/
* A sample OHM application: https://rest-openapi-demo.herokuapp.com/api (https://github.com/cbornet/sample-rest-app)

More readings on REST and Hypermedia:
* "Get Autonomy and Resilience for Free With Hypermedia APIs" by Mike Amundsen : http://amundsen.com/talks/2020-10-apiworld/2020-10-apiworld-hypermedia.pdf
* Roy Fieldings' REST dissertation : https://www.ics.uci.edu/~fielding/pubs/dissertation/rest_arch_style.htm
* "REST APIs must be hypertext-driven" by Roy Fielding : https://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven