DEV Community

Cover image for OpenAPI spec (swagger) v2 vs v3
Andrey Frolov
Andrey Frolov

Posted on

OpenAPI spec (swagger) v2 vs v3

It's just a compilation of other materials that I combined around the internet.

image

I've copied the image this from this article

Multiple Hosts

OpenAPI 2.0 allowed specifying a single host and basePath, and yet the schemes attribute allows specifying both http and https, therefore effectively enabling two hosts that only vary in the scheme. In the OpenAPI.vNext, the working branch of the spec repo, a new root level hosts object contains an array of objects that contain host, basePath, and scheme properties.

By structuring this as an array of objects, any number of root URLs for the API can be supported, and it allows for a clearer correlation of the scheme, host, and basePath properties. It also reduces the number of root level properties required, simplifying the document structure.

image

Additionally, the host, basePath, and scheme may be overriden at the path item level. This should make it easier to incorporate functionality provided on a separate host into an API description.

image

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']
Enter fullscreen mode Exit fullscreen mode

OpenAPI 3

servers:
- url: https://{subdomain}.site.com/{version}
  description: The main prod server
  variables:
    subdomain:
      default: production
    version:
      enum:
        - v1
        - v2
      default: v2
Enter fullscreen mode Exit fullscreen mode

There’s a few minor changes to path items, too. They now can accept a description. Also you can now give each path its own base URL (http://login.example.com, for example).

URL verbs

You’re no longer allowed to define a request body for GET and DELETE (which matches how RESTful APIs work). Lastly, there's support for TRACE.

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.

Open API spec 3.0 provides components object which can contain:

  • schemas
  • parameters
  • responses
  • examples
  • security schemes
  • links
  • request bodies
  • headers
  • callbacks

This component object won’t affect the API until it is referenced somewhere in the API.

Advantage : If multiple operations of an API needs similar input structure the the input structure can be defined under component as request bodies and can be reused in multiple paths. Similarly headers, responses and so on can be reused.

"components": {
  "schemas": {
    "Category": {
      "type": "object",
      "properties": {
        "id": {
          "type": "integer",
          "format": "int64"
        },
        "name": {
          "type": "string"
        }
      }
    },
    "Tag": {
      "type": "object",
      "properties": {
        "id": {
          "type": "integer",
          "format": "int64"
        },
        "name": {
          "type": "string"
        }
      }
    }
  },
  "parameters": {
    "skipParam": {
      "name": "skip",
      "in": "query",
      "description": "number of items to skip",
      "required": true,
      "schema": {
        "type": "integer",
        "format": "int32"
      }
    },
    "limitParam": {
      "name": "limit",
      "in": "query",
      "description": "max records to return",
      "required": true,
      "schema" : {
        "type": "integer",
        "format": "int32"
      }
    }
  },
  "responses": {
    "NotFound": {
      "description": "Entity not found."
    },
    "IllegalInput": {
      "description": "Illegal input for operation."
    },
    "GeneralError": {
      "description": "General Error",
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/GeneralError"
          }
        }
      }
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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.

Request body content negotiation

The 3.0 release features a requestBody that supports content negotiation so that you can define different schemas and examples for various media types. The requestBody allows web services to accept and return data in different formats, such as images, plain text, XML, and JSON. It also allows you to provide one or multiple examples.

Examples

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

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'
Enter fullscreen mode Exit fullscreen mode

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.

To this end, the 3.0 draft specification introduces the links object in order to describe which new resources may be accessed based on the information retrieved from an initial resource. This is not necessarily hypermedia-driven in that, the URLs to the new resources have not been embedded in the returned payload, but they are constructed based on rules defined in OpenAPI Specification. A new expression syntax has been introduced to allow information from a response to be correlated with parameters in the linked operation.

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: []
Enter fullscreen mode Exit fullscreen mode

OpenAPI 3

components:
  securitySchemes:
    UserSecurity:
      type: http
      scheme: basic
    APIKey:
      type: http
      scheme: bearer
      bearerFormat: TOKEN
security:
  - UserSecurity: []
  - APIKey: []
Enter fullscreen mode Exit fullscreen mode

Callbacks

Webhooks leverage HTTP in an publish/subscribe pattern, and they have become a popular pattern among API providers, including Slack, GitHub, and many other popular services. Webhooks are simple to use and fit nicely into an existing HTTP-based style of API. However, one criticism of the OpenAPI spec was that it had no way to describe an outbound HTTP request and its expected response. The new callback object makes this possible. A callback object can be attached to a subscribe operation in order to describe an outbound operation that a subscriber may expect.

image

JSON Schema

A number of requests were made to expand the subset of JSON Schema that the OpenAPI spec allows to include more complex features of JSON Schema. In the 2.0 spec process, the potential tooling complexities around code generation prompted the exclusion of anyOf and oneOf. However, many users have requested relaxing that constraint, even though it would compromise tooling support for those features. This is one of the great challenges in spec design, and it is never easy when making choices like this to know whether it is better to give people sharp tools that they could cut themselves with, or to rely on experience to say no, the burden of this responsibility is too great. While OpenAPI 2.0 took the more conservative approach, the user base has grown more experienced, so some of the restrictions are being lifted, and users will have to make smart choices.

Type Can Now Be An Array

In previous versions of OpenAPI, type could only be a single string. But in JSON Schema, type can be an array of strings. There is no workaround for this in version 2.0, but in version 3.0, you can select multiple types using oneOf:

oneOf:
  - type: string
  - type: integer
Enter fullscreen mode Exit fullscreen mode

With OpenAPI 3.1, the specification now supports type as an array:

type: [string, integer]
Enter fullscreen mode Exit fullscreen mode

Nullable is No More

Neither OpenAPI 2.0 nor 3.0 support null as a type, but JSON Schema does support type null. OpenAPI 3.0 includes the field name nullable, which you can set to true if you want the value to be null:

type: string
nullable: true
Enter fullscreen mode Exit fullscreen mode

However, support for type null has been added in version 3.1, and nullable has been removed.

type: [string, "null"]
Enter fullscreen mode Exit fullscreen mode

Links that was used for an article

Top comments (0)