DEV Community

Preecha
Preecha

Posted on

What Changed in OpenAPI 3.2 vs 3.1 vs 3.0?

TL;DR

OpenAPI 3.1 aligns schemas with JSON Schema Draft 2020-12 and introduces a top-level webhooks object. OpenAPI 3.2 adds support for the HTTP QUERY method and extends the specification for newer API patterns. Modern PetstoreAPI uses OpenAPI 3.2 to demonstrate these features with practical examples.

Try Apidog today

Introduction

When writing an OpenAPI specification, you must choose between OpenAPI 3.0, 3.1, and 3.2. That choice affects schema syntax, webhook definitions, supported HTTP methods, and compatibility with validators, documentation generators, and code generators.

The original Swagger Petstore uses Swagger 2.0. Modern PetstoreAPI uses OpenAPI 3.2 to demonstrate newer OpenAPI capabilities.

If you are building or testing REST APIs, Apidog supports importing OpenAPI 3.0, 3.1, and 3.2 specifications. You can validate schemas, inspect references, and test whether an implementation matches its contract.

This guide covers:

  • The baseline features in OpenAPI 3.0
  • The JSON Schema changes introduced in OpenAPI 3.1
  • OpenAPI 3.2 features such as QUERY
  • A practical migration process
  • How to validate the result before upgrading production tooling

OpenAPI 3.0: The Baseline

Released in July 2017, OpenAPI 3.0 was a major upgrade from Swagger 2.0.

Start a 3.0 document with:

openapi: 3.0.3

info:
  title: Petstore API
  version: 1.0.0
Enter fullscreen mode Exit fullscreen mode

1. Define multiple servers

OpenAPI 3.0 replaced Swagger 2.0's single host, basePath, and schemes configuration with a servers array:

servers:
  - url: https://api.petstoreapi.com/v1
    description: Production
  - url: https://staging.petstoreapi.com/v1
    description: Staging
Enter fullscreen mode Exit fullscreen mode

This lets documentation and testing tools switch between environments without modifying every operation.

2. Use a dedicated request body

In Swagger 2.0, JSON request bodies were defined as body parameters. OpenAPI 3.0 introduced requestBody:

paths:
  /pets:
    post:
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Pet'
      responses:
        '201':
          description: Pet created
Enter fullscreen mode Exit fullscreen mode

You can also define different schemas for different media types:

requestBody:
  content:
    application/json:
      schema:
        $ref: '#/components/schemas/Pet'
    application/xml:
      schema:
        $ref: '#/components/schemas/Pet'
Enter fullscreen mode Exit fullscreen mode

3. Reuse definitions with components

OpenAPI 3.0 consolidated reusable definitions under components:

components:
  schemas:
    Pet:
      type: object
      properties:
        id:
          type: string
        name:
          type: string

  responses:
    NotFound:
      description: Resource not found

  parameters:
    PetId:
      name: petId
      in: path
      required: true
      schema:
        type: string
Enter fullscreen mode Exit fullscreen mode

Reference these definitions with $ref:

parameters:
  - $ref: '#/components/parameters/PetId'
Enter fullscreen mode Exit fullscreen mode

4. Describe callbacks

Callbacks describe requests that the API provider sends after a client operation:

callbacks:
  orderUpdate:
    '{$request.body#/callbackUrl}':
      post:
        requestBody:
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/OrderUpdate'
        responses:
          '200':
            description: Callback accepted
Enter fullscreen mode Exit fullscreen mode

The callback URL can be derived from the original request using a runtime expression.

5. Connect operations with links

Links describe how a response value can be passed to another operation:

links:
  GetPetByPetId:
    operationId: getPetById
    parameters:
      petId: '$response.body#/id'
Enter fullscreen mode Exit fullscreen mode

This is useful for documentation, API exploration, and generated workflows.

OpenAPI 3.0 limitations

