If you’ve been hiding under a rock for the past 18 months you may not know that the Swagger API specification, arguably the most popular specification format available to the API community, has been donated to the Linux Foundation to become the bedrock of the OpenAPI Specification. The OpenAPI Specification (OAS) is supported by various industry heavyweights including the likes of Google, Microsoft, and IBM, with its goal being:
“…to define a standard, language-agnostic interface to REST APIs which allows both humans and computers to discover and understand the capabilities of the service without access to source code, documentation, or through network traffic inspection”
After grooming an extensive backlog, the community supported Technical Design Committee (TDC) has released an implementer draft of the specification at version 3.0. The draft is accompanied by a walkthrough to help developers learn about the changes and get hands on with the draft.
In this post we’ll take a look at this walkthrough and the changes OAS 3.0 introduces, dive into detail on the highlights, and try to assess the implications of new features for both API providers and consumers.
Standardizing Reuse with the Components Object
The draft specification includes several structural changes and perhaps the most important is how root-level objects such as definitions have been modified to be encapsulated by a Components object. The purpose the Components object is to address the inconsistencies in behavior of root-level properties in version 2.0 and extend the opportunities for reuse across an API specification i.e. anything defined within the Components object is available for reuse elsewhere but no longer constitutes a root-level object that is effectively global in scope.
The implication of encapsulating root-level objects and removing the global scope is that supporting code-generation tools should only create object definitions when they find an explicit reference; if an object is not referenced it should be ignored. If this implication is valid then this will give API providers the ability to include standard Components object definitions with the expectation that consumers will just ignore them if they are unused; API consumers will also be able to generate code with a lower footprint as unused objects will similarly be ignored (with obvious efficiencies in code review, secure coding practices and maintenance).
Such an approach would obviously come at cost of succinct and terse specification documents so a possible future enhancement is to allow a Components object to be externalized. Of course, it remains to be seen whether this interpretation is valid as developers will decide how to create their code-generation tools.
For API designers and developers the Components object offers significant benefits in defining reusable objects; for example, reuse of a Parameter object is a real boon for those who want to define a single parameter and reuse it across multiple resources or methods, something impossible at version 2.0 and achievable in API description languages like RAML. By way of example a reusable Parameter object can be defined as follows:
description: My Nordic APIs Identifier
This can then be referenced elsewhere in the specification:
- $ref: #/components/parameters/NordicId
- name: another_random
description: Another random parameter as an example
Defining Multiple Servers
Another structural highlight is the ability to define multiple servers. This is important as an API can be aliased multiple times, giving optionality in how an API is hosted. Hosts can also be overridden at the level of a Path object meaning different resources can be hosted on different servers.
Overriding hosts at path level offers significant support to a microservices architecture, giving API providers the ability of deploying several microservices described by a single API specification; the provider can therefore deliver ease-of-use for the developer community without sacrificing their architectural approach. However, using this option might need to be tempered with caution for APIs that are consumed in the browser as swapping between hosts when making Ajax calls is likely to inflict some pain in the shape of CORS. Adding multiple servers doesn’t create a CORS issue – it already exists when an Ajax call is made to a different host – but it might exacerbate it as behaviors will need to be consistent across all the hosts an API provider exposes. API providers should understand their audience before making this design decision and if appropriate implement sufficient CORS handling at the server to allow browsers to make cross-site requests securely.
Improvements for Example objects
The final structural change highlighted by the walkthrough is the increased flexibility of Example objects, which can now be used to describe any kind of example rather than one encoded in JSON or YAML; other formats such as XML or plain text can be expressed in JSON string. Describing an XML example can be done as follows:
The example can also be externalized by using a $ref object and be leveraged by Content objects as discussed below. It’s also worth noting that the Examples object is being refined and is likely to change before the final release of the specification.
Standardizing Request Parameters and Content
The OAS draft introduces some important standardization of how request definitions are defined. Firstly, request parameters are defined as an object rather than as a subset of the Parameter object. This is important as it adds some significant reuse benefits not possible at version 2.0.
The Request Body object also leverages the new Content object which aims to provide a multifaceted view of an object in that it describes different content types within a single object:
- Example1: Nordic
The Content object therefore significantly enhances the ability to define multiple content types in a single request or response definition.
Support for Webhooks
The majority of API providers and consumers are acutely aware of the fact that APIs are increasingly implementing mechanisms to establish two-way communication, in the style of publish/subscribe patterns and technologies such as WebSockets. OAS acknowledges this fact by introducing the Callback object that provides a means to define a webhook in an API specification. The Callback object can be defined per parent operation, allowing a great deal of flexibility in the data a given callback can carry. Moreover, a Callbacks object is also provided that allows a map of callbacks to be defined.
A Nod to Hypermedia
The aspiration for hypermedia-driven APIs (from the perspective of those in the developer community who want to create them) is also acknowledged through the introduction of the Links object. Hypermedia-driven APIs was explicitly not a goal at version 3.0 and Links in this context are static definitions created at design time and not generated dynamically. Describing a hypermedia-driven API in an appropriate way remains elusive in OAS, exacerbated by the fact that there are many different, opinionated methods of defining a hypermedia-driven API and choosing one that will “fit” into OAS is difficult in of itself. There already are open issues destined for the next version (for example, the very detailed issue 577). The intention of draft specification of the Link object is therefore to:
“…allow the generation of more useful documentation and client libraries that can encapsulate the process of traversing from one resource to another.”
This seems to be a pragmatic approach to providing something the community is looking for without completely overhauling the structure of the OpenAPI specification.
JSON (and other) Schema
The walkthrough also makes reference to what’s been taken on from JSON Schema, most pertinently the inclusion of anyOf and oneOf that were unavailable in version 2.0; this subject is covered extensively in issue 741 and in the draft itself. Whilst the draft significantly expands the inclusion of JSON Schema and makes it a fully compatible subset by removing the “file” type, there is no option to include native JSON Schema definitions; like version 2.0 a schema must be defined with a Schema object. The ability to use native JSON Schema is referenced in the backlog in issue 275 and would obviously be useful to developers attempting to reuse existing definitions. Moreover, it would also make OpenAPI functionally equivalent to RAML in this respect.
The subject of alternative schemas is also discussed and covered by issue 764. Alternative schemas would give API providers increased choice in defining their objects; XML Schema is almost certainly the most obvious example of an alternative and would be particularly useful for providers looking to migrate from SOAP to REST and to reuse their Request/Response parameter objects from their WSDL. Moreover, the ability to swap in something like JSON-LD might enhance the ability of providers to define hypermedia-driven APIs and express them (to some extent) via an OAS specification.
A huge amount of work has gone into producing this draft and the community as a whole should be grateful to the TDC and those that support them for the progress made in advancing the specification. The improvement in the objects the specification offers are exceeding valuable in simplifying the means to create definitions that can be reused throughout an API specification.
It goes without saying, however that there is currently a gap between the draft and the tools that support it (like Swagger Editor). It will be exciting to see how it continues to evolve when these tools do implement version 3.0 and the specification gets exercised in the real world.
This post is of course only a summary and there other changes such as externalized documentation and security definitions that are also of value to developers. There are also many open issues in the backlog that need consideration for future versions over a wide number of subjects. If you want to get involved in helping evolve the next version check out these links: