A Visual Guide to What's New in Swagger 3.0

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)
  • 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.

info:  
  title: Swagger Sample App
host: example.com  
basePath: /v1  
schemes: ['http', 'https']  
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 their 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).

"/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
"/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”.

securityDefinitions:  
  UserSecurity:
    type: basic
  APIKey:
    type: apiKey
    name: Authorization
    in: header
security:  
  - UserSecurity: []
  - APIKey: []
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.

Need Beautiful API Documentation?

ReadMe makes it easy to create amazing documentation in minutes!

Sign Up Now