OpenAPI 3.0 remains widely supported, but it has several constraints:

  1. Its schema format is not fully compatible with standard JSON Schema.
  2. Webhooks must be represented through operation-level callbacks.
  3. Polymorphic schemas can behave differently across tools.
  4. Nullable values require the OpenAPI-specific nullable keyword.
  5. Some standard JSON Schema keywords are unavailable or behave differently.

For example, a nullable string in OpenAPI 3.0 is written as:

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

OpenAPI 3.1: JSON Schema Alignment

OpenAPI 3.1 aligns its Schema Object with JSON Schema Draft 2020-12.

Start a 3.1 document with:

openapi: 3.1.0

info:
  title: Petstore API
  version: 1.0.0
Enter fullscreen mode Exit fullscreen mode

1. Replace nullable with JSON Schema types

OpenAPI 3.0:

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

OpenAPI 3.1:

type:
  - string
  - "null"
Enter fullscreen mode Exit fullscreen mode

You can also use anyOf when the schema needs more complex validation:

anyOf:
  - type: string
  - type: "null"
Enter fullscreen mode Exit fullscreen mode

JSON Schema alignment provides several practical benefits:

  • Schemas can use standard JSON Schema validators.
  • Schema definitions can be shared with other JSON Schema-based systems.
  • You can use JSON Schema 2020-12 keywords.
  • Validation behavior is more consistent across compatible tools.

You can explicitly declare the schema dialect:

jsonSchemaDialect: https://json-schema.org/draft/2020-12/schema
Enter fullscreen mode Exit fullscreen mode

2. Define top-level webhooks

OpenAPI 3.1 introduced a top-level webhooks object.

In OpenAPI 3.0, webhook-like behavior was usually modeled as a callback attached to an operation:

paths:
  /subscribe:
    post:
      callbacks:
        orderUpdate:
          '{$request.body#/callbackUrl}':
            post:
              responses:
                '200':
                  description: Callback accepted
Enter fullscreen mode Exit fullscreen mode

In OpenAPI 3.1, an API-initiated request can be documented directly:

webhooks:
  orderUpdate:
    post:
      summary: Receive an order update
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/OrderUpdate'
      responses:
        '200':
          description: Webhook accepted
Enter fullscreen mode Exit fullscreen mode

Use a callback when the destination URL comes from a specific API operation. Use a top-level webhook when documenting an API-initiated request independently.

3. Model polymorphism with oneOf

OpenAPI 3.1 can combine JSON Schema composition with a discriminator:

components:
  schemas:
    Pet:
      oneOf:
        - $ref: '#/components/schemas/Cat'
        - $ref: '#/components/schemas/Dog'
      discriminator:
        propertyName: petType
        mapping:
          cat: '#/components/schemas/Cat'
          dog: '#/components/schemas/Dog'
Enter fullscreen mode Exit fullscreen mode

A matching payload could look like:

{
  "petType": "cat",
  "name": "Fluffy"
}
Enter fullscreen mode Exit fullscreen mode

Always test discriminator behavior with your target code generator. Implementations do not all handle polymorphism identically.

4. Use SPDX license identifiers

OpenAPI 3.1 allows an SPDX identifier in the Info Object:

info:
  title: Petstore API
  version: 1.0.0
  license:
    name: MIT
    identifier: MIT
Enter fullscreen mode Exit fullscreen mode

Use either identifier or url for the license, not both.

5. Reuse complete path items

OpenAPI 3.1 supports reusable Path Item Objects:

components:
  pathItems:
    PetsCollection:
      get:
        summary: List pets
        responses:
          '200':
            description: Pet list

paths:
  /pets:
    $ref: '#/components/pathItems/PetsCollection'
Enter fullscreen mode Exit fullscreen mode

This is useful when several paths expose the same operation structure.

Important 3.0-to-3.1 changes

nullable is removed

Replace:

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

With:

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

Exclusive bounds become numeric

OpenAPI 3.0 uses a boolean keyword:

type: number
minimum: 0
exclusiveMinimum: true
Enter fullscreen mode Exit fullscreen mode

