Skip to content

Normalize relative ref paths to avoid duplicating schemas - #2105

Open
ctreatma wants to merge 5 commits into
swagger-api:masterfrom
ctreatma:collapse-equivalent-refs
Open

Normalize relative ref paths to avoid duplicating schemas#2105
ctreatma wants to merge 5 commits into
swagger-api:masterfrom
ctreatma:collapse-equivalent-refs

Conversation

@ctreatma

@ctreatma ctreatma commented Jun 17, 2024

Copy link
Copy Markdown

Currently, if an OpenAPI spec contains multiple relative $refs that resolve to the same external resource, but those refs reach that resource through different relative paths, swagger-parser may treat them as distinct references and create duplicate resolved components.

For example, given references such as:

From the spec root: $ref: ./components/schemas/Thing.yaml
From a file under components/paths: $ref: ../../components/schemas/Thing.yaml

both references can ultimately identify the same Thing.yaml resource, but their paths may contain different relative segments when they reach the resolver. The parser can therefore resolve the same schema more than once, producing components such as Thing and Thing_1 instead of reusing Thing.

This change normalizes URI references before they are used as keys by ResolverCache. Equivalent paths containing . or .. segments therefore share the same resolution and external-file cache entries, while the original reference is still used when loading and deserializing the resource.

Because normalization is performed in ResolverCache, the behavior applies consistently to reference types resolved through the cache rather than being limited to schemas.

Fixes #2016, fixes #1518.

@ctreatma
ctreatma force-pushed the collapse-equivalent-refs branch from 6f1d634 to 18d5450 Compare June 17, 2024 15:10
@nmarriotti

Copy link
Copy Markdown

Just ran into this issue today. Glad to see a fix is on the way (hopefully soon). Thanks!

@ctreatma
ctreatma force-pushed the collapse-equivalent-refs branch 2 times, most recently from d25dc19 to e2fd955 Compare August 8, 2024 20:11
@ctreatma
ctreatma force-pushed the collapse-equivalent-refs branch from e2fd955 to 8174b8f Compare December 20, 2024 17:08
@ctreatma

Copy link
Copy Markdown
Author

I rebased on the latest from master to confirm that the issue described in this PR still exists and that the changes in this PR are sufficient to resolve it.

@ctreatma
ctreatma force-pushed the collapse-equivalent-refs branch 2 times, most recently from 47a4931 to 26e34ae Compare January 8, 2025 17:18
@ctreatma
ctreatma force-pushed the collapse-equivalent-refs branch from 929aacc to 74720bc Compare January 17, 2025 17:20
ctreatma added a commit to equinix/equinix-sdk-go that referenced this pull request Feb 24, 2025
The semantic-release tool explicitly ignores the `.gitignore` file,
which means that the automated release process will commit all files
that are present in the local repo even if they are in the `.gitignore`.
This updates the Metal codegen task to explicitly clean up the temporary
merged spec. If swagger-api/swagger-parser#2105 gets merged and is
included in an openapi-generator release before this SDK loses support
for Metal, we can remove the temporary merged Metal spec.
@ctreatma
ctreatma force-pushed the collapse-equivalent-refs branch from 74720bc to adcfebb Compare March 31, 2025 21:11
@ctreatma
ctreatma force-pushed the collapse-equivalent-refs branch from adcfebb to 1cd8e74 Compare July 16, 2025 20:27
@ctreatma
ctreatma force-pushed the collapse-equivalent-refs branch from 1cd8e74 to ddc074b Compare November 19, 2025 17:50
@ctreatma

Copy link
Copy Markdown
Author

@MichakrawSB I see that this PR has been assigned to me but I'm not clear what needs to be done to move it forward. Is there something I need to address before the GitHub Actions workflows can be approved to run on this PR?

@ewaostrowska
ewaostrowska force-pushed the collapse-equivalent-refs branch from ddc074b to 9a05a4b Compare August 13, 2026 09:54
@ewaostrowska

Copy link
Copy Markdown
Contributor

Hi @ctreatma! Thank you for the PR :)
I reworked the normalization to keep the fix small and focused.

Instead of using Paths, normalization now happens in ResolverCache via URI.normalize(). The Paths approach followed OS filesystem rules, so on Windows it could produce backslashes like ..\schemas\Foo.yaml. OpenAPI $ref values are URI references and must use /, so that was a correctness issue on Windows regardless of the duplicate-schema problem you were fixing.

The original $ref string is preserved for loading and error reporting — only the cache key is normalized. Because canonicalization sits in ResolverCache, it applies to every loadRef caller: PathsProcessor, OperationProcessor, ParameterProcessor, and SecuritySchemeProcessor, not just schemas. The cache is the single point where ref identity is decided, so normalizing there guarantees consistent behavior regardless of which processor resolves the ref first.

I expanded the regression tests to cover #2016, #1518, #1886, URI fragments, URL and file refs, invalid URI fallback, and a non-schema ApiResponse case.

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

Labels

Projects

None yet

5 participants