As part of swagger2openapi I keep up to date a conversion of the ubiquitous Swagger Petstore example API definition, and some 3.0.0 examples have recently been added to the OpenAPI specification repository, but we we both agreed I should look for something real-world which would show off the major changes between OpenAPI 2.0 (fka Swagger) and OpenAPI 3.0.0.
I turned out to be harder than I expected to find a good candidate definition, even as the maintainer of the APIs.guru collection which contains over 500 real-world APIs.
I set myself some ground rules:
- The definition had to originate in Swagger 2.0 format
- It had to be valid at source, not patched up as many APIs in APIs.guru are
- It should include oAuth authentication
- It must have
- It must have
Luckily I have the metadata of all of the APIs.guru APIs extracted into a database for easy analysis. If I couldn't find an example in APIs.guru, I could always widen the search to include the 45,000-plus APIs I've indexed from GitHub and SwaggerHub.
I needed to add a couple of columns to the API metadata table, then I queried using my constraints, and ordered by size to find the most concise candidate definition.
-swagger: '2.0' +openapi: 3.0.0-RC1
First things first, and we get our feet wet gently. All references to Swagger in the OpenAPI specification have been changed to OpenAPI, and that includes the
swagger property in your API definition.
While the version number is still a string, it is now semver - major.minor.patch - compatible. This means when the OpenAPI 3.0.0 specification is released, patch versions can be published to clarify wording, examples etc where this does not affect the specification itself, and minor versions can be published which add new features in a backwards-compatible way. Only breaking changes would result in an OpenAPI 4.x.x version.
Any characters after the patch version are informative only and should be ignored by tooling. In fact, tooling authors should look only at the major and minor (e.g. 3.0) versions when determining compatibility.
One other change to the
info object is that
termsOfService must now be a URL. This should not affect many APIs as this appears to always have been standard practice.
-host: connect.authentiq.io -basePath: / -schemes: - - https +servers: + - url: 'https://connect.authentiq.io/'
Out go separate
schemes and in comes an array of
servers each with a
url property, allowing multiple endpoints for an API. Unlike Swagger 2.0, OpenAPI 3 also supports url templating, by means of replaceable
variables (not shown here as they will not exist in converted definitions).
-consumes: - - application/x-www-form-urlencoded - - application/json -produces: - - application/x-www-form-urlencoded - - application/json - - application/problem+json - - text/html
Out go the top-level
produces arrays. As we will see later, each
response can now specify multiple content-types.
parameters: - name: client_id in: query - type: string description: > A client ID obtained from the [Dashboard](https://dashboard.authentiq.com/). required: true + schema: + type: string
headers are no-longer objects which share properties like
schema objects, instead they include one.
headers can optionally have a
content object instead of a
schema if their definition varies based on
parameters are the one area I've found where it is not possible to losslessly convert valid Swagger 2.0 definitions to OpenAPI 3.0. The
tsv (tab-separated values) has been dropped, and it is no longer possible to define nested separators for arrays within arrays, e.g.
a|b,c|d. If you need these features, now would be a great time to raise an issue at the OpenAPI specification repository.
parameters: - name: Authorization in: header description: | HTTP Basic authorization header. required: false - type: string - - name: client_id - in: formData - description: | - The registered client ID. - required: true - type: string
This is where it gets interesting, all
parameters which are
in: formData disappear. We'll see them turn up again in a new guise shortly. The same would be true for the
responses: '200': - $ref: '#/responses/Token' + $ref: '#/components/responses/Token'
This is an example of the restucturing that has gone on in OpenAPI 3.0.0. Schemas from
/definitions now reside under
/components/schemas and the top-level
responses object moves to
/components/responses - all
$refs need to be updated to maintain the referential integrity of your definition.
+ requestBody: + content: + application/x-www-form-urlencoded: + schema: + type: object + properties: + client_id: + description: | + The registered client ID. + type: string + client_secret: + description: | + The registered client ID secret. + type: string + format: password
Here we see the previous
formData parameters have been converted into properties of a new object held under the
requestBody property of the
consumes array values become the keys of the
content object map.
responses: '200': description: A list of Client Objects. - schema: - type: array - items: - $ref: '#/definitions/Client' + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Client' + application/x-www-form-urlencoded: + schema: + type: array + items: + $ref: '#/components/schemas/Client'
responses, each old
produces array value can have its own schema.
responses: '201': description: Client created headers: Location: description: URL of new client resource - type: string + schema: + type: string
headers no longer have a
type, but are defined by a
parameters: - - $ref: '#/parameters/client_id' + - $ref: '#/components/parameters/client_id'
parameters have moved from the top-level
parameters object to
-securityDefinitions: - client_secret: - description: Session management by confidential clients. - type: oauth2 - flow: password - tokenUrl: 'https://connect.authentiq.io/token' - scopes: - clients: Enable client management + securitySchemes: + client_secret: + description: Session management by confidential clients. + type: oauth2 + flows: + password: + tokenUrl: 'https://connect.authentiq.io/token' + scopes: + clients: Enable client management
securityDefinitions become the
/components/securitySchemes object. You can see that multiple
flows are now allowed per oAuth2 scheme.
And that's it for this example.
This walk-through of a conversion (by a work-in-progress converter, tracking a Release Candidate specification) does not show off any of the new features of OpenAPI 3.0.0 like
cookie parameters, but hopefully shows some of the major areas of change when converting an API definition by hand, or help you find where things have moved to if you use a converter like swagger2openapi.
Also not shown are changes from the RC2 release candidate, including changes to the
discriminator property. Keep your eyes peeled for an imminent release.
As ever, if you spot anything which looks incorrect by the specification, please don't hesitate to contact me. Feedback is always gratefully received.