OpenAPI 3.1 uses the exclusive bound itself:

type: number
exclusiveMinimum: 0
Enter fullscreen mode Exit fullscreen mode

Apply the same conversion to exclusiveMaximum.

Schema validation becomes stricter

Because OpenAPI 3.1 uses JSON Schema 2020-12 semantics, review:

  • example and examples
  • Tuple and array validation
  • Nullable fields
  • Composition with allOf, anyOf, and oneOf
  • Custom schema keywords
  • Numeric boundary keywords

Do not upgrade only the openapi version string. Update the affected schemas and run them through a 3.1-compatible validator.

OpenAPI 3.2: Newer HTTP Patterns

An OpenAPI 3.2 document starts with:

openapi: 3.2.0

info:
  title: Petstore API
  version: 1.0.0
Enter fullscreen mode Exit fullscreen mode

Before adopting 3.2, verify that your documentation renderer, validator, mock server, and code generator support it.

1. Describe the HTTP QUERY method

OpenAPI 3.2 adds support for the HTTP QUERY method, which is intended for safe, idempotent requests that need structured request content.

paths:
  /pets/search:
    query:
      summary: Search pets with complex criteria
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                filters:
                  type: object
                  additionalProperties: true
                sort:
                  type: array
                  items:
                    type: string
      responses:
        '200':
          description: Search results
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Pet'
Enter fullscreen mode Exit fullscreen mode

Use QUERY when:

  • The request is logically read-only.
  • Search criteria are too complex for practical query parameters.
  • Your HTTP infrastructure supports the method.
  • Your clients and code generators can send it correctly.

Do not switch existing GET endpoints automatically. Proxies, gateways, frameworks, and client libraries may not yet support QUERY.

2. Provide named examples

Named examples make generated documentation and test cases more useful:

content:
  application/json:
    schema:
      $ref: '#/components/schemas/Pet'
    examples:
      availableCat:
        summary: Available cat
        description: A cat available for adoption
        value:
          id: "019b4132-70aa-764f-b315-e2803d882a24"
          name: Fluffy
          species: CAT
          status: AVAILABLE

      adoptedDog:
        summary: Adopted dog
        value:
          id: "019b4127-54d5-76d9-b626-0d4c7bfce5b6"
          name: Buddy
          species: DOG
          status: ADOPTED
Enter fullscreen mode Exit fullscreen mode

Include examples for:

  • Successful requests
  • Successful responses
  • Validation failures
  • Authentication failures
  • Boundary values
  • Each polymorphic schema variant

Named Example Objects are not exclusive to OpenAPI 3.2, but they remain an important part of a useful 3.2 specification.

3. Fully document OAuth flows

A complete OAuth authorization code flow can include authorization, token, and refresh URLs:

components:
  securitySchemes:
    oauth2:
      type: oauth2
      flows:
        authorizationCode:
          authorizationUrl: https://petstoreapi.com/oauth/authorize
          tokenUrl: https://petstoreapi.com/oauth/token
          refreshUrl: https://petstoreapi.com/oauth/refresh
          scopes:
            pets:read: Read pets
            pets:write: Create and update pets
            orders:read: Read orders
Enter fullscreen mode Exit fullscreen mode

Apply scopes at the document or operation level:

security:
  - oauth2:
      - pets:read
Enter fullscreen mode Exit fullscreen mode

For an operation requiring write access:

paths:
  /pets:
    post:
      security:
        - oauth2:
            - pets:write
Enter fullscreen mode Exit fullscreen mode

refreshUrl is not itself new to OpenAPI 3.2, so it should not be the sole reason to upgrade. Add it when it accurately describes your OAuth implementation.

4. Make discriminator mappings explicit

For portable polymorphism, use explicit component references:

discriminator:
  propertyName: type
  mapping:
    cat: '#/components/schemas/Cat'
    dog: '#/components/schemas/Dog'
    bird: '#/components/schemas/Bird'
