Skip to content

Support local dereferencing of schema anchors#492

Open
ayushshrivastv wants to merge 15 commits into
mattpolzin:mainfrom
ayushshrivastv:LocalAnchorDereferencing.swift
Open

Support local dereferencing of schema anchors#492
ayushshrivastv wants to merge 15 commits into
mattpolzin:mainfrom
ayushshrivastv:LocalAnchorDereferencing.swift

Conversation

@ayushshrivastv

Copy link
Copy Markdown
Contributor

Closes #363

Summary

  • preserve local #anchor references as a first-class JSONReference.InternalReference case
  • make Document.locallyDereferenced() build an anchor-aware temporary lookup so schema anchors can resolve during local dereferencing
  • teach component lookup to resolve local schema anchors without changing non-schema component lookup behavior
  • add regression coverage for anchor parsing and document dereferencing

Implementation Details

OpenAPI 3.1 schema anchors live outside the Components Object, but local dereferencing in OpenAPIKit currently resolves only through document.components. To keep the fix narrow and avoid changing unrelated reference behavior, this patch keeps the anchor support scoped to local dereferencing:

  • JSONReference<...>.InternalReference now preserves #anchor values as .anchor(name:) instead of collapsing them into a generic path reference.
  • JSONReference<JSONSchema>.anchor(named:) was added as a convenience constructor for local schema anchor references.
  • Document.locallyDereferenced() now uses a temporary, anchor-aware copy of components that is populated by walking the document's inline and component-hosted schemas and registering anchored schemas for lookup during dereferencing.
  • Components+JSONReference now recognizes .anchor(name:) for JSONSchema lookups so the existing dereference machinery can resolve anchored schemas and continue following nested references/cycles consistently.

This keeps the public fix focused on the issue at hand: local document dereferencing now works for $ref: '#someAnchor' without widening non-schema or non-local lookup behavior.

Testing

  • swift test --filter JSONReferenceTests
  • swift test --filter DereferencedDocumentTests
  • swift test --filter ComponentsTests
  • swift test

@ayushshrivastv

ayushshrivastv commented Mar 22, 2026

Copy link
Copy Markdown
Contributor Author

@mattpolzin Can you guide me on this pull request? I have tried to add local dereferencing to support anchors, while trying to stay aligned with the existing code patterns, especially since this ends up touching more lines than I’d ideally like, but my test suite is still hitting some test failures. So before I make further changes, would you mind taking a quick look and letting me know if the approach is headed in the right direction?

@mattpolzin mattpolzin left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

First of all, I apologize that this PR sat for so long. I ran out of time going over the last few PRs put up the same week as this one and just haven't been able to prioritize getting nice-to-have stuff for OpenAPIKit merged since.

I would fully understand if you have moved on from this work and do not want to revisit it at this point.

However, if you would like to continue, I have a few high level questions

  1. Did you considered building out information about anchors while parsing the OpenAPI document as an alternative to the code in this PR that crawls the document after the fact? I'm just looking for an explanation of the contrasting approaches if you have one, not asking you to change how you've done it outright unless the alternative approach ends up being nicer.
  2. The collisionIndex strategy is a bit hard to follow at first read and the opaque components object entries are a bit of a bummer. As I understand it, anchors must be unique within any given resource, so maybe a strategy more along the lines of just using the nearest $id (or document base URI) and the anchor to identify the anchor would be a bit more obvious to the reader of the code given that is the way anchors get referenced in practice?

if case .anchor(name: let anchorName) = reference,
ReferenceType.self == JSONSchema.self {
guard let schema = localAnchorSchema(named: anchorName) else {
throw ReferenceError.missingOnLookup(name: reference.name ?? "unnamed", key: ReferenceType.openAPIComponentsKey)

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

This error message states the given name was not found in the Components Object at the given key, which is not where the anchor lookup would have pointed necessarily.

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.

Support local dereferencing of $ref to $anchor

2 participants