Skip to content

fix: emit the schemas with an nested in the route schemas - #956

Open
Tony133 wants to merge 1 commit into
mainfrom
fix/865-nested-id-schemas
Open

Tony133 wants to merge 1 commit into
mainfrom
fix/865-nested-id-schemas

Conversation

@Tony133

@Tony133 Tony133 commented Sep 25, 2026

Copy link
Copy Markdown
Member

Proposal:

The ref resolver collects every subschema having an $id it meets while resolving the route schemas (that is what TypeBox Type.Recursive(..., { $id: 'Node' }) produces: an inline schema referencing itself with $ref: 'Node'), and rewrites the references to it as #/definitions/def-N. However components.schemas / definitions were built from ref.definitions() before the routes were processed, so:

  • the reference was left dangling (Missing $ref pointer "#/components/schemas/def-0")
  • the schema was left inline, $id included, which Swagger 2.0 rejects as well

Changes:

  • referenceInlineDefinitions() (lib/util/definitions.js): after each ref.resolve(), the subschemas matching a collected definition are replaced by { $ref: '#/definitions/def-N' } and returned. They are matched by $id, not by identity, because the resolver ignores the duplicates of an $id (the same schema used by two routes). Shared schemas, anchors ($id: '#...') and the root definitions added by the resolver (already handled by hoistDefinitions) are left alone.
  • The resolve returned by Ref() (lib/util/add-hook.js) applies it and accumulates the definitions in ref.inlineDefinitions, including the ones nested in a collected definition.
  • Both generators add ref.inlineDefinitions to the top-level definitions after the routes loop, through the usual prepareOpenapiSchemas / prepareSwaggerDefinitions.
  • hoistDefinitions now treats the definitions known to the resolver as top-level ones: otherwise a shared schema consumed by def-1 was hoisted again as def-1-def-0.

For the schema of the issue, def-0 is now emitted with its recursive $ref, and treeNodes.items becomes { $ref: '#/components/schemas/def-0' }. The document validates with swagger-parser in both OpenAPI and Swagger 2.0.

An inline $id schema is now handled exactly like a shared schema referenced with $ref: for instance a querystring property with an $id becomes a $ref parameter, as a $ref to a shared schema already does.

Note:

  • In Swagger 2.0 a schema with an $id used as the root of a response still keeps $id: 'todo.com' inline (pre-existing, unrelated to the resolver collection).
  • A shared schema object copied inline in a route (same $id as an addSchema() one) is left inline, as before.

Fixes #865

@Tony133
Tony133 marked this pull request as ready for review September 26, 2026 16:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Recursive type definition using Typebox in schema leads to broken swagger file

1 participant