Enter fullscreen mode Exit fullscreen mode

Explicit $ref targets are generally easier for tools to resolve than relying on implicit schema-name matching.

5. Deprecate individual fields

Mark deprecated schema properties and tell clients what to use instead:

properties:
  oldField:
    type: string
    deprecated: true
    description: Use newField instead.

  newField:
    type: string
Enter fullscreen mode Exit fullscreen mode

Deprecation metadata was available before OpenAPI 3.2, but it remains useful when maintaining a modern specification.

How Modern PetstoreAPI Uses OpenAPI 3.2

Modern PetstoreAPI demonstrates OpenAPI 3.2 features in a complete specification.

1. Inspect the full specification

The OpenAPI document is available at:

https://petstoreapi.com/openapi.json

Download it locally for validation:

curl -o openapi.json https://petstoreapi.com/openapi.json
Enter fullscreen mode Exit fullscreen mode

Check the declared version:

jq '.openapi' openapi.json
Enter fullscreen mode Exit fullscreen mode

2. Inspect the QUERY operation

The search operation follows this structure:

/pets/search:
  query:
    summary: Search pets with complex criteria
    requestBody:
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/PetSearchQuery'
Enter fullscreen mode Exit fullscreen mode

When testing this operation, confirm that your HTTP client allows a request body with QUERY.

3. Inspect webhook definitions

Webhook operations are defined separately from normal API paths:

webhooks:
  petStatusChanged:
    post:
      summary: Pet status changed
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PetStatusWebhook'
Enter fullscreen mode Exit fullscreen mode

Use this definition to generate a mock webhook receiver or validate webhook payloads.

4. Inspect polymorphic pet schemas

The base Pet schema supports multiple concrete variants:

Pet:
  oneOf:
    - $ref: '#/components/schemas/Cat'
    - $ref: '#/components/schemas/Dog'
    - $ref: '#/components/schemas/Bird'
  discriminator:
    propertyName: species
Enter fullscreen mode Exit fullscreen mode

Test at least one valid payload for each variant and one invalid payload with an unknown species value.

5. Use examples as test fixtures

The specification includes examples for different endpoint scenarios. Extract these examples and use them as:

  • Documentation samples
  • Mock server responses
  • Contract test fixtures
  • Regression test inputs

Examples should still be validated against their associated schemas. An example is useful only if it remains synchronized with the contract.

6. Return RFC 9457 problem details

Error responses can use the application/problem+json media type:

responses:
  '400':
    description: Bad Request
    content:
      application/problem+json:
        schema:
          $ref: '#/components/schemas/ProblemDetails'
Enter fullscreen mode Exit fullscreen mode

A representative response might look like:

{
  "type": "https://petstoreapi.com/problems/invalid-request",
  "title": "Invalid request",
  "status": 400,
  "detail": "The species field is required",
  "instance": "/pets"
}
Enter fullscreen mode Exit fullscreen mode

See the complete OpenAPI specification for all definitions and examples.

Migration Guide

Treat an OpenAPI upgrade as a compatibility project rather than a version-number change.

A safe workflow is:

  1. Create a migration branch.
  2. Update the openapi version.
  3. Convert incompatible schema syntax.
  4. Run structural validation.
  5. Validate all examples.
  6. Regenerate clients and server stubs.
  7. Review generated-code changes.
  8. Run contract and integration tests.
  9. Confirm documentation and gateway compatibility.

Migrate from OpenAPI 3.0 to 3.1

Step 1: Replace nullable

Before:

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

After:

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

Search for every nullable field:

grep -R "nullable:" .
Enter fullscreen mode Exit fullscreen mode

Do not forget nullable array items or properties inside referenced components.

Step 2: Convert exclusive numeric bounds

Before:

type: number
minimum: 0
exclusiveMinimum: true
Enter fullscreen mode Exit fullscreen mode

After:

type: number
exclusiveMinimum: 0
Enter fullscreen mode Exit fullscreen mode

Before:

