API Maturity

Zdenek “Z” Nemec
Good API
Published in
8 min readApr 16, 2018

Often, when designing an API, I reference to Richardson Maturity Model, and, lately to Amundsen Maturity Model. The desired norm I recommend to Good API clients is to attain level two of both Richardson and Amundsen’s Maturity Models (reasonable minimum for most of the APIs). But why does it matter? What are these level anyway? And if I have an existing API how to do a maturity assessment? Let’s dive into the maturity of APIs.

Richardson Maturity

Image by Martin Fowler

Richardson Maturity Model (RMM) classifies APIs based on its architectural maturity towards REST. It looks at the transactions of the API and implies its architectural style.

The higher the level the more is the API closer to the REST Architectural Style and the further away from RPC. That is if an API is Richardson Maturity Model Level 3 it is a REST API with all of the benefits (and drawbacks!) of the REST architectural style. If the Maturity Level is at zero, the API is likely to be some variant of the RPC architectural style, with all its pros and cons.

RMM0: Richardson Level Zero

To evaluate API Richardson Maturity Model, one needs to look at many different criteria. But typical level one is easy to spot. There is usually only one endpoint for an API-service, and each different action the API affords (affordance) is invoked by passing different parameters to that endpoint.

RPC, SOAP, and GraphQL APIs are, according to the Richardson Maturity Model, at level zero.

RMM1: Richardson Level One

The level one is more difficult to differentiate especially from the level two. At level one, the API has at least some notion of the concept of resources representing the information or actions the API affords. However, the interaction with level one resources is usually not respecting the semantics of the HTTP protocol. For example, they are misusing HTTP Request Methods (e.g., POST instead PATCH or GET), Status Codes (e.g., 200 for error response), or HTTP Headers (e.g., ignoring Content Negotiation or Caching headers). This leads to losing the performance and scalability benefits of the existing Web infrastructure and confusing HTTP-savvy consumers.

A good knowledge of the HTTP Protocol is needed to deliver or assess APIs beyond Maturity Level One.

RMM2: Richardson Level Two

At the Maturity Level Two, an API is enjoying most of the benefits of the Web infrastructure since it follows the HTTP protocol and its semantics, but still missing the advantage of decoupling the service from its clients. A Maturity Level Two API respects the HTTP protocol but doesn’t provide the controls needed for the client to navigate the application state without any external knowledge.

In other words, a Level Two API doesn’t provide links in the responses, so the client does not know what action it can take without relying on a previously shared knowledge. This leads to tight coupling of client and server, no discoverability and prevents independent API evolution.

RMM3: Richardson Level Three

Finally, at the Level Three, an API that distinguishes resources, respects HTTP protocol and provides links–affordances meets all the constraint of a REST API Architectural style. Only Level Three API and can be called a REST API.

Explanation of RMM using JSON Request and Responses:

Amundsen Maturity

Image by Mike Amundsen

Amundsen Maturity Model classifies APIs based on their data model abstraction. Its levels are not implying the architectural style of a given API. Instead, the Amundsen Maturity classifies an API by its design with regards to data abstraction and actions it affords. The higher the level the more is the API decoupled from the internal models of the implementations and the more is focused on API consumers.

AMM0: Amundsen Level Zero

Data abstraction is one of the superpowers of APIs. However, at Amundsen Level Zero there is no abstraction between the service persistence layer (e.g., Database) and the client. This means whatever data model is in the database that data model is what client is getting. You can't change your database without breaking client.

AMM0 APIs can be easily spotted— see that MongoDB document or SQL dump in the response? You know you are looking into the API provider's kitchen.

Example of Amundsen' Level Zero API: A Database model exposed over API

AMM1: Amundsen Level One

Amundsen Level One is taking the exposition of API implementation internals from the persistence layer to the execution layer. Instead of dealing with the data as they are stored in a database (Level Zero), clients are now presented with the implementation objects. Now you can, in theory, change your database but not the service implementation (framework/middleware).

Legacy Webservices (WS*) are a great example of the Level One, but modern variants exist. For example, the Restify-Mongoose middleware exposes database objects modeling framework’s query functionality to the client. Tough luck replacing the Mongoose framework (or MongoDB) later! And I am not even mentioning the usability of such an API for non-database users!

To identify Amundsen Level One APIs, the person doing the assessment must be able to distinguish whether data, as accepted and exposed by the API, are related to the API implementation or not. If so, it is a bad sign that this API is leaking implementation internals and as such it preventing any independent evolution of the API implementation later down the road.

