Skip to content

fix: support $ref to definitions of shared schemas - #952

Merged
mcollina merged 5 commits into
mainfrom
fix/639-shared-schema-definitions
Sep 25, 2026
Merged

mcollina merged 5 commits into
mainfrom
fix/639-shared-schema-definitions

Conversation

@Tony133

@Tony133 Tony133 commented Sep 20, 2026 •

Copy link
Copy Markdown
Member

Proposal:

Swagger 2.0 and OpenAPI do not allow the definitions keyword inside a schema object, so the plugin drops it from shared schemas. The $refs pointing into it were left untouched though, producing dangling references such as #/definitions/def-0/definitions/foo.

Moreover, the exact example of #639 (a nested $id: '#address') currently throws Cannot redefine property: Symbol(json-schema-resolver.refToDef), because the shared schemas are mapped again as externalSchemas on every resolve() call and their subschemas are evaluated against the wrong base URI.

This PR follows the approach suggested in the review of #676: instead of moving definitions somewhere else inside the schema, every nested definition is hoisted to the top-level definitions / components.schemas, and the references are rewritten through a map.

Reference Before After
http://foo/common.json#/definitions/foo #/components/schemas/def-0/definitions/foo (missing) #/components/schemas/def-0-foo
http://foo/common.json#address #/components/schemas/def-0address (missing) #/components/schemas/def-0-foo

In detail:

  • nested definitions and $defs are hoisted as <schema>-<key>, at any depth (definitions nested in definitions, or in a property subschema); name collisions get a numeric suffix;
  • all the $refs of the final document are rewritten with a longest-prefix match, so .../definitions/foo/properties/city keeps its trailing pointer;
  • local references of a shared schema (#/definitions/foo, #/properties/bar, #) are made absolute before the resolution, since # becomes the root of the whole document once the schema lands there;
  • references to an anchor (http://foo/common.json#address, or #address from inside the shared schema) are converted to the JSON pointer of the anchored subschema before the resolution, since the ref resolver appends the fragment to the definition name as it is (def-0address). This is the form used by the Fastify "Fluent Schema" guide, mentioned in the comments of JSON Schema Definitions not work #639. The route schemas are cloned, not mutated, and only when at least one anchor exists;
  • the fragment-only $ids are then removed from the cloned shared schemas: nothing points to them anymore, the ref resolver would list each of them as a duplicated definition (def-1), and Swagger 2.0 does not accept a nested $id;
  • the schemas already known by the ref resolver are no longer passed as externalSchemas, which fixes the crash.

The walker is schema-aware: a property named definitions, or data inside enum/default/examples, is not mistaken for a keyword. The final rewrite walk only runs when something has been hoisted.

Known limitations:

Note:

  • Tests cover both Swagger 2.0 and OpenAPI modes with the exact schema of the issue, the shape of the Fluent Schema guide (references by anchor, by pointer and local anchors), anchors outside of definitions, nested definitions, $defs, local and recursive refs, name collisions and JSON pointer escaping. Generated documents are validated with swagger-parser.
  • The README has a new section about the definitions/$defs of shared schemas, describing the <schema>-<key> naming and how to reference an anchor.

Fixes #639
Refs #675, #676

@Tony133
Tony133 force-pushed the fix/639-shared-schema-definitions branch from 3073a0b to 6ad810b Compare September 20, 2026 10:21
@Tony133 Tony133 changed the title fix: support to definitions of shared schemas fix: support $ref to definitions of shared schemas Sep 20, 2026
@Tony133
Tony133 force-pushed the fix/639-shared-schema-definitions branch from 6ad810b to a9d73ac Compare September 20, 2026 10:35
Signed-off-by: Antonio Tripodi <Tony133@users.noreply.github.com>
@Tony133
Tony133 marked this pull request as ready for review September 21, 2026 19:42
@Tony133
Tony133 requested a review from mcollina September 22, 2026 08:12
Comment thread lib/util/definitions.js
Comment thread lib/util/definitions.js
@Tony133
Tony133 requested a review from Fdawgs September 22, 2026 13:23
@Tony133
Tony133 requested review from gurgunday and removed request for Fdawgs September 23, 2026 20:55

@mcollina mcollina left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we are walking the schema tree multiple times, and this is a relatively expensive operation. Could you minimize?

Comment thread lib/util/definitions.js Outdated
Comment thread lib/util/definitions.js Outdated
@Tony133
Tony133 requested a review from mcollina September 25, 2026 11:53

@mcollina mcollina left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm

@mcollina
mcollina merged commit 5285637 into main Sep 25, 2026
20 checks passed
@mcollina
mcollina deleted the fix/639-shared-schema-definitions branch September 25, 2026 14:00
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.

JSON Schema Definitions not work

3 participants