Skip to content

Add $self for self-identifying documents #4389

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 11 commits into
base: v3.2-dev
Choose a base branch
from
96 changes: 91 additions & 5 deletions src/oas.md
Original file line number Diff line number Diff line change
Expand Up @@ -308,21 +308,104 @@ Note that some URI fields are named `url` for historical reasons, but the descri

Unless specified otherwise, all fields that are URIs MAY be relative references as defined by [RFC3986](https://tools.ietf.org/html/rfc3986#section-4.2).

Relative references in [Schema Objects](#schema-object), including any that appear as `$id` values, use the nearest parent `$id` as a Base URI, as described by [JSON Schema Specification Draft 2020-12](https://www.ietf.org/archive/id/draft-bhutton-json-schema-01.html#section-8.2).
#### Establishing the Base URI

Relative URI references in other Objects, and in Schema Objects where no parent schema contains an `$id`, MUST be resolved using the referring document's base URI, which is determined in accordance with [[RFC3986]] [Section 5.1.2 – 5.1.4](https://tools.ietf.org/html/rfc3986#section-5.1.2).
In practice, this is usually the retrieval URI of the document, which MAY be determined based on either its current actual location or a user-supplied expected location.
Relative URI references are resolved using the appropriate base URI, which MUST be determined in accordance with [[RFC3986]] [Section 5.1.1 – 5.1.4](https://tools.ietf.org/html/rfc3986#section-5.1.1).
RFC3986 Section 5.1.1 requires determining the base URI from within a resource's contents, which for the OAS means the `$self` field of the [OpenAPI Object](#openapi-object) for an [OpenAPI Document](#openapi-document), or the `$id` JSON Schema keyword in [Schema Objects](#schema-object).
Within an OpenAPI Document, a Schema Object that does not have its base URI set by `$id` takes its base URI from the OpenAPI Object's `$self` field the same as any other Object, treating the OpenAPI Document as the "encapsulating entity" in accordance with RFC3986 Section 5.1.2.
See [JSON Schema draft 2020-12 Section 8.2](https://www.ietf.org/archive/id/draft-bhutton-json-schema-01.html#section-8.2) for more information about base URIs in Schema Objects.

The most common base URI source in the absence of `$self` or `$id` is the retrieval URI, in accordance with RFC3986 Section 5.1.3.

Note that these rules mean that different fields in the document, particularly those in Schema Objects vs other kinds of Objects, can have different base URIs.
Relative URI references in `$self` or `$id` are resolved against the base URI appropriate for their location in the document.

Implementations SHOULD allow users to provide the intended retrieval URI along with each document, as this is necessary in situations including:

* Implementations that do not support direct retrieval, which requires additional dependencies and security considerations
* Network configurations or conditions that prevent direct retrieval
* Test configurations that need to simulate the document being hosted in a production location
* Documents that exist only in-memory and have no readily identifiable location (although for a single document without references to other documents, an application-specific default base URI in accordance with RFC3986 Section 5.1.4 would also be suitable)

Base URIs for documents containing OpenAPI content without an OpenAPI Object at the root ignore the `$self` rule, as no `$self` can be present in such documents.

##### Examples of Base URI Determination and Reference Resolution

Given a retrieval URI of `https://example.com/foo/bar/openapi.yaml`, and the following OpenAPI Document:

```YAML
openapi: 3.2.0
$self: /openapi
info:
title: Example API
version: 1.0
components:
pathItems:
Foo:
$ref: "./shared#/components/pathItems/Foo"
```

1. The base URI used to resolve `$self` is the retrieval URI, resulting in an effective `$self` value of `https://example.com/openapi` (OADs that use HTTP content negotiation to provide both JSON and YAML representations typically do not use a file extension in their self-assigned URI, to avoid needing to change URIs based on the format).
2. The base URI for the `$ref` comes from `$self` (`https://example.com/openapi`), producing a resolved URI of `https://example.com/shared#/components/pathItems/Foo`.

Relative `$self` values are often used for APIs deployed in multiple locations, such as a device management API that is hosted on each device.

In the next example, the retrieval URI is irrelevant, because `$self` is already a fully resolved URI rather than a relative URI-reference:

```YAML
openapi: 3.2.0
$self: https://example.com/openapi
info:
title: Example API
version: 1.0
components:
schemas:
Foo:
$id: ./schemas/foo
properties:
bar:
$ref: bar
Bar:
$id: ./schemas/bar
```

In this example, both Schema Objects use `https://example.com/openapi` as their base URI for resolving their relative `$id` values to `https://example.com/schemas/foo` and `https://example.com/schemas/bar`. The `$ref` under `properties` is resolved against the `$id`-provided base URI `https://example.com/schemas/foo`, producing `https://example.com/schemas/bar`, which is the `$id`-assigned URI of the `Bar` schema component.

Note that using embedded `$id` keywords would prevent using `$ref: "#/components/schemas/Bar"` in the `properties` keyword's `$ref` because the base URI for such fragments is set by the `$id`. Therefore, a `$ref: "#/components/schemas/Bar"` would resolve to `"https://example.com/schemas/foo#/components/schemas/Bar"`, rather than the presumably-intended location of `"https://example.com/openapi#/components/schemas/Bar"`.

#### Resolving URI fragments

If a URI contains a fragment identifier, then the fragment should be resolved per the fragment resolution mechanism of the referenced document. If the representation of the referenced document is JSON or YAML, then the fragment identifier SHOULD be interpreted as a JSON-Pointer as per [RFC6901](https://tools.ietf.org/html/rfc6901).

#### Relative URI References in CommonMark Fields

Relative references in CommonMark hyperlinks are resolved in their rendered context, which might differ from the context of the API description.

### Relative References in API URLs

API endpoints are by definition accessed as locations, and are described by this specification as **_URLs_**.

Unless specified otherwise, all fields that are URLs MAY be relative references as defined by [RFC3986](https://tools.ietf.org/html/rfc3986#section-4.2).
Unless specified otherwise, relative references are resolved using the URLs defined in the [Server Object](#server-object) as a Base URL. Note that these themselves MAY be relative to the referring document.
Unless specified otherwise, relative references are resolved using the URLs defined in the [Server Object](#server-object) as a Base URL. Note that these themselves MAY be relative to the referring document (**NOT** the [OpenAPI Object's](#openapi-object) `$self` field).

#### Examples of API Base URL Determination

Assume a retrieval URL of `https://device1.example.com` for the following OpenAPI Document:

```YAML
openapi: 3.2.0
$self: https://apidescriptions.example.com/foo
info:
title: Example API
version: 1.0
servers:
- url: .
description: The production API on this device
- url: ./test
description: The test API on this device
```

For API URLs, the `$self` field, which identifies the OpenAPI Document, is ignored, and the retrieval URL is used instead. This produces a normalized production URL of `https://device1.example.com`, and a normalized test URL of `https://device1.example.com/test`.

### Schema

Expand All @@ -342,6 +425,7 @@ This is the root object of the [OpenAPI Description](#openapi-description).
| Field Name | Type | Description |
| ---- | :----: | ---- |
| <a name="oas-version"></a>openapi | `string` | **REQUIRED**. This string MUST be the [version number](#versions) of the OpenAPI Specification that the OpenAPI Document uses. The `openapi` field SHOULD be used by tooling to interpret the OpenAPI Document. This is _not_ related to the API [`info.version`](#info-version) string. |
| <a name="oas-self"></a>$self | `string` | This string MUST be in the form of a URI-reference, MUST NOT be an empty string, and MUST NOT contain a fragment (empty or otherwise). The `$self` field provides the self-assigned URI of this document, which also serves as its base URI in accordance with [[RFC3986]] [Section 5.1.1](https://www.rfc-editor.org/rfc/rfc3986#section-5.1.1). Implementations MUST support identifying the targets of [API description URIs](#relative-references-in-api-description-uris) using the resolved URI defined by this field, as shown under [Examples of Base URI Determination and Reference Resolution](#examples-of-base-uri-determination-and-reference-resolution). |
| <a name="oas-info"></a>info | [Info Object](#info-object) | **REQUIRED**. Provides metadata about the API. The metadata MAY be used by tooling as required. |
| <a name="oas-json-schema-dialect"></a> jsonSchemaDialect | `string` | The default value for the `$schema` keyword within [Schema Objects](#schema-object) contained within this OAS document. This MUST be in the form of a URI. |
| <a name="oas-servers"></a>servers | [[Server Object](#server-object)] | An array of Server Objects, which provide connectivity information to a target server. If the `servers` field is not provided, or is an empty array, the default value would be a [Server Object](#server-object) with a [url](#server-url) value of `/`. |
Expand Down Expand Up @@ -475,7 +559,7 @@ An object representing a Server.

| Field Name | Type | Description |
| ---- | :----: | ---- |
| <a name="server-url"></a>url | `string` | **REQUIRED**. A URL to the target host. This URL supports Server Variables and MAY be relative, to indicate that the host location is relative to the location where the document containing the Server Object is being served. Variable substitutions will be made when a variable is named in `{`braces`}`. |
| <a name="server-url"></a>url | `string` | **REQUIRED**. A URL to the target host. This URL supports Server Variables and MAY be relative, to indicate that the host location is relative to the location where the document containing the Server Object is being served. Variable substitutions will be made when a variable is named in `{`braces`}`. Note that the [OpenAPI Object's](#openapi-object) `$self` field is **NOT** used for relative URL reference resolution. |
| <a name="server-description"></a>description | `string` | An optional string describing the host designated by the URL. [CommonMark syntax](https://spec.commonmark.org/) MAY be used for rich text representation. |
| <a name="server-name"></a>name | `string` | An optional unique string to refer to the host designated by the URL. |
| <a name="server-variables"></a>variables | Map[`string`, [Server Variable Object](#server-variable-object)] | A map between a variable name and its value. The value is used for substitution in the server's URL template. |
Expand All @@ -484,6 +568,8 @@ This object MAY be extended with [Specification Extensions](#specification-exten

##### Server Object Example

See also [Examples of API Base URL Determination](#examples-of-api-base-url-determination) for examples of resolving relative server URLs.

A single server would be described as:

```json
Expand Down
5 changes: 5 additions & 0 deletions src/schemas/validation/schema.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ properties:
openapi:
type: string
pattern: '^3\.2\.\d+(-.+)?$'
$self:
type: string
format: uri-reference
$comment: MUST NOT be empty, and MUST NOT contain a fragment
pattern: '^[^#]+$'
info:
$ref: '#/$defs/info'
jsonSchemaDialect:
Expand Down