AMM2: Amundsen Level Two

Leaving the levels that are exposing API implementation data models, we are getting to the higher levels of abstraction and decoupling from the internal models.

At the Level Two, the API successfully manages to decouple the actual implementation internals and persistence data models from the resource representation model. This can be achieved using the Representor Pattern where an internal data model is replaced with a resource representation before it is shared via a transport layer.

Image by The Hypermedia Project

The Level Two APIs are focused on its interface and delivering the data the consumers needs (and more, see AMM3). Furthermore, AMM2 APIs do not expose any internal models and usually tend to properly use the HTTP Content-Negotiation mechanisms.

AMM3: Amundsen Level Three

Finally, at the Level Three, the APIs are focused on the actions the API affords and consumers can take. If you think about an API as a product, these APIs affordances are modeled in hand with the user stories of the API product. The actions the API affords are reflecting the needs of the consumers. With affordance-oriented APIs, the clients are no longer ask to take a look at the data and figure out what they can do with it. Instead, they are directly presented with the action they can take.

The Level Three APIs are focused on the actions, not data. Often, the Level Three APIs provide the actions at the runtime (REST–Hypermedia APIs) and employ media types needed for the communication of thereof (such as application/vnd.restful+json).

As such, the affordance-centric APIs excels in consumers usability, decoupling from the internals and evolution over the time.

Overfetching and AMM2 vs AMM3

If an AMM2 API is exposing resource representations without thinking about the consumers’ interaction with it, it usually means it is providing some data consumer doesn’t care about. Sometimes this is called Overfetching and it is something that GraphQL claims to solve. But all that is needed is to move from one step higher, from thinking about “here are the data” (AMM2) to thinking about “here are the actions” (AMM3).

Let’s say we are building a Star Wars API, and one of our anticipated user story is: As I user I want to know the name of a director of a particular episode.

Here are the different levels of the Amundsen Maturity model:

AMM0: Exposing movie information as data as stored in our DB.

AMM1: Exposing movie information as some middleware eg. ESB / WS objects.

AMM2: Exposing movie information as a representation in a format that is hiding the above (AMM0 and AMM1).

AMM3: No longer exposing movie information per se, instead providing the actions that are mapping to user stories, in this case, the action to retrieve the name of the director of a particular episode.

Why it Matters?

So why I am recommending to attain at least the level two both of Richardson and Amundsen Maturity Models?

In the case of Richardson Maturity, it is because of the resilience, performance, scale-ability, visibility, and predictability you get by simply adhering to the infrastructure that made Web possible.

With Amundsen Maturity, breaking free from internal data models enables your system implementation to evolve over the time. By going at least the AMM2 you get the incredible superpower of APIs to abstract the complexity away and to create systems that last.

But as with everything attaining these levels come with costs.

For RMM2 it is the fact that you have to understand network systems and no longer pretend the network is not there, But a comprehensive knowledge of the HTTP protocol and all its nuances does not come cheap.

For AMM2 the cost you are paying, as with any increasing abstraction, is the overall stack complexity and some runtime performance trade-offs.

In need of an API that is here for just a few months, have only one client that you control and needs to be blazing fast? Go with RMM < 2 and AMM < 2 (RPC).

Current API Descriptions Format are Letting us Down

I believe Mike Amundsen observed the API description documents and noticed the correlation between the API description format and the level of data model abstraction. And he was correct! The predominant API description formats–Open API Spec (both 2.0 and 3.0) and API Blueprint and RAML are indeed influencing how we design our APIs both from architectural and data modeling standpoint.

Saying this as the author of API Blueprint, at the current state, these formats are holding us down. They served their purpose and did an excellent job to get us from level zero to level two on both levels. But now, they constraint us to think and work both at RMM2 and AMM2 levels. In other words, OpenAPI Specification, API Blueprint, and RAML are leading us to tightly couple clients and servers and to overfetch data.

This is not the way forward towards autonomous APIs and clients. These formats need to go.

“Your data model is not your objectmodel is not your resource model is not your affordance model.”

–Mike Amundsen, 2016

Thanks to Ralph Kemp for the initial incentive to write this article and the invaluable feedback he provided.

For another explanation of the Richardson Maturity Model head over to Understanding the Richardson Maturity Model via Fast Food

Examples of RMM and AMM used in this article are available as GitHub Gists and hold some discussion on its own. If you are having problems to access the GitHub you can download the examples from here.

--

--