Aarash Heydari is a Member of Technical Staff for Clumio’s Backend team. He completed his undergraduate studies in computer science at UC Berkeley. Aarash spends his free time in quarantine playing drums and reading philosophy.
One of the first employees at Clumio’s India R&D Center, Bhaskarjyoti Bora codes passionately. With more than 15 years of experience, he has held technical positions with Goldman Sachs and Nutanix.
Recently, Clumio launched an Open Source Contributions GitHub repository to build an ecosystem of common data management workflows that can be shared by our customers and developers. In this blog, I’ll describe how Clumio’s REpresentational State Transfer (REST) API was designed under the guiding principle of putting user experience (UX) first.
All SaaS products require an external API. Since the advent of the Internet, there have been many protocols designed to meet this need, and REST is the most enduring and widely adopted among them. But REST itself is a broad architectural style open to interpretation, and not all REST APIs are created equal.
When companies think about UX, the term is typically associated with web design: action buttons, informational dashboards, and low-latency wait times. But in today’s world of automation, the request/response structures and URLs themselves are the user experience of a scripted client. Some guiding principles we like to use at Clumio include:
When programmers interact with resources in code, they naturally organize classes which point to one another with a variety of interface methods. HTTP lacks this native organizability because it is built to serve any kind of web content generically.
Resources and Operations
To organize Clumio’s APIs, we formalized the notion of a `resource` as a manageable object within the Clumio system. Each resource has an interface of different operations corresponding to different URL/HTTP Method pairs, typically including a GET that dumps the state of the object. For example, we have a `tasks` resource, which exposes the operations of retrieval and cancellation (Figure A). This abstraction groups together URLs that manage the same logical objects.
One product of this resource-operation formalism is what we call “the Discovery endpoint”. It functions as a hypermedia landing page for the API, because it provides a machine-readable description of all the different resources you can manage and links to the operations you can perform on them.
Figure A: The API Discovery endpoint response, which provides a machine-readable description of all API resources and endpoints.
Shifting our perspective towards resources and operations allows the client to use the Discovery endpoint as an API lookup table, and resolve the correct URL by selecting the operation they wish to perform. Hard-coding URLs becomes unnecessary and clients are protected from URL changes.
The Discovery endpoint is an example of Hypermedia as the Engine of Application State (HATEOAS), which is a cryptic way to state that the API response body provides hypermedia (URL links) to other operations. Integrating hypermedia is the primary criteria of “level three” of REST under the Richardson Maturity Model of APIs, a categorization of four levels of API maturity, from 0 through 3. Hypermedia unlocks the “State Transfer” part of the “REpresentational State Transfer” acronym because it allows the API to give clues to the user about other possible actions they can take based on the current state. It also makes the API a discoverable, self-documenting experience. For example, a Virtual Machine resource provides links to various related resources such as the policy assigned to it (Figure B).
Figure B: The REST API representation of a Virtual Machine also includes links to related resources such as the datacenter it resides within and the policy assigned to it.
To accelerate innovation, an API must acknowledge the need for versioning and backwards-compatibility. Different REST APIs have their own versioning conventions, but there were two approaches that we wanted to avoid:
- Enforcing one overall API version seemed to be a heavy handed approach. Different parts of the system grow at different speeds, and multiple versions of some resources may need to be usable at any given time to support backwards-compatibility of clients. Since Clumio leverages the power of SaaS to upgrade our services more frequently than our competitors, incrementing an overall API version upon every release would quickly get out of hand.
- Putting the version in the URL seemed suboptimal. For example, URL templates such as /users/v3/ look deficient. Philosophically, the URL ought to be an identifier for a resource in the system, without the caveat of an API version.
Clumio’s resource-operation formalism naturally lends itself to a resource-based versioning scheme. We use the HTTP request ‘Accept’ header to specify the API version that should be consumed. For example, `Accept: application/api.clumio.users=v2+json` could be used by a client to ask for a specific version (v2) of the user-management related endpoints. All supported versions for each resource are documented in the Discovery endpoint.
The result is a win-win. User experience is prioritized: API clients are protected from new backwards incompatible versions by specifying their desired version in their request headers. For developers adding new features, new APIs can be added and existing APIs can innovate at different speeds without breaking old clients.
So what are you waiting for… Give it a try!
As the Clumio Data Fabric adds support for more data sources and features, the REST API grows alongside it. Under the principle of “putting UX first”, Clumio set the foundation for a forward-looking REST API that aims to provide an outstanding experience to all collaborators. Speaking of collaborators, I mentioned earlier that Clumio launched an Open Source Contributions GitHub repository to build an ecosystem of common data management workflows that can be shared by our clients. We welcome you to tinker with our APIs and contribute!