Summary
When bundling, the OpenAPI Link Object operationRef is rewritten to an absolute URI. For a document loaded from the local filesystem this produces an absolute filesystem path in the output (e.g. /home/alice/project/ops.json#/paths/~1things/get), which leaks a machine-specific path and is not transferable. This diverges from how the reference implementations treat operationRef, and it's worth revisiting against the OpenAPI spec's two distinct relative-reference rules.
Current behavior
packages/apidom-reference/src/bundle/strategies/openapi-3-1/visitor.ts (and the identical logic in openapi-3-0):
// rewrite to an absolute URI so the link keeps resolving once the document
// is treated as self-contained
const absoluteURI = url.resolve(this.reference.uri, operationRef);
if (absoluteURI !== operationRef) {
linkElement.set('operationRef', absoluteURI);
}
An external operationRef therefore becomes:
- entry doc is an HTTP(S) URL → absolute URL (portable, fine)
- entry doc is a local file → absolute filesystem path (leaks
/home/..., not transferable)
operationRef points at an Operation Object, which has no Components bucket in 3.0/3.1, so it cannot be hoisted/internalized like a Reference Object or Schema.
Spec context (OpenAPI 3.1)
The spec defines two relative-reference rules with different bases:
- §4.6 Relative References in URIs — governs
$ref and operationRef: "resolved using the referring document as the Base URI" (nearest parent $id for Schemas).
- §4.7 Relative References in URLs — governs
externalDocs.url, license.url, contact.url, termsOfService, Server.url: "resolved using the URLs defined in the Server Object as a Base URL" — NOT the document base.
So operationRef re-basing against the document URI is spec-legal (§4.6). But the §4.7 URL fields must not be resolved against the document base — and ApiDOM correctly leaves all of them untouched today (verified: no license/externalDocs/contact/server.url handling in bundle or dereference). This issue is only about operationRef.
Prior art
- libopenapi (
datamodel/low/v3/link.go): OperationRef is low.NodeReference[string], treated as an opaque string — Build() performs no $ref/index resolution on it, Hash() writes it verbatim. It is never resolved or rewritten. Likewise externalDocs.url (external_doc.go) is opaque.
- Redocly: hoists/rewrites
$ref; URL references are resolved/inlined by default with --keep-url-references to preserve. No path-leaking absolute-filesystem rewrite.
- Neither reference implementation emits an absolute filesystem path into a reference value.
Proposal (decide later)
Revisit operationRef bundling across the openapi-2, openapi-3-0, and openapi-3-1 strategies. Options:
- Leave it opaque (match libopenapi) — simplest; correct for an
operationRef authored in the entry document, since its §4.6 base (the document) is unchanged.
- Re-base only when needed — leave entry-document
operationRef as-is; only re-base one carried in from a non-entry external file (where the §4.6 base changes), and even then prefer an absolute URL, never an absolute filesystem path.
- At minimum: never emit an absolute filesystem path — for a file-sourced entry doc, keep the relative form rather than leak
/home/....
Also: while here, confirm/keep the §4.7 URL fields (license.url, externalDocs.url, contact.url, termsOfService, server.url) untouched, and document that contract.
Acceptance for now
The current absolute-URI behavior is accepted as-is for the OpenAPI 3.1 bundle strategy (PR #361) — it keeps the link resolvable on the originating machine and matches the existing openapi-2 / openapi-3-0 behavior. This issue tracks the cross-version cleanup so it's decided deliberately rather than diverging one strategy mid-stream.
Surfaced during review of #361.
Summary
When bundling, the OpenAPI Link Object
operationRefis rewritten to an absolute URI. For a document loaded from the local filesystem this produces an absolute filesystem path in the output (e.g./home/alice/project/ops.json#/paths/~1things/get), which leaks a machine-specific path and is not transferable. This diverges from how the reference implementations treatoperationRef, and it's worth revisiting against the OpenAPI spec's two distinct relative-reference rules.Current behavior
packages/apidom-reference/src/bundle/strategies/openapi-3-1/visitor.ts(and the identical logic inopenapi-3-0):An external
operationReftherefore becomes:/home/..., not transferable)operationRefpoints at an Operation Object, which has no Components bucket in 3.0/3.1, so it cannot be hoisted/internalized like a Reference Object or Schema.Spec context (OpenAPI 3.1)
The spec defines two relative-reference rules with different bases:
$refandoperationRef: "resolved using the referring document as the Base URI" (nearest parent$idfor Schemas).externalDocs.url,license.url,contact.url,termsOfService,Server.url: "resolved using the URLs defined in the Server Object as a Base URL" — NOT the document base.So
operationRefre-basing against the document URI is spec-legal (§4.6). But the §4.7 URL fields must not be resolved against the document base — and ApiDOM correctly leaves all of them untouched today (verified: nolicense/externalDocs/contact/server.urlhandling in bundle or dereference). This issue is only aboutoperationRef.Prior art
datamodel/low/v3/link.go):OperationRefislow.NodeReference[string], treated as an opaque string —Build()performs no$ref/index resolution on it,Hash()writes it verbatim. It is never resolved or rewritten. LikewiseexternalDocs.url(external_doc.go) is opaque.$ref; URL references are resolved/inlined by default with--keep-url-referencesto preserve. No path-leaking absolute-filesystem rewrite.Proposal (decide later)
Revisit
operationRefbundling across the openapi-2, openapi-3-0, and openapi-3-1 strategies. Options:operationRefauthored in the entry document, since its §4.6 base (the document) is unchanged.operationRefas-is; only re-base one carried in from a non-entry external file (where the §4.6 base changes), and even then prefer an absolute URL, never an absolute filesystem path./home/....Also: while here, confirm/keep the §4.7 URL fields (
license.url,externalDocs.url,contact.url,termsOfService,server.url) untouched, and document that contract.Acceptance for now
The current absolute-URI behavior is accepted as-is for the OpenAPI 3.1 bundle strategy (PR #361) — it keeps the link resolvable on the originating machine and matches the existing openapi-2 / openapi-3-0 behavior. This issue tracks the cross-version cleanup so it's decided deliberately rather than diverging one strategy mid-stream.
Surfaced during review of #361.