diff --git a/versions/1.1.0-dev.md b/versions/1.1.0-dev.md index a2f3cad..868ea85 100644 --- a/versions/1.1.0-dev.md +++ b/versions/1.1.0-dev.md @@ -21,7 +21,7 @@ The main purpose of the Overlay Specification is to provide a way to repeatably ### Overlay -An Overlay is a JSON or YAML structure containing an ordered list of [Action Objects](#overlay-actions) that are to be applied to the target document. Each [Action Object](#action-object) has a `target` property and a modifier type (`update`, `remove`, or `copy`). The `target` property is a [[RFC9535|RFC9535 JSONPath]] query expression that identifies the elements of the target document to be updated and the modifier determines the change. +An Overlay is a JSON or YAML structure containing an ordered list of [Action Objects](#action-object) that are to be applied to the target document. Each Action Object has a `target` property and a modifier type (`update`, `remove`, or `copy`). The `target` property is a [[RFC9535|RFC9535 JSONPath]] query expression that identifies the elements of the target document to be updated and the modifier determines the change. ## Specification @@ -139,9 +139,52 @@ The properties of the resolved `copy` object MUST be compatible with the target This object MAY be extended with [Specification Extensions](#specification-extensions). -### Examples +### Specification Extensions + +While the Overlay Specification tries to accommodate most use cases, additional data can be added to extend the specification at certain points. + +The extension properties are implemented as patterned fields that are always prefixed by `"x-"`. + +| Field Pattern | Type | Description | +| ---- | :--: | ---- | +| ^x- | Any | Allows extensions to the Overlay Specification. The field name MUST begin with `x-`, for example, `x-internal-id`. Field names beginning `x-oai-` and `x-oas-` are reserved for uses defined by the [OpenAPI Initiative](https://www.openapis.org/). The value MAY be `null`, a primitive, an array or an object. | + +The extensions may or may not be supported by the available tooling, but those may be extended as well to add requested support (if tools are internal or open-sourced). + +### RFC9535 compliance + +[[RFC9535]] is a recent specification and libraries implementing JSONPath support might predate the RFC. Those libraries might differ entirely (expressions syntax is incompatible), or implement additional capabilities (superset of the RFC). A tool or library MUST fully implement [[RFC9535]] when parsing and expanding JSONPath query expressions to be compliant with the Overlay specification. + +Interoperable Overlay Documents MUST use RFC9535 JSONPath query expressions and MUST NOT use tool-specific JSONPath extensions. + +## Examples + +| Use Case | Description | +|---------------------------------------------------------------------------------|-------------------------------------------------------------------------| +| Update objects | How to **update** objects. | +| - Structured update | - **Mirror** target document **structure** update example. | +| - Targeted updates | - A **targeted update** example. | +| - Multiple target updates | - **Update multiple** target objects example | +| - Update objects given a label | - Apply **updates** to **labeled** targets using `x-oai-traits` example | +| Copy objects | How to **copy** objects. | +| - Simple copy of an object | - A **simple copy** object example. | +| - Verified target copy of an object | - **Copy** an object to a **verified target** example. | +| Move objects | How to **move** objects. | +| - Simple move of an object | - **Move** an object example. | +| Modify array objects | How to **modify array** objects. | +| - Add an array element | - **Add** an **array element** example | +| - Remove an array element | - **Remove** an **array element** example | +| - Move an array element | - **Move** an **array element** example. | +| - Replace an array element | - **Replace** an **array element** example. | + +**Note:** All examples in this section are non-normative and are provided solely to illustrate the behavior defined in the preceding normative sections. + -#### Structured Overlay Example +### Update Examples +The following examples show different ways to apply `update` actions to modify target documents. + + +#### Structured Update When updating properties throughout the target document it may be more efficient to create a single `Action Object` that mirrors the structure of the target document. e.g. @@ -169,7 +212,8 @@ actions: tags: ``` -#### Targeted Overlay Example + +#### Targeted Updates Alternatively, where only a small number of updates need to be applied to a large document, each [Action Object](#action-object) MAY be more targeted. @@ -179,22 +223,23 @@ info: title: Targeted Overlay version: 1.0.0 actions: - - target: $.paths['/foo'].get + - target: '$.paths["/foo"].get' update: description: This is the new description - - target: $.paths['/bar'].get + - target: '$.paths["/bar"].get' update: description: This is the updated description - - target: $.paths['/bar'] + - target: '$.paths["/bar"]' update: post: description: This is an updated description of a child object x-safe: false ``` -#### Wildcard Overlay Example + +#### Multiple Target Updates -One significant advantage of using the JSONPath syntax is that it allows referencing multiple nodes in the target document. This would allow a single update object to be applied to multiple target objects using wildcards and other multi-value selectors. +One significant advantage of using the JSONPath syntax is that it allows referencing multiple nodes in the target document. This would allow a single update object to be applied to multiple target objects using **wildcards** (`*`) and other multi-value selectors. ```yaml overlay: 1.0.0 @@ -202,46 +247,21 @@ info: title: Update many objects at once version: 1.0.0 actions: - - target: $.paths.*.get + - target: '$.paths.*.get' update: x-safe: true - - target: $.paths.*.get.parameters[?@.name=='filter' && @.in=='query'] + - target: '$.paths.*.get.parameters[?@.name=="filter" && @.in=="query"]' update: schema: $ref: '#/components/schemas/filterSchema' ``` -#### Array Modification Examples - -Array elements can be added using the `update` action. - -```yaml -overlay: 1.0.0 -info: - title: Add an array element - version: 1.0.0 -actions: - - target: $.paths.*.get.parameters - update: - name: newParam - in: query -``` - -Array elements can be deleted using the `remove` action. Use of array indexes to remove array items should be avoided where possible as indexes will change when items are removed. - -```yaml -overlay: 1.0.0 -info: - title: Remove an array element - version: 1.0.0 -actions: - - target: $.paths.*.get.parameters[?@.name == 'dummy'] - remove: true -``` + +#### Labeled *(Trait)* Updates -#### Traits Example +This example shows how to apply overlay updates to **labeled** targets using `x-oai-traits`. This technique allows authors to define **named update points** within a target document so overlays can apply reusable updates declaratively, rather than hard-coding document paths. -By annotating a target document (such as an [[OpenAPI]] document) using [Specification Extensions](#specification-extensions) such as `x-oai-traits`, the author of the target document MAY identify where overlay updates should be applied. +By annotating a target document (such as an [[OpenAPI]] document) using [Specification Extensions](#specification-extensions) such as `x-oai-traits`, the author of the target document can identify where overlay updates SHOULD be applied. ```yaml openapi: 3.1.0 @@ -274,10 +294,13 @@ paths: With the above OpenAPI document, the following Overlay document will apply the necessary updates to describe how paging is implemented, where that trait has been applied. +In this example, the `x-oai-traits` extension labels the `GET /items` operation as **paged**. +Using this approach, authors MAY apply shared pagination updates to every operation in the target document that defines the label. + ```yaml -overlay: 1.0.0 +overlay: 1.1.0 info: - title: Apply Traits + title: Apply labeled updates using traits version: 1.0.0 actions: - target: $.paths.*.get[?(@['x-oai-traits'][?(@ == 'paged')])] @@ -291,7 +314,7 @@ actions: # ... ``` -resulting in +This approach inverts control: the **target document** declares where updates should apply, while the **overlay** defines reusable logic that can be shared across multiple API specifications. ```yaml openapi: 3.1.0 @@ -335,22 +358,20 @@ paths: description: OK ``` -This approach allows inversion of control as to where the Overlay updates apply to the target document itself. +### Copy Examples -#### Copy example +Copy actions behave similarly to `update` actions but source the node from the document being transformed. Copy `actions` MAY be used in sequence with `update` or `remove` actions to perform more advanced transformations like moving or renaming nodes. -Copy actions behave similarly to `update` actions but source the new values to merge with the target from the document being transformed instead of providing them in the Overlay document. Copy actions MAY be used in sequence with `update` or `remove` actions to perform more advanced transformations like moving or renaming nodes. +#### Simple Copy -##### Simple copy +This example shows how to copy all operations from the `items` path item to the "some-items" path item. -This example shows how to copy all operations from the `items` path item to the `some-items` path item. - -###### Source description +#### Source Description ```yaml openapi: 3.1.0 info: - title: Example API + title: API with a paged collection version: 1.0.0 paths: /items: @@ -365,12 +386,12 @@ paths: description: OK ``` -###### Overlay +#### Overlay ```yaml overlay: 1.1.0 info: - title: Copy contents of an existing path to a new location + title: Demonstrates variations of "copy" uses version: 1.0.0 actions: - target: '$.paths["/some-items"]' @@ -378,12 +399,12 @@ actions: description: 'copies recursively all elements from the "items" path item to the new "some-items" path item without ensuring the node exists before the copy' ``` -###### Result description +#### Result Description ```yaml openapi: 3.1.0 info: - title: Example API + title: API with a paged collection version: 1.0.0 paths: /items: @@ -402,11 +423,11 @@ paths: description: OK ``` -##### Ensure the target exists and copy +#### Verified Target Copy This example shows how to copy all operations from the `items` path item to the `other-items` path item after first ensuring the target exists with an update action. -###### Source description +#### Source Description ```yaml openapi: 3.1.0 @@ -426,12 +447,12 @@ paths: description: OK ``` -###### Overlay +#### Overlay ```yaml overlay: 1.1.0 info: - title: Create a path and copy the contents of an existing path to the new path + title: Demonstrates variations of "copy" uses version: 1.0.0 actions: - target: '$.paths' @@ -441,12 +462,12 @@ actions: description: 'copies recursively all elements from the "items" path item to the new "other-items" path item while ensuring the node exists before the copy' ``` -###### Result description +#### Result Description ```yaml openapi: 3.1.0 info: - title: Example API + title: API with a paged collection version: 1.0.0 paths: /items: @@ -466,7 +487,11 @@ paths: description: OK ``` -##### Move example +### Move Examples + +A **move** operation works like a _rename_, using a sequence of actions — `update`, `copy`, then `remove` — to shift a value to a new location in the target document. + +#### Simple Move This example shows how to rename the `items` path item to `new-items` using a sequence of overlay actions: @@ -474,12 +499,12 @@ This example shows how to rename the `items` path item to `new-items` using a se 2. Use a `copy` action to copy the source path item to the target. 3. Use a `remove` action to delete the original source path item. -###### Source description +#### Source Description ```yaml openapi: 3.1.0 info: - title: Example API + title: API with a paged collection version: 1.0.0 paths: /items: @@ -494,12 +519,12 @@ paths: description: OK ``` -###### Overlay +#### Overlay ```yaml overlay: 1.1.0 info: - title: Update the path for an API endpoint + title: Demonstrates variations of "copy" uses version: 1.0.0 actions: - target: '$.paths' @@ -511,12 +536,12 @@ actions: description: 'moves (renames) the "items" path item to "new-items"' ``` -###### Result description +#### Result Description ```yaml openapi: 3.1.0 info: - title: Example API + title: API with a paged collection version: 1.0.0 paths: /new-items: @@ -531,37 +556,154 @@ paths: description: OK ``` -### Specification Extensions +### Array Examples -While the Overlay Specification tries to accommodate most use cases, additional data can be added to extend the specification at certain points. +These examples demonstrate how to modify array-valued fields using Overlay actions — specifically how to **add**, **remove**, **move**, and **replace** elements within arrays in the target document. -The extension properties are implemented as patterned fields that are always prefixed by `"x-"`. +#### Add Array Element -| Field Pattern | Type | Description | -| ---- | :--: | ---- | -| ^x- | Any | Allows extensions to the Overlay Specification. The field name MUST begin with `x-`, for example, `x-internal-id`. Field names beginning `x-oai-` and `x-oas-` are reserved for uses defined by the [OpenAPI Initiative](https://www.openapis.org/). The value MAY be `null`, a primitive, an array or an object. | +Array elements MAY be added using the `update` property. -The extensions may or may not be supported by the available tooling, but those may be extended as well to add requested support (if tools are internal or open-sourced). +```yaml +overlay: 1.1.0 +info: + title: Add an array element + version: 1.0.0 +actions: + - target: '$.paths.*.get.parameters' + update: + name: newParam + in: query +``` -### File Naming Convention +#### Remove Array Element -Overlay files MAY choose to follow the convention of a `purpose.overlay.yaml` file naming pattern. -Other file naming conventions are also supported. +Array elements MAY be deleted using the `remove` property. Use of array indexes to remove array items SHOULD be avoided where possible, as indexes will change when items are removed. -### RFC9535 compliance +```yaml +overlay: 1.1.0 +info: + title: Remove an array element + version: 1.0.0 +actions: + - target: '$.paths.*.get.parameters[?@.name == "dummy"]' + remove: +``` -[[RFC9535]] is a recent specification and libraries implementing JSONPath support might predate the RFC. Those libraries might differ entirely (expressions syntax is incompatible), or implement additional capabilities (superset of the RFC). A tool or library MUST fully implement [[RFC9535]] when parsing and expanding JSONPath query expressions to be compliant with the Overlay specification. +#### Move Array Element + +Array elements MAY be moved by combining `update`, `copy`, and `remove` actions. + +A **move** operation works like a _rename_, using these actions in sequence — `update`, `copy`, then `remove` — to shift a value to a new location in the target document. + +1. Use an `update` action to ensure the target array exists. +2. Use a `copy` action to copy the selected array element to the new target array. +3. Use a `remove` action to delete the original array element. + +```yaml +overlay: 1.1.0 +info: + title: Move an array element + version: 1.0.0 +actions: + # Ensure the target array exists + - target: '$.paths["/new-items"].get.parameters' + update: [] + + # Copy matching parameter objects from one path item to another + - target: '$.paths["/new-items"].get.parameters' + copy: '$.paths["/items"].get.parameters[?@.name == "oldParam"]' + + # Remove the parameter object from the original array + - target: '$.paths["/items"].get.parameters[?@.name == "oldParam"]' + remove: true +``` + +#### Replace Array Element + +Array elements MAY be replaced by selecting one or more matching elements and applying an `update` action to modify their properties. This is only applicable to arrays of objects—primitive-valued arrays can only be replaced in their entirety. + +```yaml +overlay: 1.1.0 +info: + title: Replace an array element + version: 1.0.0 +actions: + - target: '$.paths.*.get.parameters[?@.name == "limit"]' + update: + description: The maximum number of items to return per page. + schema: + type: integer + minimum: 1 + maximum: 100 +``` + +#### Source Description + +```yaml +openapi: 3.1.0 +info: + title: API with a paged collection + version: 1.0.0 +paths: + /items: + get: + responses: + 200: + description: OK + /some-items: + delete: + responses: + 200: + description: OK +``` + +#### Overlay + +```yaml +overlay: 1.1.0 +info: + title: Demonstrates variations of "copy" uses + version: 1.0.0 +actions: + - target: '$.paths' + update: { "/new-items": {} } + - target: '$.paths["/new-items"]' + copy: '$.paths["/items"]' + - target: '$.paths["/items"]' + remove: true + description: 'moves (renames) the "items" path item to "new-items"' +``` + +#### Result Description + +```yaml +openapi: 3.1.0 +info: + title: API with a paged collection + version: 1.0.0 +paths: + /new-items: + get: + responses: + 200: + description: OK + /some-items: + delete: + responses: + 200: + description: OK +``` -Interoperable Overlay Documents MUST use RFC9535 JSONPath query expressions and MUST NOT use tool-specific JSONPath extensions. +## Appendix A: File Naming Convention -### Comments in OpenAPI descriptions +Overlay files MAY choose to follow the convention of a `purpose.overlay.yaml` file naming pattern. Other file naming conventions are also supported. -Some formats, like [YAML](https://yaml.org/) or [JSONC](https://jsonc.org/), support using comments which do not impact the semantic meaning of the description. Applying Overlay Actions to a description MAY result in the loss of such comments in the updated description. The exact behavior is specific to the tool implementing the Overlay Specification. +**Note:** This section is informative. The use of the purpose.overlay.yaml pattern is optional and does not affect conformance. -## Appendix A: Revision History +## Appendix B: Revision History | Version | Date | Notes | | ---- | ---- | ---- | -| 1.1.0 | TBD | Release of the Overlay Specification 1.1.0 | | 1.0.0 | 2024-10-17 | First release of the Overlay Specification |