type: number
maximum: 100
exclusiveMaximum: true
Enter fullscreen mode Exit fullscreen mode

After:

type: number
exclusiveMaximum: 100
Enter fullscreen mode Exit fullscreen mode

Step 3: Decide whether callbacks should become webhooks

Keep callbacks when the callback is tied to an operation and its destination is derived from that operation's request or response.

Use top-level webhooks for independently documented API-initiated requests:

webhooks:
  orderUpdated:
    post:
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/OrderUpdate'
      responses:
        '204':
          description: Update accepted
Enter fullscreen mode Exit fullscreen mode

Step 4: Validate JSON Schema behavior

Pay special attention to:

oneOf:
anyOf:
allOf:
not:
if:
then:
else:
dependentRequired:
unevaluatedProperties:
Enter fullscreen mode Exit fullscreen mode

A schema that was accepted by an OpenAPI 3.0 tool may produce different results under JSON Schema 2020-12 semantics.

Step 5: Test downstream tools

Before merging, verify:

  • Documentation renders correctly.
  • Mock servers start successfully.
  • Client generation completes.
  • Server stub generation completes.
  • API gateways accept the document.
  • Contract tests still pass.

Migrate from OpenAPI 3.1 to 3.2

Step 1: Update the version

openapi: 3.2.0
Enter fullscreen mode Exit fullscreen mode

Run your existing validation pipeline immediately. This reveals tools that reject 3.2 before you add any 3.2-specific features.

Step 2: Add QUERY only where appropriate

/pets/search:
  query:
    summary: Search pets
    requestBody:
      required: true
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/PetSearchQuery'
Enter fullscreen mode Exit fullscreen mode

Test the operation through every relevant layer:

  • Client library
  • Browser or frontend runtime
  • Reverse proxy
  • CDN
  • API gateway
  • Application framework
  • Monitoring and logging stack

If any required component rejects QUERY, keep the existing GET or POST design until the infrastructure is ready.

Step 3: Improve examples

Add descriptive names and realistic values:

examples:
  availablePet:
    summary: Pet available for adoption
    value:
      name: Fluffy
      species: CAT
      status: AVAILABLE

  adoptedPet:
    summary: Pet already adopted
    value:
      name: Buddy
      species: DOG
      status: ADOPTED
Enter fullscreen mode Exit fullscreen mode

Validate examples in CI so they do not drift from their schemas.

Step 4: Review security definitions

Check that OAuth definitions match the real authorization server:

authorizationUrl: https://petstoreapi.com/oauth/authorize
tokenUrl: https://petstoreapi.com/oauth/token
refreshUrl: https://petstoreapi.com/oauth/refresh
Enter fullscreen mode Exit fullscreen mode

Also verify operation-level scopes. A valid security scheme can still be incorrect if operations request the wrong permissions.

Step 5: Check generator support

Generate a test client before adopting 3.2 in production. Confirm that the generator:

  • Recognizes the document version
  • Handles QUERY
  • Generates request bodies correctly
  • Preserves security scopes
  • Resolves discriminator mappings
  • Does not silently ignore unsupported fields

Testing OpenAPI Specifications with Apidog

Apidog can import OpenAPI 3.x specifications and help validate the resulting API contract.

Import the specification

  1. Open Apidog.
  2. Select Import.
  3. Choose OpenAPI 3.x.
  4. Paste the specification URL or upload the JSON or YAML file.
  5. Review the validation results.
  6. Confirm that endpoints, schemas, examples, and security schemes were imported correctly.

For Modern PetstoreAPI, use:

https://petstoreapi.com/openapi.json
Enter fullscreen mode Exit fullscreen mode

Validate the contract

Review the imported specification for:

  • Invalid schema keywords
  • Missing or unresolved $ref values
  • Examples that do not match schemas
  • Incomplete security definitions
  • Missing required path parameters
  • Invalid response definitions
  • Duplicate or missing operation IDs

Test the implementation

