Over the past few years, Swagger 2 has become the de facto standard for defining or documenting your API. Since then, it's been moved to the Linux foundation and renamed to OpenAPI Spec. Version 3 has been in the works for a while, and it's finally feature complete! Here's a guide to what's changed, and how to upgrade from Swagger 2 to OpenAPI 3.
Like Swagger? ReadMe just launched support for Swagger 2! Try it out now!
Here's a hoverable overview of the structure of Swagger 2/OpenAPI 3 specs:
Format Changes
Swagger 3 will still be in JSON or YAML, however some minor things have been changed about the formats used.
- Swagger has been renamed OpenAPI, although this post will use them somewhat interchangeably.
- OpenAPI 3 now specifies YAML should be 1.2, which has been out since 2009 so it shouldn't break anything. It's just a clarification. (However, only features that can be transpiled to JSON are allowed.)
- The project is adopting Semver for versioning. So while the previous version is 2.0, the new will be 3.0.0.
- Github Flavored Markdown will be replaced with CommonMark. Not much will change, since CommonMark is mostly just an attempt to standardize what most sites refer to as GFM (even GitHub is doing something similar).
- Swagger now supports more of JSON Schema (oneOf, anyOf, not, nullable, deprecated, writeOnly), and clarifies JSON References a bit.
URL Structure
Currently, Swagger 2 lets you define schemes, a host and a baseUrl, which is combined into your URL. Now, you can have multiple “URLs,” and they can be defined anywhere—meaning you can have just one at the base like before, or a specific endpoint can have its own server if the base URL is different. Additionally, path templating is now allowed. In OpenAPI 3, this was only allowed in the actual endpoint URLs. You define the templates with a “variable” property.
Swagger 2
info:
title: Swagger Sample App
host: example.com
basePath: /v1
schemes: ['http', 'https']
OpenAPI 3
servers:
- url: https://{subdomain}.site.com/{version}
description: The main prod server
variables:
subdomain:
default: production
version:
enum:
- v1
- v2
default: v2
There’s a few minor changes to path items, too. They now can accept a description, and there's support for TRACE
. Thanks to servers
, you can now give each path its own base URL (http://login.example.com, for example). Lastly, you’re no longer allowed to define a request body for GET
and DELETE
(which matches how RESTful APIs work).
Components
Swagger 2 had the concept of definitions
, however they were somewhat arbitrary and weren’t as well-defined. OpenAPI 3 attempts to standardize the concept into “components,” which are definable objects that can be reused multiple places.
Here’s the list of OpenAPI 3 components:
- responses (existing)
- parameters (existing)
- examples (new)
- requestBodies (new)
- headers (new)
- links (new)
- callbacks (new)
- schemas (updated)
- securitySchemes (updated)
So, rather than one “definitions” section with all references, you would now access something like #/components/schemas/Pet
.
Request Format
One of the most confusing aspects of Swagger 2 was body/formData. They were a subset of parameters—you could only have one or the other—and if you went with body, the format was different than the rest of the parameters. (You could only have on body
parameter, the name was irrelevant, the format was different, etc.)
Now, body has been moved into its own section called requestBody, and formData has been merged into it. In addition, cookies has been added as a parameter type (in addition to the existing header, path and query options).
Swagger 2
"/pets/{petId}":
post:
parameters:
- name: petId
in: path
description: ID of pet to update
required: true
type: string
- name: user
in: body
description: user to add to the system
required: true
schema:
type: array
items:
type: string
OpenAPI 3
"/pets/{petId}":
post:
requestBody:
description: user to add to the system
required: true
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/Pet'
examples:
- name: Fluffy
petType: Cat
- http://example.com/pet.json
parameters:
- name: petId
in: path
description: ID of pet to update
required: true
type: string
The requestBody has a lot of new features. You can now provide an example
(or array of examples
) for requestBody
. This is pretty flexible (you can pass in a full example, a reference, or even a URL to the example).
The new requestBody supports different media types (content
is an array of mimetypes, like application/json
or text/plain
, although you can use */*
as a catch-all).
For parameters, you have two options on how you want to define them. You can define a “schema” (like in 2.0), which lets you describe the item. Or, if it’s more complex, you can use “content,” which is the same as “requestBody.”
Response Format
Responses have also gotten an upgrade!
Wildcard response codes mean you can now define a response for “4xx” rather than having to define each one separately.
Responses and responses headers can both be more complex. You can use “content” objects (like in requests) for the payload.
There’s also the concept of callbacks, which allow you to define a webhook:
myWebhook:
'$request.body#/url':
post:
requestBody:
description: Callback payload
content:
'application/json':
schema:
$ref: '#/components/schemas/SomePayload'
responses:
200:
description: webhook processed!
Linking
Linking is one of the most interesting additions to OpenAPI 3. It’s a bit complicated, but potentially incredibly powerful. It’s basically a way of describing “what’s next”. (For people familiar, it's in the same vein as HATEOAS / Hypermedia APIs.)
Let’s say you get a user, and it has an addressId
. This addressId
is pretty useless by itself. You can use links to show how to “expand” that, and get the full address.
paths:
/users/{userId}:
get:
responses:
200:
links:
address:
operationId: getAddressWithAddressId
parameters:
addressId: '$response.body#/addressId'
See what’s happening there? In the response from “/users/{userId}”, we get back an addressId
. The “links” describes how we can get an address by referencing the “$response.body#/addressId”.
Another usecase is pagination. If you fetch 100 results, links
can show how to get results 101-200. It’s flexible, which means it can handle any pagination scheme from limits
to cursors
.
Security
A bunch of changes to security! It’s been renamed, OAuth2 flow names have been updated, you can have multiple flows, and there’s support for OpenID Connect. The “basic” type has been renamed to “http”, and now security can have a “scheme” and a “bearerFormat”.
Swagger 2
securityDefinitions:
UserSecurity:
type: basic
APIKey:
type: apiKey
name: Authorization
in: header
security:
- UserSecurity: []
- APIKey: []
OpenAPI 3
components:
securitySchemes:
UserSecurity:
type: http
scheme: basic
APIKey:
type: http
scheme: bearer
bearerFormat: TOKEN
security:
- UserSecurity: []
- APIKey: []
So… can you use it?
The OpenAPI 3.0.0 Spec is currently out as a release candidate, and is considered feature complete. This means that nothing big will change, although some minor details might be refined or tweaked. The final spec should be done within a few months!
Upgrading from Swagger 2.0 to OpenAPI 3.0.0 is lossless, meaning that it can be done without losing any data. Currently there is no tool to upgrade them (and no plans from the Open API Initiative to build one, although there will likely eventually be some options provided by vendors). [EDIT: Seems there is an unofficial one! mermade/swagger2openapi]
You can get started with the spec here: https://github.com/OAI/OpenAPI-Specification/blob/OpenAPI.next/versions/3.0.md
Even once the spec is finalized, having an OpenAPI 3 file is only as good as the products that support it. Since it’s not backwards compatible, OpenAPI 3 specs won’t work in tools that only support Swagger 2.
That’s OpenAPI 3.0!
Overall, I’m impressed by 3.0. Most of the shortcomings we’ve run into when supporting Swagger 2 on ReadMe have solved by OpenAPI 3. It comes with some additional complexity, however they’ve done a great job at making Swagger reflect how most people currently build APIs.
Use Swagger? Create beautiful API docs in seconds.
Thanks to Ron Ratovsky! This post was based on his talks and blog posts.
Does working to improve APIs across thousands of companies sound interesting to you? Are you obsessed with developer experiences and want to help us build the future of APIs? We’re hiring for a bunch of roles at https://readme.com/careers and can’t wait to hear from you!