Skip to content

OpenAPI 3.1+: nullable is not converted and examples is downgraded to example #954

Description

@minseonkkim

Prerequisites

  • I have written a descriptive issue title
  • I have searched existing issues to ensure the bug has not already been reported

Fastify version

5.12.5

Plugin version

9.9.0

Node.js version

24.21.0

Operating system

Windows

Operating system version (i.e. 20.04, 11.3, 10)

win32 10.0.26200

Description

When generating an OpenAPI 3.1 (or 3.2) document, @fastify/swagger passes through keywords that only exist in OpenAPI 3.0:

  1. nullable: true is emitted as-is. OpenAPI 3.1 uses JSON Schema 2020-12, where nullable no longer exists (as also noted in the comment above isOpenapi30() in lib/spec/openapi/utils.js). Tools reading a 3.1 document ignore it, so the nullability is silently lost. For example, openapi-typescript does not generate string | null for such properties (see Support nullable as type arrays for OpenAPI 3.1 openapi-ts/openapi-typescript#898).
  2. examples is converted to example. OpenAPI 3.1 Schema Objects support the JSON Schema examples array, but the plugin converts it to the deprecated example keyword and drops every example after the first.

Since Ajv supports nullable: true, many Fastify users write schemas this way. Switching the openapi option from 3.0.3 to 3.1.0 then produces a document that no longer describes these fields correctly.

The opposite direction (type: ['string', 'null'] → nullable: true for 3.0) was recently implemented in #939 (fixes #889). This issue proposes the symmetric conversion for 3.1+.

Reproduction

import Fastify from 'fastify'
import swagger from '@fastify/swagger'

for (const version of ['3.0.3', '3.1.0']) {
  const app = Fastify()
  await app.register(swagger, {
    openapi: { openapi: version, info: { title: 'repro', version: '1.0.0' } }
  })

  app.post('/', {
    schema: {
      body: {
        type: 'object',
        properties: {
          nullableKeyword: { type: 'string', nullable: true },
          typeArray: { type: ['string', 'null'] },
          multipleExamples: { type: 'string', examples: ['foo', 'bar'] }
        }
      }
    }
  }, async () => ({}))

  await app.ready()
  const { properties } = app.swagger().paths['/'].post.requestBody.content['application/json'].schema
  console.log(version, JSON.stringify(properties, null, 2))
}

Actual output (3.1.0)

{
  "nullableKeyword": { "type": "string", "nullable": true },
  "typeArray": { "type": ["string", "null"] },
  "multipleExamples": { "type": "string", "example": "foo" }
}

The same output is produced for 3.2.0. The 3.0.3 output is correct.

Link to code that reproduces the bug

https://github.com/minseonkkim/fastify-swagger-openapi31-repro

Expected Behavior

No response

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugConfirmed bug

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions