|
| 1 | +[Source](https://github.com/OAI/OpenAPI-Specification/issues/1722) |
| 2 | +---- |
| 3 | + |
| 4 | +# OpenAPI Overlays |
| 5 | + |
| 6 | +In recent months we have been discussing various use cases for overlays and various solutions. The following proposal takes a somewhat more radical approach to the problem. It is a more ambitious proposal than the others we have seen before but the additional complexity does allow for supporting many of the scenarios that have been discussed to date. |
| 7 | + |
| 8 | + |
| 9 | +#### <a name="overlayDocument"></a>Overlay Document |
| 10 | + |
| 11 | +An overlay document contains a list of [Update Objects](#overlayUpdates) that are to be applied to the target document. Each [Update Object](#updateObject) has a `target` property and a `value` property. The `target` property is a [JMESPath](http://jmespath.org/specification.html) query that identifies what part of the target document is to be updated and the `value` property contains an object with the properties to be overlayed. |
| 12 | + |
| 13 | + |
| 14 | +#### <a name="overlayObject"></a>Overlay Object |
| 15 | + |
| 16 | +This is the root object of the [OpenAPI Overlay document](#oasDocument). |
| 17 | + |
| 18 | +##### Fixed Fields |
| 19 | + |
| 20 | +Field Name | Type | Description |
| 21 | +---|:---:|--- |
| 22 | +<a name="overlayVersion"></a>overlay | `string` | Version of the Overlay specification that this document conforms to. |
| 23 | +<a name="overlayInfo"></a>info | [[Info Object](#overlayInfoObject)] | Identifying information about the overlay. |
| 24 | +<a name="overlayExtends"></a>extends | `url` | URL to an OpenAPI document this overlay applies to. |
| 25 | +<a name="overlayUpdates"></a>updates | [[Update Object](#updateObject)] | A list of update objects to be applied to the target document. |
| 26 | + |
| 27 | +The list of update objects MUST be applied in sequential order to ensure a consistent outcome. This enables objects to be deleted in one update and then re-created in a subsequent update. |
| 28 | + |
| 29 | +#### <a name="overlayInfoObject"></a>Info Object |
| 30 | + |
| 31 | +This object contains identifying information about the [OpenAPI Overlay document](#oasDocument). |
| 32 | + |
| 33 | +##### Fixed Fields |
| 34 | + |
| 35 | +Field Name | Type | Description |
| 36 | +---|:---:|--- |
| 37 | +<a name="overlayTitle"></a>title | `string` | A human readable description of the purpose of the overlay. |
| 38 | +<a name="overlayVersion"></a>version | `string` | A version identifer for indicating changes to an overlay document. |
| 39 | + |
| 40 | +#### <a name="updateObject"></a>Update Object |
| 41 | + |
| 42 | +This object represents one or more changes to be applied to the target document at the ___location defined by the target JMESPath. |
| 43 | + |
| 44 | +##### Fixed Fields |
| 45 | + |
| 46 | +Field Name | Type | Description |
| 47 | +---|:---:|--- |
| 48 | +<a name="updateTarget"></a>target | `string` | A JMESPath expression referencing the target objects in the target document. |
| 49 | +<a name="updateValue"></a>value | [Any](#valueObject) | An object with the properties and values to be updated in the target document. |
| 50 | + |
| 51 | +The properties of the `Value Object` MUST be compatible with the target object referenced by the JMESPath key. When the Overlay document is applied, the properties in the `Value Object` replace properties in the target object with the same name and new properties are appended to the target object. |
| 52 | + |
| 53 | + |
| 54 | +##### Structured Overlays Example |
| 55 | + |
| 56 | +When updating properties throughout the target document it may be more efficient to create a single `Update Object` that mirrors the structure of the target document. e.g. |
| 57 | + |
| 58 | +```yaml |
| 59 | +overlay: 1.0.0 |
| 60 | +info: |
| 61 | + title: Structured Overlay |
| 62 | + version: 1.0.0 |
| 63 | +updates: |
| 64 | +- target: "@" |
| 65 | + value: |
| 66 | + info: |
| 67 | + x-overlay-applied: structured-overlay |
| 68 | + paths: |
| 69 | + "/": |
| 70 | + summary: "The root resource" |
| 71 | + get: |
| 72 | + summary: "Retrieve the root resource" |
| 73 | + x-rate-limit: 100 |
| 74 | + "/pets": |
| 75 | + get: |
| 76 | + summary: "Retrieve a list of pets" |
| 77 | + x-rate-limit: 100 |
| 78 | + components: |
| 79 | + tags: |
| 80 | +``` |
| 81 | +
|
| 82 | +##### Targeted Overlays |
| 83 | +
|
| 84 | +Alternatively, where only a small number of updates need to be applied to a large document, each [Update Object](#updateObject) can be more targeted. |
| 85 | +
|
| 86 | +```yaml |
| 87 | +overlay: 1.0.0 |
| 88 | +info: |
| 89 | + title: Structured Overlay |
| 90 | + version: 1.0.0 |
| 91 | +updates: |
| 92 | +- target: paths."/foo".get |
| 93 | + value: |
| 94 | + description: This is the new description |
| 95 | +- target: paths."/bar".get |
| 96 | + value: |
| 97 | + description: This is the updated description |
| 98 | +- target: paths."/bar" |
| 99 | + value: |
| 100 | + post: |
| 101 | + description: This is an updated description of a child object |
| 102 | + x-safe: false |
| 103 | +``` |
| 104 | +
|
| 105 | +##### Wildcard Overlays Examples |
| 106 | +
|
| 107 | +One significant advantage of using the JMESPath syntax 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. |
| 108 | +
|
| 109 | +```yaml |
| 110 | +overlay: 1.0.0 |
| 111 | +info: |
| 112 | + title: Update many objects at once |
| 113 | + version: 1.0.0 |
| 114 | +updates: |
| 115 | +- target: paths.*.get |
| 116 | + value: |
| 117 | + x-safe: true |
| 118 | +- target: paths.*.get.parameters[?name=='filter' && in=='query'] |
| 119 | + value: |
| 120 | + schema: |
| 121 | + $ref: "/components/schemas/filterSchema" |
| 122 | +``` |
| 123 | +
|
| 124 | +##### Array Modification Examples |
| 125 | +
|
| 126 | +Due to the fact that we can now reference specific elements of the parameter array, it does open the possibilty to being able to add parameters and potentially remove them using a `null` value. |
| 127 | + |
| 128 | +```yaml |
| 129 | +overlay: 1.0.0 |
| 130 | +info: |
| 131 | + title: Add an array element |
| 132 | + version: 1.0.0 |
| 133 | +updates: |
| 134 | +- target: paths.*.get.parameters[length(@)] |
| 135 | + value: |
| 136 | + name: newParam |
| 137 | + in: query |
| 138 | +``` |
| 139 | + |
| 140 | +```yaml |
| 141 | +overlay: 1.0.0 |
| 142 | +info: |
| 143 | + title: Remove a array element |
| 144 | + version: 1.0.0 |
| 145 | +updates: |
| 146 | +- target: $.paths[*].get.parameters[? name == 'dummy'] |
| 147 | + value: null |
| 148 | +``` |
| 149 | + |
| 150 | + |
| 151 | +## Proposal Summary |
| 152 | + |
| 153 | +### Benefits |
| 154 | + |
| 155 | +- This approach addresses the two distinct approaches of structured overlay vs targeted overlay which suits distinct but equally valid scenarios. |
| 156 | +- Addresses the problem of modifying the parameters array and removes the need to replace the entire array when a small change is required. |
| 157 | +- Allows sets of related overlays to be stored in a same file. |
| 158 | +- Enables updating a set of objects based on a pattern. This might be an effective way of apply common behaviour across many operations in an API. |
| 159 | + |
| 160 | +### Challenges |
| 161 | +- Tooling will need a JMESPath implementation. |
| 162 | +- Large overlays may be slow to process. |
| 163 | +- Multiple complex pattern based overlays may cause overlapping updates causing confusing outcomes. |
0 commit comments