From e991dfc319d7ac9d4eb213bebf73c602432b24a8 Mon Sep 17 00:00:00 2001 From: fmvilas Date: Sun, 24 Mar 2019 20:46:35 +0100 Subject: [PATCH] Add support for RAML-like traits --- examples/next/streetlights.yml | 7 ++ versions/next/asyncapi.md | 163 +++++++++++++++++++++++++++- versions/next/schema.json | 190 +++++++++++++++++++++++++++++++++ 3 files changed, 358 insertions(+), 2 deletions(-) diff --git a/examples/next/streetlights.yml b/examples/next/streetlights.yml index 6323fe767..f3ff208f7 100644 --- a/examples/next/streetlights.yml +++ b/examples/next/streetlights.yml @@ -52,6 +52,8 @@ channels: - $ref: '#/components/parameters/streetlightId' publish: operationId: turnOn + traits: + - $ref: '#/components/traits/docs' message: $ref: '#/components/messages/turnOnOff' @@ -174,3 +176,8 @@ components: description: The ID of the streetlight. schema: type: string + + traits: + docs: + externalDocs: + url: https://company.com/docs diff --git a/versions/next/asyncapi.md b/versions/next/asyncapi.md index 24e904543..92aaa96e1 100644 --- a/versions/next/asyncapi.md +++ b/versions/next/asyncapi.md @@ -51,8 +51,10 @@ Means that the [application](#definitionsApplication) is a [consumer](#definitio - [Channels Object](#channelsObject) - [Channel Item Object](#channelItemObject) - [Operation Object](#operationObject) + - [Operation Trait Object](#operationTraitObject) - [Stream Object](#streamObject) - [Message Object](#messageObject) + - [Message Trait Object](#messageTraitObject) - [Tag Object](#tagObject) - [External Documentation Object](#externalDocumentationObject) - [Components Object](#componentsObject) @@ -611,6 +613,7 @@ Field Name | Type | Description tags | [[Tag Object](#tagObject)] | A list of tags for API documentation control. Tags can be used for logical grouping of operations. externalDocs | [External Documentation Object](#externalDocumentationObject) | Additional external documentation for this operation. protocolInfo | Map[`string`, [Protocol Info Object](#protocolInfoObject)] | A free-form map where the keys describe the name of the protocol and the values describe protocol-specific definitions for the operation. +traits | [[Operation Trait Object](#operationTraitObject)] | [[[Operation Trait Object](#operationTraitObject), Map]] | A list of traits to apply to the operation object. The list MUST contain either a list of [Operation Trait Objects](#operationTraitObject) or a list of tuples where the first element is an [Operation Trait Object](#operationTraitObject)] and the second is a free-form object with the values of the variables a trait MAY use. **All the variables of a trait MUST be provided.** Traits MUST be merged into the operation object using the [JSON Merge Patch](https://tools.ietf.org/html/rfc7386) algorithm in the same order they are defined here. message | [Message Object](#messageObject) | A definition of the message that will be published or received on this channel. `oneOf` is allowed here to specify multiple messages, however, **a message MUST be valid only against one of the referenced message objects.** This object can be extended with [Specification Extensions](#specificationExtensions). @@ -648,7 +651,14 @@ This object can be extended with [Specification Extensions](#specificationExtens }, "amqp-0-9-1": { "noAck": true - } + }, + "traits": [ + { "$ref": "#/components/traits/kafka" }, + [ + { "$ref": "#/components/traits/docs" }, + { "headerId": "publish-1234" } + ] + ] } ``` @@ -674,6 +684,66 @@ message: $ref: "#/components/schemas/signup" amqp-0-9-1: noAck: true +traits: + - $ref: "#/components/traits/kafka" + - + - $ref: "#/components/traits/docs" + - headerId: publish-1234 +``` + + + + +#### Operation Trait Object + +Describes a trait that MAY be applied to an [Operation Object](#operationObject). This object MAY contain any property from the [Operation Object](#operationObject), except `message` and `traits`. + +If you're looking to apply traits to a message, see the [Message Trait Object](#messageTraitObject). + +All the string values of this object MUST support simple templating using the `{{` and `}}` delimiters. + +##### Fixed Fields + +Field Name | Type | Description +---|:---:|--- +operationId | `string` | Unique string used to identify the operation. The id MUST be unique among all operations described in the API. The operationId value is **case-sensitive**. Tools and libraries MAY use the operationId to uniquely identify an operation, therefore, it is RECOMMENDED to follow common programming naming conventions. +summary | `string` | A short summary of what the operation is about. +description | `string` | A verbose explanation of the operation. [CommonMark syntax](http://spec.commonmark.org/) can be used for rich text representation. +tags | [[Tag Object](#tagObject)] | A list of tags for API documentation control. Tags can be used for logical grouping of operations. +externalDocs | [External Documentation Object](#externalDocumentationObject) | Additional external documentation for this operation. +protocolInfo | Map[`string`, [Protocol Info Object](#protocolInfoObject)] | A free-form map where the keys describe the name of the protocol and the values describe protocol-specific definitions for the operation. + +This object can be extended with [Specification Extensions](#specificationExtensions). + +##### Operation Trait Object Example + +```json +{ + "protocolInfo": { + "amqp-0-9-1": { + "noAck": true + } + } +} +``` + +```yaml +protocolInfo: + amqp-0-9-1: + noAck: true +``` + +```json +{ + "externalDocs": { + "url": "https://mycompany.com/docs#{{headerId}}" + } +} +``` + +```yaml +externalDocs: + url: "https://mycompany.com/docs#{{headerId}}" ``` @@ -872,6 +942,7 @@ Field Name | Type | Description externalDocs | [External Documentation Object](#externalDocumentationObject) | Additional external documentation for this message. protocolInfo | Map[`string`, [Protocol Info Object](#protocolInfoObject)] | A free-form map where the keys describe the name of the protocol and the values describe protocol-specific definitions for the message. examples | [Map[`string`, `any`]] | An array with examples of valid message objects. +traits | [[Message Trait Object](#messageTraitObject)] | [[[Message Trait Object](#messageTraitObject), Map]] | A list of traits to apply to the message object. The list MUST contain either a list of [Message Trait Objects](#messageTraitObject) or a list of tuples where the first element is a [Message Trait Object](#messageTraitObject)] and the second is a free-form object with the values of the variables a trait may use. **All the variables of a trait MUST be provided.** Traits MUST be merged into the message object using the [JSON Merge Patch](https://tools.ietf.org/html/rfc7386) algorithm in the same order they are defined here. The resulting object MUST be a valid [Message Object](#messageObject). This object can be extended with [Specification Extensions](#specificationExtensions). @@ -918,7 +989,14 @@ This object can be extended with [Specification Extensions](#specificationExtens "properties": { "delivery_mode": 2 } - } + }, + "traits": [ + { "$ref": "#/components/traits/kafka" }, + [ + { "$ref": "#/components/traits/docs" }, + { "docId": "message-1234" } + ] + ] } ``` @@ -952,6 +1030,11 @@ correlationId: amqp-0-9-1: properties: delivery_mode: 2 +traits: + - $ref: "#/components/traits/kafka" + - + - $ref: "#/components/traits/docs" + - docId: message-1234 ``` Example using Google's protobuf to define the payload: @@ -994,6 +1077,70 @@ payload: +#### Message Trait Object + +Describes a trait that MAY be applied to a [Message Object](#messageObject). This object MAY contain any property from the [Message Object](#messageObject), except `payload` and `traits`. + +If you're looking to apply traits to an operation, see the [Operation Trait Object](#operationTraitObject). + +All the string values of this object MUST support simple templating using the `{{` and `}}` delimiters. + +##### Fixed Fields + +Field Name | Type | Description +---|:---:|--- +headers | Map[`string`, [Schema Object](#schemaObject) | [Reference Object](#referenceObject)] | Definition of the application headers. It **does not** define the protocol headers. +correlationId | [Correlation ID Object](#correlationIdObject) | [Reference Object](#referenceObject) | Definition of the correlation ID used for message tracing or matching. +schemaFormat | `string` | A string containing the name of the schema format/language used to define the message payload. If omitted, implementations should parse the payload as a [Schema object](#schemaObject). +contentType | `string` | The content type to use when encoding/decoding a message's payload. The value MUST be a specific media type (e.g. `application/json`). When omitted, the value MUST be the one specified on the [defaultContentType](#defaultContentTypeString) field. +name | `string` | A machine-friendly name for the message. +title | `string` | A human-friendly title for the message. +summary | `string` | A short summary of what the message is about. +description | `string` | A verbose explanation of the message. [CommonMark syntax](http://spec.commonmark.org/) can be used for rich text representation. +tags | [[Tag Object](#tagObject)] | A list of tags for API documentation control. Tags can be used for logical grouping of messages. +externalDocs | [External Documentation Object](#externalDocumentationObject) | Additional external documentation for this message. +protocolInfo | Map[`string`, [Protocol Info Object](#protocolInfoObject)] | A free-form map where the keys describe the name of the protocol and the values describe protocol-specific definitions for the message. +examples | [Map[`string`, `any`]] | An array with examples of valid message objects. + +This object can be extended with [Specification Extensions](#specificationExtensions). + +##### Message Trait Object Example + +```json +{ + "schemaFormat": "application/vnd.google.protobuf;version=3", + "contentType": "application/json" +} +``` + +```yaml +schemaFormat: 'application/vnd.google.protobuf;version=3' +contentType: application/json +``` + +```json +{ + "externalDocs": { + "url": "https://mycompany.com/docs#{{headerId}}" + } +} +``` + +```yaml +externalDocs: + url: 'https://mycompany.com/docs#{{headerId}}' +``` + + + + + + + + + + + #### Tag Object Allows adding meta data to a single tag. @@ -1097,6 +1244,7 @@ Field Name | Type | Description securitySchemes| Map[`string`, [Security Scheme Object](#securitySchemeObject) \| [Reference Object](#referenceObject)] | An object to hold reusable [Security Scheme Objects](#securitySchemeObject). parameters | Map[`string`, [Parameter Object](#parameterObject) \| [Reference Object](#referenceObject)] | An object to hold reusable [Parameter Objects](#parameterObject). correlationIds | Map[`string`, [Correlation ID Object](#correlationIdObject)] | An object to hold reusable [Correlation ID Objects](#correlationIdObject). + traits | Map[`string`, [Operation Trait Object](#operationTraitObject)] | [Message Trait Object](#messageTraitObject)] | An object to hold reusable [Operation Trait Objects](#operationTraitObject) and [Message Trait Objects](#messageTraitObject). This object can be extended with [Specification Extensions](#specificationExtensions). @@ -1187,6 +1335,13 @@ my.org.User "description": "Default Correlation ID", "location": "$message.header#/correlationId" } + }, + "traits": { + "docs": { + "externalDocs": { + "url": "https://mycompany.com/docs#{{headerId}}" + } + } } } ``` @@ -1240,6 +1395,10 @@ components: default: description: Default Correlation ID location: $message.header#/correlationId + traits: + docs: + externalDocs: + url: "https://mycompany.com/docs#{{headerId}}" ``` #### Schema Object diff --git a/versions/next/schema.json b/versions/next/schema.json index f690f0e7a..66049e6ee 100644 --- a/versions/next/schema.json +++ b/versions/next/schema.json @@ -304,6 +304,9 @@ ] } } + }, + "traits": { + "$ref": "#/definitions/traits" } } }, @@ -604,6 +607,34 @@ } }, "properties": { + "traits": { + "type": "array", + "items": { + "oneOf": [ + { "$ref": "#/definitions/Reference" }, + { "$ref": "#/definitions/operationTrait" }, + { + "type": "array", + "items": [ + { + "oneOf": [ + { + "$ref": "#/definitions/Reference" + }, + { + "$ref": "#/definitions/operationTrait" + } + ] + }, + { + "type": "object", + "additionalItems": true + } + ] + } + ] + } + }, "summary": { "type": "string" }, @@ -811,6 +842,38 @@ "additionalProperties": { "type": "object" } + }, + "traits": { + "type": "array", + "items": { + "oneOf": [ + { + "$ref": "#/definitions/Reference" + }, + { + "$ref": "#/definitions/messageTrait" + }, + { + "type": "array", + "items": [ + { + "oneOf": [ + { + "$ref": "#/definitions/Reference" + }, + { + "$ref": "#/definitions/messageTrait" + } + ] + }, + { + "type": "object", + "additionalItems": true + } + ] + } + ] + } } } }, @@ -865,6 +928,133 @@ } } }, + "traits": { + "type": "object", + "additionalProperties": { + "anyOf": [ + { "$ref": "#/definitions/operationTrait" }, + { "$ref": "#/definitions/messageTrait" } + ] + } + }, + "operationTrait": { + "type": "object", + "additionalProperties": false, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + }, + "properties": { + "summary": { + "type": "string" + }, + "description": { + "type": "string" + }, + "tags": { + "type": "array", + "items": { + "$ref": "#/definitions/tag" + }, + "uniqueItems": true + }, + "externalDocs": { + "$ref": "#/definitions/externalDocs" + }, + "operationId": { + "type": "string" + }, + "protocolInfo": { + "type": "object", + "additionalProperties": { + "type": "object" + } + } + } + }, + "messageTrait": { + "type": "object", + "additionalProperties": false, + "patternProperties": { + "^x-": { + "$ref": "#/definitions/vendorExtension" + } + }, + "properties": { + "schemaFormat": { + "type": "string" + }, + "contentType": { + "type": "string" + }, + "headers": { + "type": "object", + "additionalProperties": { + "oneOf": [ + { + "$ref": "#/definitions/Reference" + }, + { + "$ref": "#/definitions/schema" + } + ] + } + }, + "correlationId": { + "oneOf": [ + { + "$ref": "#/definitions/Reference" + }, + { + "$ref": "#/definitions/correlationId" + } + ] + }, + "tags": { + "type": "array", + "items": { + "$ref": "#/definitions/tag" + }, + "uniqueItems": true + }, + "summary": { + "type": "string", + "description": "A brief summary of the message." + }, + "name": { + "type": "string", + "description": "Name of the message." + }, + "title": { + "type": "string", + "description": "A human-friendly title for the message." + }, + "description": { + "type": "string", + "description": "A longer description of the message. CommonMark is allowed." + }, + "externalDocs": { + "$ref": "#/definitions/externalDocs" + }, + "deprecated": { + "type": "boolean", + "default": false + }, + "examples": { + "type": "array", + "items": { + "type": "object" + } + }, + "protocolInfo": { + "type": "object", + "additionalProperties": { + "type": "object" + } + } + } + }, "SecurityScheme": { "oneOf": [ { "$ref": "#/definitions/userPassword" },