Generate or configure test cases for:

  • Required request fields
  • Request schema validation
  • Response schema validation
  • Expected status codes
  • Authentication and authorization
  • Invalid enum values
  • Polymorphic payloads
  • Problem-detail error responses

For example, test a valid pet payload:

{
  "name": "Fluffy",
  "species": "CAT",
  "status": "AVAILABLE"
}
Enter fullscreen mode Exit fullscreen mode

Then test an invalid payload:

{
  "name": "Fluffy",
  "species": "UNKNOWN",
  "status": "AVAILABLE"
}
Enter fullscreen mode Exit fullscreen mode

The second request should fail if species is restricted to known values.

Compare versions before deployment

Import the current and migrated specifications, then review:

  • Removed endpoints
  • New endpoints
  • Changed required properties
  • Type changes
  • Enum changes
  • New authentication requirements
  • Deprecated operations or fields
  • Changed request and response schemas

Treat these changes as potentially breaking until client compatibility has been verified.

Which Version Should You Use?

Use OpenAPI 3.0 when:

  • Your toolchain does not fully support 3.1.
  • You depend on older code generators or API gateways.
  • You do not need JSON Schema 2020-12 features.

Use OpenAPI 3.1 when:

  • You want JSON Schema 2020-12 alignment.
  • You need top-level webhooks.
  • You want to share schemas with other JSON Schema tools.
  • Your validators and generators support it.

Use OpenAPI 3.2 when:

  • You need features such as the QUERY method.
  • Your complete toolchain supports 3.2.
  • You have tested generated clients, gateways, mocks, and documentation against the specification.

For many teams, OpenAPI 3.1 is the practical migration target while OpenAPI 3.2 support continues to expand across tools.

Conclusion

OpenAPI has evolved in three important stages:

  • OpenAPI 3.0: Introduced servers, request bodies, components, callbacks, and links.
  • OpenAPI 3.1: Aligned schemas with JSON Schema 2020-12 and added top-level webhooks.
  • OpenAPI 3.2: Added support for newer HTTP patterns such as QUERY.

Modern PetstoreAPI demonstrates these features through an OpenAPI 3.2 specification. Use it to inspect syntax, test tool compatibility, and compare implementation approaches.

When migrating, update schema syntax first, validate every reference and example, and test all downstream tooling before deploying the new specification.

FAQ

Should I upgrade to OpenAPI 3.1 or 3.2?

Upgrade to OpenAPI 3.1 if you need JSON Schema 2020-12 alignment and your tools support it. Upgrade to 3.2 when you need 3.2-specific features such as QUERY and have verified your entire toolchain.

Will an OpenAPI 3.0 specification work with 3.1 tools?

Many 3.1 tools can read 3.0 specifications, but changing the document version to 3.1 requires schema updates. In particular, convert nullable, exclusiveMinimum, and exclusiveMaximum.

Do code generators support OpenAPI 3.2?

Support varies. Check your generator's documentation and run a generation test. A tool may accept the document while ignoring unsupported 3.2 features.

Can I use OpenAPI 3.2 features in a 3.1 document?

No. The declared OpenAPI version must match the features used by the document. If you define a QUERY operation, declare OpenAPI 3.2.

How do I validate an OpenAPI specification?

Import it into Apidog and review schema validity, references, examples, and security definitions. Also validate it in CI and test all generated artifacts before merging changes.

Where can I see a complete OpenAPI 3.2 example?

Modern PetstoreAPI provides its specification at:

https://petstoreapi.com/openapi.json

What is the difference between webhooks and callbacks?

A callback is attached to an API operation and often derives its destination URL from that operation. A top-level webhook documents an API-initiated request independently of a specific path operation.

Should I use JSON or YAML?

Both formats represent the same OpenAPI document.

Use YAML when human readability and manual editing are the priority. Use JSON when your workflow depends on JSON-native tooling or generated specifications. Modern PetstoreAPI provides a JSON specification that can be downloaded and inspected directly.

Top comments (0)