What’s New in Swagger/OpenAPI 3?
OpenAPI 3 represents a big leap forward in the world of API creation and documentation. We find out what's new with this release.
Join the DZone community and get the full member experience.
Join For FreeOn July 26th 2017, the OpenAPI Specification (OAS) v3 was released. OpenAPI 3 is the successor of the widely used OpenAPI/Swagger 2.0 format, for machine-readable API definitions. It contains a variety of changes, and even though everything that can be expressed in Version 2 is supported in Version 3 as well, specifications are not backwards-compatible. So, what are these changes and should you switch to the new version already?
Before diving into the differences let's start with a bit of OpenAPI history and clarify the usage of the two terms Swagger and OpenAPI. Swagger was started by Tony Tam, a developer at the company Reverb, as an API definition format to drive the documentation and developer console, for a product called Wordnik. It was subsequently open sourced for the benefit of other developers.
In 2014, the Swagger 2.0 Working Group was formed to create a more formal specification for Swagger. SmartBear acquired the Swagger project from Reverb in 2015 and subsequently donated it to the Linux Foundation. There, they were joined by a number of other companies, including household names such as Google, IBM and Microsoft, and founded the OpenAPI Initiative (OAI). Swagger 2.0 was renamed to OpenAPI 2.0, so the two terms and specifications are completely interchangeable.
The Swagger name was dropped from the specification with version 3 but remains alive in the tooling surrounding the specification format such as the Swagger UI project.
Considering that almost three years have passed since the release of Swagger 2.0 there was ample time to gain practical experience with the format and improve it in terms of features and syntax based on feedback collected from real developers. As Open API Initiative (OAI) Chair Ole Lensmar stated in the v3 release announcement, the update was "entirely user and usage driven."
In terms of the format of API definitions, these are the major visible changes that affect all existing API definitions:
1. The API's base URL is now defined in a single 'url' attribute instead of the previous separation into 'host', 'basepath' and 'schemas', and it's possible to add multiple URLs if the API is available on multiple servers. Example:
v2:
{
“host” : “a.blazemeter.com”,
“basePath” : “/api/v4/”
“schemes” : [ “https” ]
}
}
v3:
{
“servers” : [
“https://a.blazemeter.com/api/v4/”
]
}
2. The new 'requestBody' attribute supersedes the previous 'formData' parameter type and 'body' attribute and is now more flexible in allowing the specification of different types of content with various media types. Example:
v2:
{
“parameters” : [
{
“name” : “userId”,
“type” : ”string”,
“in” : “formData”,
“required” : true
}
]
}
v3:
{
“requestBody”: {
“content” : {
“application/x-www-form-urlencoded” : {
“schema” : {
“type” : “object”,
“properties” : {
“name” : “userId”,
“type” : “string”
}
}
}
}
}
}
3. Other parts of the structure have been moved and renamed, such as 'definitions' which are now '/components/schemas'. Better reusability of parts of an API definition was one of the design objectives of the new specification, and '/components' is the container for all the reusable elements which includes 'parameters' and 'responses' along with 'definitions'.
4. The OAuth 2.0 support has been improved. It's now possible to define multiple flows and even point to automated endpoint discovery as used for OpenID Connect.
If you want to learn more, fellow API expert Mike Ralphson has published a great side-by-side comparison with a real-world example.
OpenAPI v3 New Features
Two completely new features were also added to OpenAPI v3: Callbacks and Links.
Callbacks
Polling an API regularly for updated information puts a strain on an API provider's server. In order to avoid polling and to push information to API consumers in real-time, many APIs employ an event notification mechanism known as callbacks or webhooks. This means a consumer registers a URL for a specific event, and the provider then posts information to this URL when the event that the consumer has indicated interest in occurs. This HTTP request is essentially an API call that adheres to a certain specification, but so far there was no way to add this specification to the machine-readable API definition.
OpenAPI v3 adds 'callbacks' as a new, optional attribute to operations, the idea being that callbacks are specified as part of the operation used to register them. The definition of the content of a callback is exactly the same as every other API path, meaning its body and metadata can be well-defined in machine-readable form. Additionally, the callback definition can make a reference to the outbound API request and define e.g. which parameter is responsible for defining the callback URL.
Here's a small example of how callbacks can look in an OpenAPI definition:
````json
{
"paths" : {
"/hooks" : {
"post" : {
"description" : "Register for callbacks.",
"requestBody": {
"content": {
"application/x-www-form-urlencoded": {
"schema": {
"type": "object",
"properties": {
"callbackUrl": {
"description": "URL to call for updates.",
"type": "string"
}
}
}
}
}
},
"responses" : {
"201" : {
"description" : "Successfully registered"
}
},
"callbacks" : {
"data_event" : {
"{$request.body#/callbackUrl}" : {
"post" : {
"requestBody" : {
"description" : "Data for the event.",
"content" : [...]
},
"responses" : {
"200" : {
"description" : "Your callback should answer with 200."
}
}
}
}
}
}
````
The above sample specification declares a subscription operation under the `/hooks` path that expects a form-encoded POST request with a property callbackUrl. Real world examples could have additional parameters to describe the kind of events that the client wants to subscribe to. Then, a callback called `data_event` (which is just an arbitrary name) is defined that uses the callbackUrl from the subscription request as its operation URL, sends some data with POST (omitted for sake of brevity) and expects a 200 response from the subscriber.
Links
An API is not just an enumeration of unrelated operations. There are relationships between API methods and ways in which they can be used together. For example, let's say we have a CMS-type of system in which users create content. Typically there is one API call to retrieve a user, and there are other user-specific endpoints, such as a list of all content written by a user. Based on the user API call, a new API call can be crafted that returns the content. This kind of relationship can be defined using Links in OpenAPI 3. If you know the idea of Hypermedia you should note that Hypermedia is a dynamic way to express links to related resources and actions within an API response, whereas this specification feature is a static way to specify these relationships. OpenAPI does not yet explicitly support Hypermedia, however, the Links feature can be considered a first step towards full Hypermedia support in the specification.
Just like Callbacks, Links are specified with a `links` attribute on the operations object. Every link contains these two pieces of information:
- A reference to another related operation, specified as `operationRef` or `operationId.`
- A mapping of fields contained in the request or response of the current operation to the `parameters` or `requestBody` of the target operation.
Here's an example:
````json
{
"paths": {
"/users/{id}" : {
"operationId" : "getUser",
"get" : {
"parameters" : {
"name" : "id",
"in" : "path"
},
"responses": [...],
"links" : {
"details" : {
"operationId" : "getUserContent",
"parameters": {
"id" : "$response.body#/id"
}
}
}
}
},
"/users/{id}/content" : {
"operationId" : "getUserContent",
"get" : {
"parameters" : {
"name" : "id",
"in" : "path"
},
"responses" : [...]
}
}
}
}
````
The above sample specification is based on the user and content scenario. One API GET operation called getUser and located at `/users/{id}` defines a link to another API GET operation called getUserContent and located at `/users/{id}/content`. An id attribute from the body of getUser is mapped to the parameters in getUserContent.
As mentioned before, OpenAPI v2 and v3 are not compatible, which means that each of the tools dealing with OpenAPI needs to be updated to support the new format. A non-exhaustive list of tools with v3 support is available at the OAI. If your favorite tools do not support v3 yet, you can keep using v2 for now, provided that you don't need any of the new v3 features.
Once you do need an OpenAPI v3 definition, there are tools for automated conversion of your existing v2 definition such as swagger2openapi.
If you're just getting started with Swagger or want to use callbacks or links feel free to dive into the v3 specification because this is the definite way forward. The OAI will continue to improve the format and has adopted semantic versioning, which means there will be 3.0.x patches and 3.x minor, backwards-compatible updates to keep your current v3 definition compatible with all OpenAPI versions for the foreseeable future.
Published at DZone with permission of Lukas Rosenstock, DZone MVB. See the original article here.
Opinions expressed by DZone contributors are their own.
Comments