Comparing OpenAPI/Swagger 2.0 and 3.0.0-rc1
Tags: api, openapi, swagger, openapi3
Published: 2017-05-23 08:00:50

---
title: Comparing OpenAPI/Swagger 2.0 and 3.0.0-rc1
published: true
description: A deep-dive into the result of converting an existing OpenAPI 2.0 definition
tags: api, openapi, swagger, openapi3
cover_image: https://thepracticaldev.s3.amazonaws.com/i/lhlvf5k188lznd9gwkgx.png
---

[Kin Lane](https://twitter.com/kinlane), the [API Evangelist](https://apievangelist.com/), recently got in touch asking whether I had a good example of an OpenAPI 3.0.0 definition.

As part of [swagger2openapi](https://github.com/mermade/swagger2openapi) I keep up to date a conversion of the ubiquitous Swagger [Petstore](https://github.com/Mermade/swagger2openapi/blob/master/conversions/swagger2openapi/openapi.json) example API definition, and some 3.0.0 [examples](https://github.com/OAI/OpenAPI-Specification/tree/OpenAPI.next/examples/v3.0) have recently been added to the [OpenAPI specification](https://github.com/OAI/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](https://github.com/apis-guru/openapi-directory) 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 `body` or `formData` parameters
* It must have `query` or `path` parameters

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](https://swaggerhub.com).

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.

The eventual winner was the [Authentiq.Io](https://raw.githubusercontent.com/AuthentiqID/authentiq-docs/master/docs/swagger/provider.yaml) API as mentioned on Kin's [blog posting](http://apievangelist.com/2017/05/22/a-working-example-of-openapi-version-3-dot-0-to-learn-from/).

So, let's get stuck in, and start looking at the diff between the [Swagger 2.0 original](https://gist.github.com/MikeRalphson/0c42c2778ea7a7a6fc0b5d59b4d7868e), and the [converted OpenAPI 3.0.0 definition](https://gist.github.com/MikeRalphson/72e8172bddfa4de7330c9e218b95401f).

### Metadata

```diff
-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](http://semver.org/) - 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. 

### API endpoint definition

```diff
-host: connect.authentiq.io
-basePath: /
-schemes:
-  - https
+servers:
+  - url: 'https://connect.authentiq.io/'
```

Out go separate `host`, `basePath` and `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](https://tools.ietf.org/html/rfc6570), by means of replaceable `variables` (not shown here as they will not exist in converted definitions).

### Content-Types

```diff
-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 `consumes` and `produces` arrays. As we will see later, each `requestBody` and `response` can now specify multiple content-types.

### Query and Path Parameters

```diff
       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
```

`parameters` and `headers` are no-longer objects which share properties like `type` and `items` with `schema` objects, instead they include one. `parameters` and `headers` can optionally have a `content` object instead of a `schema` if their definition varies based on `content-type`.

`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 `array` `collectionFormat` of `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](https://github.com/OAI/OpenAPI-Specification/issues) at the OpenAPI specification repository.

### FormData parameters

```diff
       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 `body` parameter.

### Reference Objects

```diff
       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 `$ref`s need to be updated to maintain the referential integrity of your definition.

### RequestBodies

```diff
+      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 `operation` object.

The `consumes` array values become the keys of the `content` object map.

### Responses

```diff
       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'
```

Under `responses`, each old `produces` array value can have its own schema.

### Response Headers

```diff
       responses:
         '201':
           description: Client created
           headers:
             Location:
               description: URL of new client resource
-              type: string
+              schema:
+                type: string
```

As with `parameters`, `headers` no longer have a `type`, but are defined by a `schema` or `content` object.

### Definition Structure

```diff
       parameters:
-        - $ref: '#/parameters/client_id'
+        - $ref: '#/components/parameters/client_id'
```

Reusable `parameters` have moved from the top-level `parameters` object to `/components/parameters`.

### Security Definitions

```diff
-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
```

Top-level `securityDefinitions` become the `/components/securitySchemes` object. You can see that multiple `flows` are now allowed per oAuth2 scheme.

### Summary

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 `links` and `callbacks` or `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](https://github.com/mermade/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.