packages feed

asyncapi3 (empty) → 1.0.0.0

raw patch · 158 files changed

+12112/−0 lines, 158 filesdep +aesondep +asyncapi3dep +base

Dependencies added: aeson, asyncapi3, base, bytestring, containers, directory, filepath, hashable, hspec, hspec-discover, hspec-golden, insert-ordered-containers, lens, optics-core, optics-th, scientific, text, unordered-containers, vector, yaml

Files

+ LICENSE view
@@ -0,0 +1,15 @@+ISC License++Copyright (c) 2026 Gautier DI FOLCO++Permission to use, copy, modify, and/or distribute this software for any+purpose with or without fee is hereby granted, provided that the above+copyright notice and this permission notice appear in all copies.++THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH+REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY+AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,+INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM+LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR+OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR+PERFORMANCE OF THIS SOFTWARE.
+ asyncapi3.cabal view
@@ -0,0 +1,116 @@+cabal-version:       3.0+name:                asyncapi3+version:             1.0.0.0+author:              Gautier DI FOLCO+maintainer:          foss@difolco.dev+category:            Data+build-type:          Simple+license:             ISC+license-file:        LICENSE+synopsis:            AsyncAPI 3.1.0 data model+description:         Haskell data-model library for AsyncAPI 3.1.0.+tested-with:         GHC==9.8.4, GHC==9.10.3, GHC==9.12.4, GHC==9.14.1++extra-source-files:+  reference/*.md+  reference/*.json+  reference/examples/*.yml+  reference/examples/social-media/backend/asyncapi.yaml+  reference/examples/social-media/comments-service/asyncapi.yaml+  reference/examples/social-media/frontend/asyncapi.yaml+  reference/examples/social-media/notification-service/asyncapi.yaml+  reference/examples/social-media/public-api/asyncapi.yaml+  test/golden/examples/*.json+  test/golden/spec-examples/*.json++common shared+  default-language:   Haskell2010+  default-extensions:+    DataKinds+    DefaultSignatures+    DeriveAnyClass+    DeriveGeneric+    DerivingStrategies+    DerivingVia+    DuplicateRecordFields+    FlexibleContexts+    GADTs+    ImportQualifiedPost+    GeneralizedNewtypeDeriving+    KindSignatures+    LambdaCase+    OverloadedStrings+    OverloadedRecordDot+    RankNTypes+    RecordWildCards+    ScopedTypeVariables+    TypeApplications+    TypeFamilies+    TypeOperators++common warnings+  ghc-options: -Wall -Wcompat -Widentities -Wincomplete-record-updates -Wincomplete-uni-patterns -Wpartial-fields -Wredundant-constraints++library+  import:            shared, warnings+  hs-source-dirs:    src+  exposed-modules:+    Data.AsyncAPI+    Data.AsyncAPI.Internal+    Data.AsyncAPI.Internal.Schema+    Data.AsyncAPI.Internal.Referenced+    Data.AsyncAPI.Internal.Encoding+    Data.AsyncAPI.Internal.Types+    Data.AsyncAPI.Internal.FieldNames+    Data.AsyncAPI.Lens+    Data.AsyncAPI.Optics+    Data.AsyncAPI.Validation+  autogen-modules:+    Paths_asyncapi3+  other-modules:+    Paths_asyncapi3+  build-depends:+      base >=4.19 && <4.23+    , aeson >=2.2 && <2.3+    , insert-ordered-containers >=0.2.7 && <0.4+    , scientific >=0.3.7 && <0.4+    , text >=2 && <2.3+    , bytestring >=0.12 && <0.13+    , containers >=0.6.7 && <0.8+    , vector >=0.13 && <0.14+    , hashable >=1.4 && <1.6+    , unordered-containers >=0.2.19 && <0.3+    , lens >=5.2 && <5.4+    , optics-core >=0.4 && <0.5+    , optics-th >=0.4 && <0.5++test-suite spec+  import:            shared, warnings+  type:              exitcode-stdio-1.0+  hs-source-dirs:    test+  main-is:           Spec.hs+  other-modules:+    AsyncAPISpec+    SpecConformanceSpec+    ValidationSpec+    ExamplesSpec+    TestSupport+  ghc-options: -threaded -rtsopts -with-rtsopts=-N+  build-depends:+      base >=4.19 && <4.23+    , asyncapi3+    , aeson >=2.2 && <2.3+    , insert-ordered-containers >=0.2.7 && <0.4+    , scientific >=0.3.7 && <0.4+    , text >=2 && <2.3+    , bytestring >=0.12 && <0.13+    , containers >=0.6.7 && <0.8+    , directory >=1.3.8 && <1.4+    , filepath >=1.4.100 && <1.6+    , hspec >=2.11 && <2.12+    , hspec-discover >=2.11 && <2.12+    , hspec-golden >=0.2.2 && <0.3+    , lens >=5.2 && <5.4+    , unordered-containers >=0.2.19 && <0.3+    , vector >=0.13 && <0.14+    , yaml >=0.11 && <0.12
+ reference/NOTICE.md view
@@ -0,0 +1,15 @@+# NOTICE++This directory contains files vendored from the+[AsyncAPI specification repository](https://github.com/asyncapi/spec)+at tag `v3.1.0` (commit `b3fac5bb522771428ea57b16129b273cd3ea0180`):++- `asyncapi.md` — from `spec/asyncapi.md`, verbatim.+- `base-doc.json` — from `scripts/validation/base-doc-combined.json`, with the+  `"asyncapi"` version field changed from `"3.0.0"` to `"3.1.0"` (the upstream+  file had not been bumped when the tag was cut; the examples all declare 3.1.0).+- `examples/` — from `examples/`, verbatim (24 documents: 19 top-level YAML+  files plus 5 `social-media/*/asyncapi.yaml`).++The AsyncAPI specification is copyright the AsyncAPI Initiative and licensed+under the [Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0).
+ reference/asyncapi.md view
@@ -0,0 +1,2766 @@+# AsyncAPI Specification++## Attribution++Part of this content has been taken from the great work done by the folks at the [OpenAPI Initiative](https://openapis.org).++### Version 3.1.0++The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in [RFC 2119](https://www.ietf.org/rfc/rfc2119.txt).++The AsyncAPI Specification is licensed under [The Apache License, Version 2.0](https://www.apache.org/licenses/LICENSE-2.0.html).++## Introduction++The AsyncAPI Specification is a project used to describe message-driven APIs in a machine-readable format. It’s protocol-agnostic, so you can use it for APIs that work over any protocol (e.g., AMQP, MQTT, WebSockets, Kafka, STOMP, HTTP, Mercure, etc).++The AsyncAPI Specification defines a set of fields that can be used in an AsyncAPI document to describe an [application](#definitionsApplication)'s API. The document may reference other files for additional details or shared fields, but it is typically a single, primary document that encapsulates the API description.++The AsyncAPI document SHOULD describe the operations an [application](#definitionsApplication) performs. For instance, consider the following AsyncAPI definition snippet:++```yaml+channels:+  userSignedUp:+    # ...(redacted for brevity)+operations:+  onUserSignedUp:+    action: receive+    channel:+      $ref: '#/channels/userSignedUp'+```++It means that the [application](#definitionsApplication) will receive messages from  the `userSignedUp` [channel](#definitionsChannel).++**The AsyncAPI specification does not assume any kind of software topology, architecture or pattern.** Therefore, a server MAY be a message broker, a web server or any other kind of computer program capable of sending and/or receiving data. However, AsyncAPI offers a mechanism called "bindings" that aims to help with more specific information about the protocol.++It's NOT RECOMMENDED to derive a [receiver](#definitionsReceiver) AsyncAPI document from a [sender](#definitionsSender) one or vice versa. There are no guarantees that the channel used by an application to receive messages will be the same channel where another application is sending them. Also, certain fields in the document like `summary`, `description`, and the id of the operation might stop making sense. For instance, given the following receiver snippet:++```yaml+operations:+  onUserSignedUp:+    summary: On user signed up.+    description: Event received when a user signed up on the product.+    action: receive+    channel:+      $ref: '#/channels/userSignedUp'+```++We can't automatically assume that an _opposite_ application exists by simply replacing `receive` with `send`:++```yaml+operations:+  onUserSignedUp: # <-- This doesn't make sense now. Should be something like sendUserSignedUp.+    summary: On user signed up. # <-- This doesn't make sense now. Should say something like "Sends a user signed up event".+    description: Event received when a user signed up on the product. # <-- This doesn't make sense now. Should speak about sending an event, not receiving it.+    action: send+    channel:+      $ref: '#/channels/userSignedUp'+```++Aside from the issues mentioned above, there may also be infrastructure configuration that is not represented here. For instance, a system may use a read-only channel for receiving messages, a different one for sending them, and an intermediary process that will forward messages from one channel to the other.++## Table of Contents+<!-- TOC depthFrom:2 depthTo:4 withLinks:1 updateOnSave:0 orderedList:0 -->++- [Definitions](#definitions)+  - [Server](#definitionsServer)+  - [Application](#definitionsApplication)+  - [Sender](#definitionsSender)+  - [Receiver](#definitionsReceiver)+  - [Message](#definitionsMessage)+  - [Channel](#definitionsChannel)+  - [Protocol](#definitionsProtocol)+- [Specification](#specification)+  - [Format](#format)+  - [File Structure](#file-structure)+  - [Absolute URLs](#absolute-urls)+  - [Schema](#schema)+    - [AsyncAPI Object](#A2SObject)+    - [AsyncAPI Version String](#A2SVersionString)+    - [Identifier](#A2SIdString)+    - [Info Object](#infoObject)+    - [Contact Object](#contactObject)+    - [License Object](#licenseObject)+    - [Servers Object](#serversObject)+    - [Server Object](#serverObject)+    - [Server Variable Object](#serverVariableObject)+    - [Default Content Type](#defaultContentTypeString)+    - [Channels Object](#channelsObject)+    - [Channel Object](#channelObject)+    - [Operations Object](#operationsObject)+    - [Operation Object](#operationObject)+    - [Operation Trait Object](#operationTraitObject)+    - [Operation Reply Object](#operationReplyObject)+    - [Operation Reply Address Object](#operationReplyAddressObject)+    - [Message Object](#messageObject)+    - [Message Trait Object](#messageTraitObject)+    - [Message Example Object](#messageExampleObject)+    - [Tags Object](#tagsObject)+    - [Tag Object](#tag-object)+    - [External Documentation Object](#externalDocumentationObject)+    - [Components Object](#componentsObject)+    - [Reference Object](#referenceObject)+    - [Multi Format Schema Object](#multiFormatSchemaObject)+    - [Schema Object](#schemaObject)+    - [Security Scheme Object](#securitySchemeObject)+    - [OAuth Flows Object](#oauth-flows-object)  +    - [OAuth Flow Object](#oauth-flow-object)+    - [Server Bindings Object](#serverBindingsObject)+    - [Parameters Object](#parametersObject)+    - [Parameter Object](#parameterObject)+    - [Channel Bindings Object](#channelBindingsObject)+    - [Operation Bindings Object](#operationBindingsObject)+    - [Message Bindings Object](#messageBindingsObject)+    - [Correlation ID Object](#correlationIdObject)+    - [Specification Extensions](#specificationExtensions)++<!-- /TOC -->++## <a name="definitions"></a>Definitions++### <a name="definitionsServer"></a>Server++A server MAY be a message broker that is capable of sending and/or receiving between a [sender](#definitionsSender) and [receiver](#definitionsReceiver). A server MAY be a service with WebSocket API that enables message-driven communication between browser-to-server or server-to-server.++### <a name="definitionsApplication"></a>Application++An application is any kind of computer program or a group of them. It MUST be a [sender](#definitionsSender), a [receiver](#definitionsReceiver), or both. An application MAY be a microservice, IoT device (sensor), mainframe process, message broker, etc. An application MAY be written in any number of different programming languages as long as they support the selected [protocol](#definitionsProtocol). An application MUST also use a protocol supported by the [server](#definitionsServer) in order to connect and exchange [messages](#definitionsMessage), or expose the protocol described in the AsyncAPI document.++### <a name="definitionsSender"></a>Sender++A sender is a type of application, that is sending [messages](#definitionsMessage) to [channels](#definitionsChannel). A sender MAY send to multiple channels depending on the [server](#definitionsServer), protocol, and use-case pattern.++### <a name="definitionsReceiver"></a>Receiver++A receiver is a type of application that is receiving [messages](#definitionsMessage) from [channels](#definitionsChannel). A receiver MAY receive from multiple channels depending on the [server](#definitionsServer), protocol, and the use-case pattern. A receiver MAY forward a received message further without changing it. A receiver MAY act as a consumer and react to the message. A receiver MAY act as a processor that, for example, aggregates multiple messages in one and forwards them.++### <a name="definitionsMessage"></a>Message++A message is the mechanism by which information is exchanged via a channel between [servers](#definitionsServer) and applications. A message MAY contain a payload and MAY also contain headers. The headers MAY be subdivided into [protocol](#definitionsProtocol)-defined headers and header properties defined by the application which can act as supporting metadata. The payload contains the data, defined by the application, which MUST be serialized into a format (JSON, XML, Avro, binary, etc.). Since a message is a generic mechanism, it can support multiple interaction patterns such as event, command, request, or response.++### <a name="definitionsChannel"></a>Channel++A channel is an addressable component, made available by the [server](#definitionsServer), for the organization of [messages](#definitionsMessage). [Sender](#definitionsSender) applications send messages to channels and [receiver](#definitionsReceiver) applications receive messages from channels. [Servers](#definitionsServer) MAY support many channel instances, allowing messages with different content to be addressed to different channels. Depending on the [server](#definitionsServer) implementation, the channel MAY be included in the message via protocol-defined headers.++### <a name="definitionsProtocol"></a>Protocol++A protocol is the mechanism (wireline protocol or API) by which [messages](#definitionsMessage) are exchanged between the application and the [channel](#definitionsChannel). Example protocols include, but are not limited to, AMQP, HTTP, JMS, Kafka, Anypoint MQ, MQTT, Solace, STOMP, Mercure, WebSocket, Google Pub/Sub, Pulsar, ROS 2.  ++### <a name="definitionsBindings"></a>Bindings++A "binding" (or "protocol binding") is a mechanism to define protocol-specific information. Therefore, a protocol binding MUST define protocol-specific information only.++## <a name="specification"></a>Specification++### <a name="format"></a>Format++The files describing the message-driven API in accordance with the AsyncAPI Specification are represented as JSON objects and conform to the JSON standards.+YAML, being a superset of JSON, can be used as well to represent a A2S (AsyncAPI Specification) file.++For example, if a field is said to have an array value, the JSON array representation will be used:++```yaml+{+   "field" : [...]+}+```++While the API is described using JSON it does not impose a JSON input/output to the API itself.++All field names in the specification are **case sensitive**.++The schema exposes two types of fields.+Fixed fields, which have a declared name, and Patterned fields, which declare a regex pattern for the field name.+Patterned fields can have multiple occurrences as long as each has a unique name.++In order to preserve the ability to round-trip between YAML and JSON formats, YAML version [1.2](https://www.yaml.org/spec/1.2/spec.html) is recommended along with some additional constraints:++- Tags MUST be limited to those allowed by the [JSON Schema ruleset](https://www.yaml.org/spec/1.2/spec.html#id2803231)+- Keys used in YAML maps MUST be limited to a scalar string, as defined by the YAML Failsafe schema ruleset++### <a name="file-structure"></a>File Structure++An AsyncAPI document MAY be made up of a single document or be divided into multiple,+connected parts at the discretion of the author. In the latter case, [Reference Objects](#referenceObject) are used.++It is important to note that everything that is defined in an AsyncAPI document MUST be used by the implemented [Application](#definitionsApplication), with the exception of the [Components Object](#componentsObject). Everything that is defined inside the Components Object represents a resource that MAY or MAY NOT be used by the implemented [Application](#definitionsApplication).++By convention, the AsyncAPI Specification (A2S) file is named `asyncapi.json` or `asyncapi.yaml`.++### <a name="absolute-urls"></a>Absolute URLs++Unless specified otherwise, all properties that are absolute URLs are defined by [RFC3986, section 4.3](https://datatracker.ietf.org/doc/html/rfc3986#section-4.3).++### <a name="schema"></a>Schema++#### <a name="A2SObject"></a>AsyncAPI Object++This is the root document object for the API specification.+It combines resource listing and API declaration together into one document.++##### Fixed Fields++Field Name | Type | Description+---|:---:|---+<a name="A2SAsyncAPI"></a>asyncapi | [AsyncAPI Version String](#A2SVersionString) | **REQUIRED.** Specifies the AsyncAPI Specification version being used. It can be used by tooling Specifications and clients to interpret the version. The structure shall be `major`.`minor`.`patch`, where `patch` versions _must_ be compatible with the existing `major`.`minor` tooling. Typically patch versions will be introduced to address errors in the documentation, and tooling should typically be compatible with the corresponding `major`.`minor` (1.0.*). Patch versions will correspond to patches of this document.+<a name="A2SId"></a>id | [Identifier](#A2SIdString) | Identifier of the [application](#definitionsApplication) the AsyncAPI document is defining.+<a name="A2SInfo"></a>info | [Info Object](#infoObject) | **REQUIRED.** Provides metadata about the API. The metadata can be used by the clients if needed.+<a name="A2SServers"></a>servers | [Servers Object](#serversObject) | Provides connection details of servers.+<a name="A2SDefaultContentType"></a>defaultContentType | [Default Content Type](#defaultContentTypeString) | Default content type to use when encoding/decoding a message's payload.+<a name="A2SChannels"></a>channels | [Channels Object](#channelsObject) | The channels used by this [application](#definitionsApplication).+<a name="A2SOperations"></a>operations | [Operations Object](#operationsObject) | The operations this [application](#definitionsApplication) MUST implement.+<a name="A2SComponents"></a>components | [Components Object](#componentsObject) | An element to hold various reusable objects for the specification. Everything that is defined inside this object represents a resource that MAY or MAY NOT be used in the rest of the document and MAY or MAY NOT be used by the implemented [Application](#definitionsApplication).++This object MAY be extended with [Specification Extensions](#specificationExtensions).++#### <a name="A2SVersionString"></a>AsyncAPI Version String++The version string signifies the version of the AsyncAPI Specification that the document complies to.+The format for this string _must_ be `major`.`minor`.`patch`.  The `patch` _may_ be suffixed by a hyphen and extra alphanumeric characters.++A `major`.`minor` shall be used to designate the AsyncAPI Specification version, and will be considered compatible with the AsyncAPI Specification specified by that `major`.`minor` version.+The patch version will not be considered by tooling, making no distinction between `1.0.0` and `1.0.1`.++In subsequent versions of the AsyncAPI Specification, care will be given such that increments of the `minor` version should not interfere with operations of tooling developed to a lower minor version. Thus a hypothetical `1.1.0` specification should be usable with tooling designed for `1.0.0`.++#### <a name="A2SIdString"></a>Identifier++This field represents a unique universal identifier of the [application](#definitionsApplication) the AsyncAPI document is defining. It must conform to the URI format, according to [RFC3986](https://tools.ietf.org/html/rfc3986).++It is RECOMMENDED to use a [URN](https://tools.ietf.org/html/rfc8141) to globally and uniquely identify the application during long periods of time, even after it becomes unavailable or ceases to exist.++##### Examples++```json+{+  "id": "urn:example:com:smartylighting:streetlights:server"+}+```++```yaml+id: 'urn:example:com:smartylighting:streetlights:server'+```++```json+{+  "id": "https://github.com/smartylighting/streetlights-server"+}+```++```yaml+id: 'https://github.com/smartylighting/streetlights-server'+```++#### <a name="infoObject"></a>Info Object++The object provides metadata about the API.+The metadata can be used by the clients if needed.++##### Fixed Fields++Field Name | Type | Description+---|:---:|---+<a name="infoObjectTitle"></a>title | `string` | **REQUIRED.** The title of the application.+<a name="infoObjectVersion"></a>version | `string` | **REQUIRED** Provides the version of the application API (not to be confused with the specification version).+<a name="infoObjectDescription"></a>description | `string` | A short description of the application. [CommonMark syntax](https://spec.commonmark.org/) can be used for rich text representation.+<a name="infoObjectTermsOfService"></a>termsOfService | `string` | A URL to the Terms of Service for the API. This MUST be in the form of an absolute URL.+<a name="infoObjectContact"></a>contact | [Contact Object](#contactObject) | The contact information for the exposed API.+<a name="infoObjectLicense"></a>license | [License Object](#licenseObject) | The license information for the exposed API.+<a name="infoObjectTags"></a>tags | [Tags Object](#tagsObject) | A list of tags for application API documentation control. Tags can be used for logical grouping of applications.+<a name="infoObjectExternalDocs"></a>externalDocs | [External Documentation Object](#externalDocumentationObject) \| [Reference Object](#referenceObject) | Additional external documentation of the exposed API.++This object MAY be extended with [Specification Extensions](#specificationExtensions).++##### Info Object Example++<!-- asyncapi-example-tester:{"name":"Info Object","json_pointer":"/info"} -->+```json+{+  "title": "AsyncAPI Sample App",+  "version": "1.0.1",+  "description": "This is a sample app.",+  "termsOfService": "https://asyncapi.org/terms/",+  "contact": {+    "name": "API Support",+    "url": "https://www.asyncapi.org/support",+    "email": "support@asyncapi.org"+  },+  "license": {+    "name": "Apache 2.0",+    "url": "https://www.apache.org/licenses/LICENSE-2.0.html"+  },+  "externalDocs": {+    "description": "Find more info here",+    "url": "https://www.asyncapi.org"+  },+  "tags": [+    {+      "name": "e-commerce"+    }+  ]+}+```++<!-- asyncapi-example-tester:{"name":"Info Object","json_pointer":"/info"} -->+```yaml+title: AsyncAPI Sample App+version: 1.0.1+description: This is a sample app.+termsOfService: https://asyncapi.org/terms/+contact:+  name: API Support+  url: https://www.asyncapi.org/support+  email: support@asyncapi.org+license:+  name: Apache 2.0+  url: https://www.apache.org/licenses/LICENSE-2.0.html+externalDocs:+  description: Find more info here+  url: https://www.asyncapi.org+tags:+  - name: e-commerce+```++#### <a name="contactObject"></a>Contact Object++Contact information for the exposed API.++##### Fixed Fields++Field Name | Type | Description+---|:---:|---+<a name="contactObjectName"></a>name | `string` | The identifying name of the contact person/organization.+<a name="contactObjectUrl"></a>url | `string` | The URL pointing to the contact information. This MUST be in the form of an absolute URL.+<a name="contactObjectEmail"></a>email | `string` | The email address of the contact person/organization. MUST be in the format of an email address.++This object MAY be extended with [Specification Extensions](#specificationExtensions).++##### Contact Object Example++<!-- asyncapi-example-tester:{"name":"Contact Object","json_pointer":"/info/contact"} -->+```json+{+  "name": "API Support",+  "url": "https://www.example.com/support",+  "email": "support@example.com"+}+```++<!-- asyncapi-example-tester:{"name":"Contact Object","json_pointer":"/info/contact"} -->+```yaml+name: API Support+url: https://www.example.com/support+email: support@example.com+```++#### <a name="licenseObject"></a>License Object++License information for the exposed API.++##### Fixed Fields++Field Name | Type | Description+---|:---:|---+<a name="licenseObjectName"></a>name | `string` | **REQUIRED.** The license name used for the API.+<a name="licenseObjectUrl"></a>url | `string` | A URL to the license used for the API. This MUST be in the form of an absolute URL.++This object MAY be extended with [Specification Extensions](#specificationExtensions).++##### License Object Example++<!-- asyncapi-example-tester:{"name":"License Object","json_pointer":"/info/license"} -->+```json+{+  "name": "Apache 2.0",+  "url": "https://www.apache.org/licenses/LICENSE-2.0.html"+}+```++<!-- asyncapi-example-tester:{"name":"License Object","json_pointer":"/info/license"} -->+```yaml+name: Apache 2.0+url: https://www.apache.org/licenses/LICENSE-2.0.html+```++#### <a name="serversObject"></a>Servers Object++The Servers Object is a map of [Server Objects](#serverObject).++##### Patterned Fields++Field Pattern | Type | Description+---|:---:|---+<a name="serversObjectServer"></a>`^[A-Za-z0-9_\-]+$` | [Server Object](#serverObject) \| [Reference Object](#referenceObject) | The definition of a server this application MAY connect to.++##### Servers Object Example++<!-- asyncapi-example-tester:{"name":"Servers Object","json_pointer":"/servers"} -->+```json+{+  "development": {+    "host": "localhost:5672",+    "description": "Development AMQP broker.",+    "protocol": "amqp",+    "protocolVersion": "0-9-1",+    "tags": [+      { +        "name": "env:development",+        "description": "This environment is meant for developers to run their own tests."+      }+    ]+  },+  "staging": {+    "host": "rabbitmq-staging.in.mycompany.com:5672",+    "description": "RabbitMQ broker for the staging environment.",+    "protocol": "amqp",+    "protocolVersion": "0-9-1",+    "tags": [+      { +        "name": "env:staging",+        "description": "This environment is a replica of the production environment."+      }+    ]+  },+  "production": {+    "host": "rabbitmq.in.mycompany.com:5672",+    "description": "RabbitMQ broker for the production environment.",+    "protocol": "amqp",+    "protocolVersion": "0-9-1",+    "tags": [+      { +        "name": "env:production",+        "description": "This environment is the live environment available for final users."+      }+    ]+  }+}+```++<!-- asyncapi-example-tester:{"name":"Servers Object","json_pointer":"/servers"} -->+```yaml+development:+  host: localhost:5672+  description: Development AMQP broker.+  protocol: amqp+  protocolVersion: 0-9-1+  tags:+    - name: 'env:development'+      description: 'This environment is meant for developers to run their own tests.'+staging:+  host: rabbitmq-staging.in.mycompany.com:5672+  description: RabbitMQ broker for the staging environment.+  protocol: amqp+  protocolVersion: 0-9-1+  tags:+    - name: 'env:staging'+      description: 'This environment is a replica of the production environment.'+production:+  host: rabbitmq.in.mycompany.com:5672+  description: RabbitMQ broker for the production environment.+  protocol: amqp+  protocolVersion: 0-9-1+  tags:+    - name: 'env:production'+      description: 'This environment is the live environment available for final users.'+```++#### <a name="serverObject"></a>Server Object++An object representing a message broker, a server or any other kind of computer program capable of sending and/or receiving data. This object is used to capture details such as URIs, protocols and security configuration. Variable substitution can be used so that some details, for example usernames and passwords, can be injected by code generation tools.++##### Fixed Fields++Field Name | Type | Description+---|:---:|---+<a name="serverObjectHost"></a>host | `string` | **REQUIRED**. The server host name. It MAY include the port. This field supports [Server Variables](#serverObjectVariables). Variable substitutions will be made when a variable is named in `{`braces`}`.+<a name="serverObjectProtocol"></a>protocol | `string` | **REQUIRED**. The protocol this server supports for connection.+<a name="serverObjectProtocolVersion"></a>protocolVersion | `string` | The version of the protocol used for connection. For instance: AMQP `0.9.1`, HTTP `2.0`, Kafka `1.0.0`, etc.+<a name="serverObjectPathname"></a>pathname | `string` | The path to a resource in the host. This field supports [Server Variables](#serverObjectVariables). Variable substitutions will be made when a variable is named in `{`braces`}`.+<a name="serverObjectDescription"></a>description | `string` | An optional string describing the server. [CommonMark syntax](https://spec.commonmark.org/) MAY be used for rich text representation.+<a name="serverObjectTitle"></a>title | `string` | A human-friendly title for the server.+<a name="serverObjectSummary"></a>summary | `string` | A short summary of the server.+<a name="serverObjectVariables"></a>variables | Map[`string`, [Server Variable Object](#serverVariableObject) \| [Reference Object](#referenceObject)]] | A map between a variable name and its value.  The value is used for substitution in the server's `host` and `pathname` template.+<a name="serverObjectSecurity"></a>security | [[Security Scheme Object](#securitySchemeObject) \| [Reference Object](#referenceObject)] | A declaration of which security schemes can be used with this server. The list of values includes alternative [security scheme objects](#securitySchemeObject) that can be used. Only one of the security scheme objects need to be satisfied to authorize a connection or operation.+<a name="serverObjectTags"></a>tags | [Tags Object](#tagsObject) | A list of tags for logical grouping and categorization of servers.+<a name="serverObjectExternalDocs"></a>externalDocs | [External Documentation Object](#externalDocumentationObject) \| [Reference Object](#referenceObject) | Additional external documentation for this server.+<a name="serverObjectBindings"></a>bindings | [Server Bindings Object](#serverBindingsObject) \| [Reference Object](#referenceObject) | A map where the keys describe the name of the protocol and the values describe protocol-specific definitions for the server.++This object MAY be extended with [Specification Extensions](#specificationExtensions).++##### Server Object Example++A single server would be described as:++<!-- asyncapi-example-tester:{"name":"Server Object","json_pointer":"/servers/production"} -->+```json+{+  "host": "kafka.in.mycompany.com:9092",+  "description": "Production Kafka broker.",+  "protocol": "kafka",+  "protocolVersion": "3.2"+}+```++<!-- asyncapi-example-tester:{"name":"Server Object","json_pointer":"/servers/production"} -->+```yaml+host: kafka.in.mycompany.com:9092+description: Production Kafka broker.+protocol: kafka+protocolVersion: '3.2'+```++An example of a server that has a `pathname`:++<!-- asyncapi-example-tester:{"name":"Server Object with pathname","json_pointer":"/servers/production"} -->+```json+{+  "host": "rabbitmq.in.mycompany.com:5672",+  "pathname": "/production",+  "protocol": "amqp",+  "description": "Production RabbitMQ broker (uses the `production` vhost)."+}+```++<!-- asyncapi-example-tester:{"name":"Server Object with pathname","json_pointer":"/servers/production"} -->+```yaml+host: rabbitmq.in.mycompany.com:5672+pathname: /production+protocol: amqp+description: Production RabbitMQ broker (uses the `production` vhost).+```++#### <a name="serverVariableObject"></a>Server Variable Object++An object representing a Server Variable for server URL template substitution.++##### Fixed Fields++Field Name | Type | Description+---|:---:|---+<a name="serverVariableObjectEnum"></a>enum | [`string`] | An enumeration of string values to be used if the substitution options are from a limited set.+<a name="serverVariableObjectDefault"></a>default | `string` | The default value to use for substitution, and to send, if an alternate value is _not_ supplied.+<a name="serverVariableObjectDescription"></a>description | `string` | An optional description for the server variable. [CommonMark syntax](https://spec.commonmark.org/) MAY be used for rich text representation.+<a name="serverVariableObjectExamples"></a>examples | [`string`] | An array of examples of the server variable.++This object MAY be extended with [Specification Extensions](#specificationExtensions).++##### Server Variable Object Example++<!-- asyncapi-example-tester:{"name":"Server Object with Variable Object","json_pointer":"/servers/production"} -->+```json+{+  "host": "rabbitmq.in.mycompany.com:5672",+  "pathname": "/{env}",+  "protocol": "amqp",+  "description": "RabbitMQ broker. Use the `env` variable to point to either `production` or `staging`.",+  "variables": {+    "env": {+      "description": "Environment to connect to. It can be either `production` or `staging`.",+      "enum": [+        "production",+        "staging"+      ]+    }+  }+}+```++<!-- asyncapi-example-tester:{"name":"Server Object with Variable Object","json_pointer":"/servers/production"} -->+```yaml+host: 'rabbitmq.in.mycompany.com:5672'+pathname: '/{env}'+protocol: amqp+description: RabbitMQ broker. Use the `env` variable to point to either `production` or `staging`.+variables:+  env:+    description: Environment to connect to. It can be either `production` or `staging`.+    enum:+      - production+      - staging+```++#### <a name="defaultContentTypeString"></a>Default Content Type++A string representing the default content type to use when encoding/decoding a message's payload. The value MUST be a specific media type (e.g. `application/json`). This value MUST be used by schema parsers when the [contentType](#messageObjectContentType) property is omitted.++In case a message can't be encoded/decoded using this value, schema parsers MUST use their default content type.++##### Default Content Type Example++<!-- asyncapi-example-tester:{"name":"Default Content Type at root doc","json_pointer":""} -->  +```json+{+  "defaultContentType": "application/json"+}+```++<!-- asyncapi-example-tester:{"name":"Default Content Type at root doc","json_pointer":""} -->  +```yaml+defaultContentType: application/json+```++#### <a name="channelsObject"></a>Channels Object++An object containing all the [Channel Object](#channelObject) definitions the [Application](#definitionsApplication) MUST use during runtime.++##### Patterned Fields++Field Pattern | Type | Description+---|:---:|---+<a name="channelsObjectChannel"></a>{channelId} | [Channel Object](#channelObject) \| [Reference Object](#referenceObject) | An identifier for the described channel. The `channelId` value is **case-sensitive**. Tools and libraries MAY use the `channelId` to uniquely identify a channel, therefore, it is RECOMMENDED to follow common programming naming conventions.++##### Channels Object Example++<!-- asyncapi-example-tester:{"name":"Channels Object","json_pointer":"/channels"} -->+```json+{+  "userSignedUp": {+    "address": "user.signedup",+    "messages": {+      "userSignedUp": {+        "$ref": "#/components/messages/userSignedUp"+      }+    }+  }+}+```++<!-- asyncapi-example-tester:{"name":"Channels Object","json_pointer":"/channels"} -->+```yaml+userSignedUp:+  address: 'user.signedup'+  messages:+    userSignedUp:+      $ref: '#/components/messages/userSignedUp'+```++#### <a name="channelObject"></a>Channel Object++Describes a shared communication channel.++##### Fixed Fields++Field Name | Type | Description+---|:---:|---+<a name="channelObjectAddress"></a>address | `string` \| `null` | An optional string representation of this channel's address. The address is typically the "topic name", "routing key", "event type", or "path". When `null` or absent, it MUST be interpreted as unknown. This is useful when the address is generated dynamically at runtime or can't be known upfront. It MAY contain [Channel Address Expressions](#channelAddressExpressions). Query parameters and fragments SHALL NOT be used, instead use [bindings](#channelBindingsObject) to define them.+<a name="channelObjectMessages"></a>messages | [Messages Object](#messagesObject) | A map of the messages that will be sent to this channel by any application at any time. **Every message sent to this channel MUST be valid against one, and only one, of the [message objects](#messageObject) defined in this map.**+<a name="channelObjectTitle"></a>title | `string` | A human-friendly title for the channel.+<a name="channelObjectSummary"></a>summary | `string` | A short summary of the channel.+<a name="channelObjectDescription"></a>description | `string` | An optional description of this channel. [CommonMark syntax](https://spec.commonmark.org/) can be used for rich text representation.+<a name="channelObjectServers"></a>servers | [[Reference Object](#referenceObject)] | An array of `$ref` pointers to the definition of the servers in which this channel is available. If the channel is located in the [root Channels Object](#channelsObject), it MUST point to a subset of server definitions located in the [root Servers Object](#serversObject), and MUST NOT point to a subset of server definitions located in the [Components Object](#componentsObject) or anywhere else. If the channel is located in the [Components Object](#componentsObject), it MAY point to a [Server Objects](#serverObject) in any location. If `servers` is absent or empty, this channel MUST be available on all the servers defined in the [Servers Object](#serversObject). Please note the `servers` property value MUST be an array of [Reference Objects](#referenceObject) and, therefore, MUST NOT contain an array of [Server Objects](#serverObject). However, it is RECOMMENDED that parsers (or other software) dereference this property for a better development experience.+<a name="channelObjectParameters"></a>parameters | [Parameters Object](#parametersObject) | A map of the parameters included in the channel address. It MUST be present only when the address contains [Channel Address Expressions](#channelAddressExpressions).+<a name="channelObjectTags"></a>tags | [Tags Object](#tagsObject) | A list of tags for logical grouping of channels.+<a name="channelObjectExternalDocs"></a>externalDocs | [External Documentation Object](#externalDocumentationObject) \| [Reference Object](#referenceObject) | Additional external documentation for this channel.+<a name="channelObjectBindings"></a>bindings | [Channel Bindings Object](#channelBindingsObject) \| [Reference Object](#referenceObject) | A map where the keys describe the name of the protocol and the values describe protocol-specific definitions for the channel.++This object MAY be extended with [Specification Extensions](#specificationExtensions).++##### Channel Object Example++<!-- asyncapi-example-tester:{"name":"Channel Object","json_pointer":"/channels/user"} -->+```json+{+  "address": "users.{userId}",+  "title": "Users channel",+  "description": "This channel is used to exchange messages about user events.",+  "messages": {+    "userSignedUp": {+      "$ref": "#/components/messages/userSignedUp"+    },+    "userCompletedOrder": {+      "$ref": "#/components/messages/userCompletedOrder"+    }+  },+  "parameters": {+    "userId": {+      "$ref": "#/components/parameters/userId"+    }+  },+  "servers": [+    { "$ref": "#/servers/rabbitmqInProd" },+    { "$ref": "#/servers/rabbitmqInStaging" }+  ],+  "bindings": {+    "amqp": {+      "is": "queue",+      "queue": {+        "exclusive": true+      }+    }+  },+  "tags": [{+    "name": "user",+    "description": "User-related messages"+  }],+  "externalDocs": {+    "description": "Find more info here",+    "url": "https://example.com"+  }+}+```++<!-- asyncapi-example-tester:{"name":"Channel Object","json_pointer":"/channels/user"} -->+```yaml+address: 'users.{userId}'+title: Users channel+description: This channel is used to exchange messages about user events.+messages:+  userSignedUp:+    $ref: '#/components/messages/userSignedUp'+  userCompletedOrder:+    $ref: '#/components/messages/userCompletedOrder'+parameters:+  userId:+    $ref: '#/components/parameters/userId'+servers:+  - $ref: '#/servers/rabbitmqInProd'+  - $ref: '#/servers/rabbitmqInStaging'+bindings:+  amqp:+    is: queue+    queue:+      exclusive: true+tags:+  - name: user+    description: User-related messages+externalDocs:+  description: 'Find more info here'+  url: 'https://example.com'+```++#### <a name="channelAddressExpressions"></a>Channel Address Expressions++Channel addresses MAY contain expressions that can be used to define dynamic values.++Expressions MUST be composed by a name enclosed in curly braces (`{` and `}`). E.g., `{userId}`.++#### <a name="messagesObject"></a>Messages Object++Describes a map of messages included in a channel.++##### Patterned Fields++Field Pattern | Type | Description+---|:---:|---+<a name="messagesObjectId"></a>`{messageId}` | [Message Object](#messageObject) \| [Reference Object](#referenceObject) | The key represents the message identifier. The `messageId` value is **case-sensitive**. Tools and libraries MAY use the `messageId` value to uniquely identify a message, therefore, it is RECOMMENDED to follow common programming naming conventions.++##### Messages Object Example++<!-- asyncapi-example-tester:{"name":"Messages Object","json_pointer":"/channels/user/messages"} -->+```json+{+  "userSignedUp": {+    "$ref": "#/components/messages/userSignedUp"+  },+  "userCompletedOrder": {+    "$ref": "#/components/messages/userCompletedOrder"+  }+}+```++<!-- asyncapi-example-tester:{"name":"Messages Object","json_pointer":"/channels/user/messages"} -->+```yaml+userSignedUp:+  $ref: '#/components/messages/userSignedUp'+userCompletedOrder:+  $ref: '#/components/messages/userCompletedOrder'+```++#### <a name="operationsObject"></a>Operations Object++Holds a dictionary with all the [operations](#operationObject) this application MUST implement.++> If you're looking for a place to define operations that MAY or MAY NOT be implemented by the application, consider defining them in [`components/operations`](#componentsOperations).++##### Patterned Fields++Field Pattern | Type | Description+---|:---:|---+<a name="operationsObjectOperation"></a>{operationId} | [Operation Object](#operationObject) \| [Reference Object](#referenceObject) | The operation this application MUST implement. The field name (`operationId`) MUST be a string used to identify the operation in the document where it is defined, and its 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.++##### Operations Object Example++<!-- asyncapi-example-tester:{"name":"Operations Object","json_pointer":"/operations"} -->+```json+{+  "onUserSignUp": {+    "title": "User sign up",+    "summary": "Action to sign a user up.",+    "description": "A longer description",+    "channel": {+      "$ref": "#/channels/userSignup"+    },+    "action": "send",+    "tags": [+      { "name": "user" },+      { "name": "signup" },+      { "name": "register" }+    ],+    "bindings": {+      "amqp": {+        "ack": false+      }+    },+    "traits": [+      { "$ref": "#/components/operationTraits/kafka" }+    ]+  }+}+```++<!-- asyncapi-example-tester:{"name":"Operations Object","json_pointer":"/operations"} -->+```yaml+onUserSignUp:+  title: User sign up+  summary: Action to sign a user up.+  description: A longer description+  channel:+    $ref: '#/channels/userSignup'+  action: send+  tags:+    - name: user+    - name: signup+    - name: register+  bindings:+    amqp:+      ack: false+  traits:+    - $ref: '#/components/operationTraits/kafka'+```++#### <a name="operationObject"></a>Operation Object++Describes a specific operation.++##### Fixed Fields++Field Name | Type | Description+---|:---:|---+<a name="operationObjectAction"></a>action | `"send"` &#124; `"receive"` | **Required**. Use `send` when it's expected that the application will send a message to the given [`channel`](#operationObjectChannel), and `receive` when the application should expect receiving messages from the given [`channel`](#operationObjectChannel).+<a name="operationObjectChannel"></a>channel | [Reference Object](#referenceObject) | **Required**. A `$ref` pointer to the definition of the channel in which this operation is performed. If the operation is located in the [root Operations Object](#operationsObject), it MUST point to a channel definition located in the [root Channels Object](#channelsObject), and MUST NOT point to a channel definition located in the [Components Object](#componentsObject) or anywhere else. If the operation is located in the [Components Object](#componentsObject), it MAY point to a [Channel Object](#channelObject) in any location. Please note the `channel` property value MUST be a [Reference Object](#referenceObject) and, therefore, MUST NOT contain a [Channel Object](#channelObject). However, it is RECOMMENDED that parsers (or other software) dereference this property for a better development experience.+<a name="operationObjectTitle"></a>title | `string` | A human-friendly title for the operation.+<a name="operationObjectSummary"></a>summary | `string` | A short summary of what the operation is about.+<a name="operationObjectDescription"></a>description | `string` | A verbose explanation of the operation. [CommonMark syntax](http://spec.commonmark.org/) can be used for rich text representation.+<a name="operationObjectSecurity"></a>security | [[Security Scheme Object](#securitySchemeObject) \| [Reference Object](#referenceObject)]| A declaration of which security schemes are associated with this operation. Only one of the [security scheme objects](#securitySchemeObject) MUST be satisfied to authorize an operation. In cases where [Server Security](#serverObjectSecurity) also applies, it MUST also be satisfied.+<a name="operationObjectTags"></a>tags | [Tags Object](#tagsObject) | A list of tags for logical grouping and categorization of operations.+<a name="operationObjectExternalDocs"></a>externalDocs | [External Documentation Object](#externalDocumentationObject) \| [Reference Object](#referenceObject) | Additional external documentation for this operation.+<a name="operationObjectBindings"></a>bindings | [Operation Bindings Object](#operationBindingsObject) \| [Reference Object](#referenceObject) | A map where the keys describe the name of the protocol and the values describe protocol-specific definitions for the operation.+<a name="operationObjectTraits"></a>traits | [[Operation Trait Object](#operationTraitObject) &#124; [Reference Object](#referenceObject) ] | A list of traits to apply to the operation object. Traits MUST be merged using [traits merge mechanism](#traits-merge-mechanism). The resulting object MUST be a valid [Operation Object](#operationObject).+<a name="operationObjectMessages"></a>messages | [[Reference Object](#referenceObject)] | A list of `$ref` pointers pointing to the supported [Message Objects](#messageObject) that can be processed by this operation. It MUST contain a subset of the messages defined in the [channel referenced in this operation](#operationObjectChannel), and MUST NOT point to a subset of message definitions located in the [Messages Object](#componentsMessages) in the [Components Object](#componentsObject) or anywhere else. **Every message processed by this operation MUST be valid against one, and only one, of the [message objects](#messageObject) referenced in this list.** Please note the `messages` property value MUST be a list of [Reference Objects](#referenceObject) and, therefore, MUST NOT contain [Message Objects](#messageObject). However, it is RECOMMENDED that parsers (or other software) dereference this property for a better development experience. <p>**Note**: excluding this property from the Operation implies that all messages from the channel will be included. Explicitly set the `messages` property to `[]` if this operation should contain no messages.</p>+<a name="operationObjectReply"></a>reply | [Operation Reply Object](#operationReplyObject) &#124; [Reference Object](#referenceObject)  | The definition of the reply in a request-reply operation.++This object MAY be extended with [Specification Extensions](#specificationExtensions).++##### Operation Object Example++<!-- asyncapi-example-tester:{"name":"Operation Object","json_pointer":"/operations/sendUserSignUp"} -->+```json+{+  "title": "User sign up",+  "summary": "Action to sign a user up.",+  "description": "A longer description",+  "channel": {+    "$ref": "#/channels/userSignup"+  },+  "action": "send",+  "security": [+    {+      "type": "oauth2",+      "description": "The oauth security descriptions",+      "flows": {+        "clientCredentials": {+          "tokenUrl": "https://example.com/api/oauth/dialog",+          "availableScopes": {+            "subscribe:auth_revocations": "Scope required for authorization revocation topic"+          }+        }+      },+      "scopes": [+        "subscribe:auth_revocations"+      ],+     "petstore_auth": [+       "write:pets",+       "read:pets"+     ]+    }+  ],+  "tags": [+    { "name": "user" },+    { "name": "signup" },+    { "name": "register" }+  ],+  "bindings": {+    "amqp": {+      "ack": false+    }+  },+  "traits": [+    { "$ref": "#/components/operationTraits/kafka" }+  ],+  "messages": [+    { "$ref": "#/channels/userSignup/messages/userSignedUp" }+  ],+  "reply": {+    "address": {+      "location": "$message.header#/replyTo"+    },+    "channel": {+      "$ref": "#/channels/userSignupReply"+    },+    "messages": [+      { "$ref": "#/channels/userSignupReply/messages/userSignedUpReply" }+    ]+  }+}+```++<!-- asyncapi-example-tester:{"name":"Operation Object","json_pointer":"/operations/sendUserSignUp"} -->+```yaml+title: User sign up+summary: Action to sign a user up.+description: A longer description+channel:+  $ref: '#/channels/userSignup'+action: send+security:+  - type: oauth2+    description: The oauth security descriptions+    flows:+      clientCredentials:+        tokenUrl: 'https://example.com/api/oauth/dialog'+        availableScopes:+          'subscribe:auth_revocations': Scope required for authorization revocation topic+    scopes:+      - 'subscribe:auth_revocations'+    petstore_auth:+      - 'write:pets'+      - 'read:pets'+tags:+  - name: user+  - name: signup+  - name: register+bindings:+  amqp:+    ack: false+traits:+  - $ref: '#/components/operationTraits/kafka'+messages:+  - $ref: '#/channels/userSignup/messages/userSignedUp'+reply:+  address:+    location: '$message.header#/replyTo'+  channel:+    $ref: '#/channels/userSignupReply'+  messages:+    - $ref: '#/channels/userSignupReply/messages/userSignedUpReply'+```++#### <a name="operationTraitObject"></a>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 the `action`, `channel`, `messages` and `traits` ones.++If you're looking to apply traits to a message, see the [Message Trait Object](#messageTraitObject).++##### Fixed Fields++Field Name | Type | Description+---|:---:|---+<a name="operationTraitObjectTitle"></a>title | `string` | A human-friendly title for the operation.+<a name="operationTraitObjectSummary"></a>summary | `string` | A short summary of what the operation is about.+<a name="operationTraitObjectDescription"></a>description | `string` | A verbose explanation of the operation. [CommonMark syntax](https://spec.commonmark.org/) can be used for rich text representation.+<a name="operationTraitObjectSecurity"></a>security | [[Security Scheme Object](#securitySchemeObject) \| [Reference Object](#referenceObject)]| A declaration of which security schemes are associated with this operation. Only one of the [security scheme objects](#securitySchemeObject) MUST be satisfied to authorize an operation. In cases where [Server Security](#serverObjectSecurity) also applies, it MUST also be satisfied.+<a name="operationTraitObjectTags"></a>tags | [Tags Object](#tagsObject) | A list of tags for logical grouping and categorization of operations.+<a name="operationTraitObjectExternalDocs"></a>externalDocs | [External Documentation Object](#externalDocumentationObject) \| [Reference Object](#referenceObject) | Additional external documentation for this operation.+<a name="operationTraitObjectBindings"></a>bindings | [Operation Bindings Object](#operationBindingsObject) \| [Reference Object](#referenceObject) | A map where the keys describe the name of the protocol and the values describe protocol-specific definitions for the operation.++This object MAY be extended with [Specification Extensions](#specificationExtensions).++##### Operation Trait Object Example++<!-- asyncapi-example-tester:{"name":"Operation Traits Object","json_pointer":"/operations/sendUserSignUp/traits/0"} -->+```json+{+  "bindings": {+    "amqp": {+      "ack": false+    }+  }+}+```++<!-- asyncapi-example-tester:{"name":"Operation Traits Object","json_pointer":"/operations/sendUserSignUp/traits/0"} -->+```yaml+bindings:+  amqp:+    ack: false+```++#### <a name="operationReplyObject"></a>Operation Reply Object++Describes the reply part that MAY be applied to an Operation Object. If an operation implements the request/reply pattern, the reply object represents the response message.++##### Fixed Fields++Field Name | Type | Description+---|:---:|---+<a name="operationReplyObjectAddress"></a>address | [Operation Reply Address Object](#operationReplyAddressObject) &#124; [Reference Object](#referenceObject) | Definition of the address that implementations MUST use for the reply.+<a name="operationReplyObjectChannel"></a>channel | [Reference Object](#referenceObject) | A `$ref` pointer to the definition of the channel in which this operation is performed. When [address](#operationReplyAddressObject) is specified, the [`address` property](#channelObjectAddress) of the channel referenced by this property MUST be either `null` or not defined. If the operation reply is located inside a [root Operation Object](#operationObject), it MUST point to a channel definition located in the [root Channels Object](#channelsObject), and MUST NOT point to a channel definition located in the [Components Object](#componentsObject) or anywhere else. If the operation reply is located inside an [Operation Object] in the [Components Object](#componentsObject) or in the [Replies Object](#componentsReplies) in the [Components Object](#componentsObject), it MAY point to a [Channel Object](#channelObject) in any location. Please note the `channel` property value MUST be a [Reference Object](#referenceObject) and, therefore, MUST NOT contain a [Channel Object](#channelObject). However, it is RECOMMENDED that parsers (or other software) dereference this property for a better development experience.+<a name="operationReplyObjectMessages"></a>messages | [[Reference Object](#referenceObject)] | A list of `$ref` pointers pointing to the supported [Message Objects](#messageObject) that can be processed by this operation as reply. It MUST contain a subset of the messages defined in the [channel referenced in this operation reply](#operationObjectChannel), and MUST NOT point to a subset of message definitions located in the [Components Object](#componentsObject) or anywhere else. **Every message processed by this operation MUST be valid against one, and only one, of the [message objects](#messageObject) referenced in this list.** Please note the `messages` property value MUST be a list of [Reference Objects](#referenceObject) and, therefore, MUST NOT contain [Message Objects](#messageObject). However, it is RECOMMENDED that parsers (or other software) dereference this property for a better development experience.++This object MAY be extended with [Specification Extensions](#specificationExtensions).++#### <a name="operationReplyAddressObject"></a>Operation Reply Address Object++An object that specifies where an operation has to send the reply.++For specifying and computing the location of a reply address, a [runtime expression](#runtimeExpression) is used.++##### Fixed Fields++Field Name | Type | Description+---|:---|---+description | `string` | An optional description of the address. [CommonMark syntax](https://spec.commonmark.org/) can be used for rich text representation.+location | `string` | **REQUIRED.** A [runtime expression](#runtimeExpression) that specifies the location of the reply address.++This object MAY be extended with [Specification Extensions](#specificationExtensions).++##### Examples++<!-- asyncapi-example-tester:{"name":"Operation Reply Address Object","json_pointer":"/operations/sendUserSignUp/reply/address"} -->+```json+{+  "description": "Consumer inbox",+  "location": "$message.header#/replyTo"+}+```++<!-- asyncapi-example-tester:{"name":"Operation Reply Address Object","json_pointer":"/operations/sendUserSignUp/reply/address"} -->+```yaml+description: Consumer Inbox+location: $message.header#/replyTo+```++#### <a name="parametersObject"></a>Parameters Object++Describes a map of parameters included in a channel address.++This map MUST contain all the parameters used in the parent channel address.++##### Patterned Fields++Field Pattern | Type | Description+---|:---:|---+<a name="parametersObjectName"></a>`^[A-Za-z0-9_\-]+$` | [Parameter Object](#parameterObject) &#124; [Reference Object](#referenceObject) | The key represents the name of the parameter. It MUST match the parameter name used in the parent channel address.++##### Parameters Object Example++<!-- asyncapi-example-tester:{"name":"Channel Parameters Object","json_pointer":"/channels/user"} -->+```json+{+  "address": "user/{userId}/signedup",+  "parameters": {+    "userId": {+      "description": "Id of the user."+    }+  }+}+```++<!-- asyncapi-example-tester:{"name":"Channel Parameters Object","json_pointer":"/channels/user"} -->+```yaml+address: user/{userId}/signedup+parameters:+  userId:+    description: Id of the user.+```++#### <a name="parameterObject"></a>Parameter Object++Describes a parameter included in a channel address.++##### Fixed Fields++Field Name | Type | Description+---|:---:|---+<a name="parameterObjectEnum"></a>enum | [`string`] | An enumeration of string values to be used if the substitution options are from a limited set.+<a name="parameterObjectDefault"></a>default | `string` | The default value to use for substitution, and to send, if an alternate value is _not_ supplied.+<a name="parameterObjectDescription"></a>description | `string` | An optional description for the parameter. [CommonMark syntax](https://spec.commonmark.org/) MAY be used for rich text representation.+<a name="parameterObjectExamples"></a>examples | [`string`] | An array of examples of the parameter value.+<a name="parameterObjectLocation"></a>location | `string` | A [runtime expression](#runtimeExpression) that specifies the location of the parameter value.++This object MAY be extended with [Specification Extensions](#specificationExtensions).++##### Parameter Object Example++<!-- asyncapi-example-tester:{"name":"Channel Parameter Object","json_pointer":"/channels/user"} -->+```json+{+  "address": "user/{userId}/signedup",+  "parameters": {+    "userId": {+      "description": "Id of the user.",+      "location": "$message.payload#/user/id"+    }+  }+}+```++<!-- asyncapi-example-tester:{"name":"Channel Parameter Object","json_pointer":"/channels/user"} -->+```yaml+address: user/{userId}/signedup+parameters:+  userId:+    description: Id of the user.+    location: $message.payload#/user/id+```++#### <a name="serverBindingsObject"></a>Server Bindings Object++Map describing protocol-specific definitions for a server.++##### Fixed Fields++Field Name | Type | Description+---|:---:|---+<a name="serverBindingsObjectHTTP"></a>`http` | [HTTP Server Binding](https://github.com/asyncapi/bindings/blob/master/http#server) | Protocol-specific information for an HTTP server.+<a name="serverBindingsObjectWebSockets"></a>`ws` | [WebSockets Server Binding](https://github.com/asyncapi/bindings/blob/master/websockets#server) | Protocol-specific information for a WebSockets server.+<a name="serverBindingsObjectKafka"></a>`kafka` | [Kafka Server Binding](https://github.com/asyncapi/bindings/blob/master/kafka#server) | Protocol-specific information for a Kafka server.+<a name="serverBindingsObjectAnypointMQ"></a>`anypointmq` | [Anypoint MQ Server Binding](https://github.com/asyncapi/bindings/blob/master/anypointmq#server) | Protocol-specific information for an Anypoint MQ server.+<a name="serverBindingsObjectAMQP"></a>`amqp` | [AMQP Server Binding](https://github.com/asyncapi/bindings/blob/master/amqp#server) | Protocol-specific information for an AMQP 0-9-1 server.+<a name="serverBindingsObjectAMQP1"></a>`amqp1` | [AMQP 1.0 Server Binding](https://github.com/asyncapi/bindings/blob/master/amqp1#server) | Protocol-specific information for an AMQP 1.0 server.+<a name="serverBindingsObjectMQTT"></a>`mqtt` | [MQTT Server Binding](https://github.com/asyncapi/bindings/blob/master/mqtt#server) | Protocol-specific information for an MQTT server.+<a name="serverBindingsObjectMQTT5"></a>`mqtt5` | [MQTT 5 Server Binding](https://github.com/asyncapi/bindings/blob/master/mqtt5#server) | Protocol-specific information for an MQTT 5 server.+<a name="serverBindingsObjectNATS"></a>`nats` | [NATS Server Binding](https://github.com/asyncapi/bindings/blob/master/nats#server) | Protocol-specific information for a NATS server.+<a name="serverBindingsObjectJMS"></a>`jms` | [JMS Server Binding](https://github.com/asyncapi/bindings/blob/master/jms#server) | Protocol-specific information for a JMS server.+<a name="serverBindingsObjectSNS"></a>`sns` | [SNS Server Binding](https://github.com/asyncapi/bindings/blob/master/sns#server) | Protocol-specific information for an SNS server.+<a name="serverBindingsObjectSolace"></a>`solace` | [Solace Server Binding](https://github.com/asyncapi/bindings/blob/master/solace#server) | Protocol-specific information for a Solace server.+<a name="serverBindingsObjectSQS"></a>`sqs` | [SQS Server Binding](https://github.com/asyncapi/bindings/blob/master/sqs#server) | Protocol-specific information for an SQS server.+<a name="serverBindingsObjectSTOMP"></a>`stomp` | [STOMP Server Binding](https://github.com/asyncapi/bindings/blob/master/stomp#server) | Protocol-specific information for a STOMP server.+<a name="serverBindingsObjectRedis"></a>`redis` | [Redis Server Binding](https://github.com/asyncapi/bindings/blob/master/redis#server) | Protocol-specific information for a Redis server.+<a name="serverBindingsObjectMercure"></a>`mercure` | [Mercure Server Binding](https://github.com/asyncapi/bindings/blob/master/mercure#server) | Protocol-specific information for a Mercure server.+<a name="serverBindingsObjectIBMMQ"></a>`ibmmq` | [IBM MQ Server Binding](https://github.com/asyncapi/bindings/blob/master/ibmmq#server-binding-object) | Protocol-specific information for an IBM MQ server.+<a name="serverBindingsObjectGooglePubSub"></a>`googlepubsub` | [Google Cloud Pub/Sub Server Binding](https://github.com/asyncapi/bindings/blob/master/googlepubsub#server) | Protocol-specific information for a Google Cloud Pub/Sub server.+<a name="serverBindingsObjectPulsar"></a>`pulsar` | [Pulsar Server Binding](https://github.com/asyncapi/bindings/tree/master/pulsar#server-binding-object) | Protocol-specific information for a Pulsar server.+<a name="serverBindingsObjectROS2"></a>`ros2` | [ROS 2 Server Binding](https://github.com/asyncapi/bindings/tree/master/ros2#server-binding-object) | Protocol-specific information for a ROS 2 server.++This object MAY be extended with [Specification Extensions](#specificationExtensions).++#### <a name="channelBindingsObject"></a>Channel Bindings Object++Map describing protocol-specific definitions for a channel.++##### Fixed Fields++Field Name | Type | Description+---|:---:|---+<a name="channelBindingsObjectHTTP"></a>`http` | [HTTP Channel Binding](https://github.com/asyncapi/bindings/blob/master/http/README.md#channel) | Protocol-specific information for an HTTP channel.+<a name="channelBindingsObjectWebSockets"></a>`ws` | [WebSockets Channel Binding](https://github.com/asyncapi/bindings/blob/master/websockets/README.md#channel) | Protocol-specific information for a WebSockets channel.+<a name="channelBindingsObjectKafka"></a>`kafka` | [Kafka Channel Binding](https://github.com/asyncapi/bindings/blob/master/kafka/README.md#channel) | Protocol-specific information for a Kafka channel.+<a name="channelBindingsObjectAnypointMQ"></a>`anypointmq` | [Anypoint MQ Channel Binding](https://github.com/asyncapi/bindings/blob/master/anypointmq/README.md#channel) | Protocol-specific information for an Anypoint MQ channel.+<a name="channelBindingsObjectAMQP"></a>`amqp` | [AMQP Channel Binding](https://github.com/asyncapi/bindings/blob/master/amqp/README.md#channel) | Protocol-specific information for an AMQP 0-9-1 channel.+<a name="channelBindingsObjectAMQP1"></a>`amqp1` | [AMQP 1.0 Channel Binding](https://github.com/asyncapi/bindings/blob/master/amqp1/README.md#channel) | Protocol-specific information for an AMQP 1.0 channel.+<a name="channelBindingsObjectMQTT"></a>`mqtt` | [MQTT Channel Binding](https://github.com/asyncapi/bindings/blob/master/mqtt/README.md#channel) | Protocol-specific information for an MQTT channel.+<a name="channelBindingsObjectMQTT5"></a>`mqtt5` | [MQTT 5 Channel Binding](https://github.com/asyncapi/bindings/blob/master/mqtt5#channel) | Protocol-specific information for an MQTT 5 channel.+<a name="channelBindingsObjectNATS"></a>`nats` | [NATS Channel Binding](https://github.com/asyncapi/bindings/blob/master/nats/README.md#channel) | Protocol-specific information for a NATS channel.+<a name="channelBindingsObjectJMS"></a>`jms` | [JMS Channel Binding](https://github.com/asyncapi/bindings/blob/master/jms/README.md#channel) | Protocol-specific information for a JMS channel.+<a name="channelBindingsObjectSNS"></a>`sns` | [SNS Channel Binding](https://github.com/asyncapi/bindings/blob/master/sns/README.md#channel) | Protocol-specific information for an SNS channel.+<a name="channelBindingsObjectSolace"></a>`solace` | [Solace Channel Binding](https://github.com/asyncapi/bindings/blob/master/solace#channel) | Protocol-specific information for a Solace channel.+<a name="channelBindingsObjectSQS"></a>`sqs` | [SQS Channel Binding](https://github.com/asyncapi/bindings/blob/master/sqs/README.md#channel) | Protocol-specific information for an SQS channel.+<a name="channelBindingsObjectSTOMP"></a>`stomp` | [STOMP Channel Binding](https://github.com/asyncapi/bindings/blob/master/stomp/README.md#channel) | Protocol-specific information for a STOMP channel.+<a name="channelBindingsObjectRedis"></a>`redis` | [Redis Channel Binding](https://github.com/asyncapi/bindings/blob/master/redis#channel) | Protocol-specific information for a Redis channel.+<a name="channelBindingsObjectMercure"></a>`mercure` | [Mercure Channel Binding](https://github.com/asyncapi/bindings/blob/master/mercure#channel) | Protocol-specific information for a Mercure channel.+<a name="channelBindingsObjectIBMMQ"></a>`ibmmq` | [IBM MQ Channel Binding](https://github.com/asyncapi/bindings/tree/master/ibmmq#channel-binding-object) | Protocol-specific information for an IBM MQ channel.+<a name="channelBindingsObjectGooglePubSub"></a>`googlepubsub` | [Google Cloud Pub/Sub Channel Binding](https://github.com/asyncapi/bindings/tree/master/googlepubsub#channel) | Protocol-specific information for a Google Cloud Pub/Sub channel.+<a name="channelBindingsObjectPulsar"></a>`pulsar` | [Pulsar Channel Binding](https://github.com/asyncapi/bindings/tree/master/pulsar#channel-binding-object) | Protocol-specific information for a Pulsar channel.+<a name="channelBindingsObjectROS2"></a>`ros2` | [ROS 2 Channel Binding](https://github.com/asyncapi/bindings/tree/master/ros2#channel-binding-object) | Protocol-specific information for a ROS 2 channel.++This object MAY be extended with [Specification Extensions](#specificationExtensions).++#### <a name="operationBindingsObject"></a>Operation Bindings Object++Map describing protocol-specific definitions for an operation.++##### Fixed Fields++Field Name | Type | Description+---|:---:|---+<a name="operationBindingsObjectHTTP"></a>`http` | [HTTP Operation Binding](https://github.com/asyncapi/bindings/blob/master/http/README.md#operation) | Protocol-specific information for an HTTP operation.+<a name="operationBindingsObjectWebSockets"></a>`ws` | [WebSockets Operation Binding](https://github.com/asyncapi/bindings/blob/master/websockets/README.md#operation) | Protocol-specific information for a WebSockets operation.+<a name="operationBindingsObjectKafka"></a>`kafka` | [Kafka Operation Binding](https://github.com/asyncapi/bindings/blob/master/kafka/README.md#operation) | Protocol-specific information for a Kafka operation.+<a name="operationBindingsObjectAnypointMQ"></a>`anypointmq` | [Anypoint MQ Operation Binding](https://github.com/asyncapi/bindings/blob/master/anypointmq/README.md#operation) | Protocol-specific information for an Anypoint MQ operation.+<a name="operationBindingsObjectAMQP"></a>`amqp` | [AMQP Operation Binding](https://github.com/asyncapi/bindings/blob/master/amqp/README.md#operation) | Protocol-specific information for an AMQP 0-9-1 operation.+<a name="operationBindingsObjectAMQP1"></a>`amqp1` | [AMQP 1.0 Operation Binding](https://github.com/asyncapi/bindings/blob/master/amqp1/README.md#operation) | Protocol-specific information for an AMQP 1.0 operation.+<a name="operationBindingsObjectMQTT"></a>`mqtt` | [MQTT Operation Binding](https://github.com/asyncapi/bindings/blob/master/mqtt/README.md#operation) | Protocol-specific information for an MQTT operation.+<a name="operationBindingsObjectMQTT5"></a>`mqtt5` | [MQTT 5 Operation Binding](https://github.com/asyncapi/bindings/blob/master/mqtt5/README.md#operation) | Protocol-specific information for an MQTT 5 operation.+<a name="operationBindingsObjectNATS"></a>`nats` | [NATS Operation Binding](https://github.com/asyncapi/bindings/blob/master/nats/README.md#operation) | Protocol-specific information for a NATS operation.+<a name="operationBindingsObjectJMS"></a>`jms` | [JMS Operation Binding](https://github.com/asyncapi/bindings/blob/master/jms/README.md#operation) | Protocol-specific information for a JMS operation.+<a name="operationBindingsObjectSNS"></a>`sns` | [SNS Operation Binding](https://github.com/asyncapi/bindings/blob/master/sns/README.md#operation) | Protocol-specific information for an SNS operation.+<a name="operationBindingsObjectSolace"></a>`solace` | [Solace Operation Binding](https://github.com/asyncapi/bindings/blob/master/solace#operation) | Protocol-specific information for a Solace operation.+<a name="operationBindingsObjectSQS"></a>`sqs` | [SQS Operation Binding](https://github.com/asyncapi/bindings/blob/master/sqs/README.md#operation) | Protocol-specific information for an SQS operation.+<a name="operationBindingsObjectSTOMP"></a>`stomp` | [STOMP Operation Binding](https://github.com/asyncapi/bindings/blob/master/stomp/README.md#operation) | Protocol-specific information for a STOMP operation.+<a name="operationBindingsObjectRedis"></a>`redis` | [Redis Operation Binding](https://github.com/asyncapi/bindings/blob/master/redis#operation) | Protocol-specific information for a Redis operation.+<a name="operationBindingsObjectMercure"></a>`mercure` | [Mercure Operation Binding](https://github.com/asyncapi/bindings/blob/master/mercure#operation) | Protocol-specific information for a Mercure operation.+<a name="operationBindingsObjectGooglePubSub"></a>`googlepubsub` | [Google Cloud Pub/Sub Operation Binding](https://github.com/asyncapi/bindings/blob/master/googlepubsub#operation) | Protocol-specific information for a Google Cloud Pub/Sub operation.+<a name="operationBindingsObjectIBMMQ"></a>`ibmmq` | [IBM MQ Operation Binding](https://github.com/asyncapi/bindings/blob/master/ibmmq#operation-binding-object) | Protocol-specific information for an IBM MQ operation.+<a name="operationBindingsObjectPulsar"></a>`pulsar` | [Pulsar Operation Binding](https://github.com/asyncapi/bindings/tree/master/pulsar#operation-binding-fields) | Protocol-specific information for a Pulsar operation.+<a name="operationBindingsObjectROS2"></a>`ros2` | [ROS 2 Operation Binding](https://github.com/asyncapi/bindings/tree/master/ros2#operation-binding-fields) | Protocol-specific information for a ROS 2 operation.++This object MAY be extended with [Specification Extensions](#specificationExtensions).++#### <a name="messageBindingsObject"></a>Message Bindings Object++Map describing protocol-specific definitions for a message.++##### Fixed Fields++Field Name | Type | Description+---|:---:|---+<a name="messageBindingsObjectHTTP"></a>`http` | [HTTP Message Binding](https://github.com/asyncapi/bindings/blob/master/http/README.md#message) | Protocol-specific information for an HTTP message, i.e., a request or a response.+<a name="messageBindingsObjectWebSockets"></a>`ws` | [WebSockets Message Binding](https://github.com/asyncapi/bindings/blob/master/websockets/README.md#message) | Protocol-specific information for a WebSockets message.+<a name="messageBindingsObjectKafka"></a>`kafka` | [Kafka Message Binding](https://github.com/asyncapi/bindings/blob/master/kafka/README.md#message) | Protocol-specific information for a Kafka message.+<a name="messageBindingsObjectAnypointMQ"></a>`anypointmq` | [Anypoint MQ Message Binding](https://github.com/asyncapi/bindings/blob/master/anypointmq/README.md#message) | Protocol-specific information for an Anypoint MQ message.+<a name="messageBindingsObjectAMQP"></a>`amqp` | [AMQP Message Binding](https://github.com/asyncapi/bindings/blob/master/amqp/README.md#message) | Protocol-specific information for an AMQP 0-9-1 message.+<a name="messageBindingsObjectAMQP1"></a>`amqp1` | [AMQP 1.0 Message Binding](https://github.com/asyncapi/bindings/blob/master/amqp1/README.md#message) | Protocol-specific information for an AMQP 1.0 message.+<a name="messageBindingsObjectMQTT"></a>`mqtt` | [MQTT Message Binding](https://github.com/asyncapi/bindings/blob/master/mqtt/README.md#message) | Protocol-specific information for an MQTT message.+<a name="messageBindingsObjectMQTT5"></a>`mqtt5` | [MQTT 5 Message Binding](https://github.com/asyncapi/bindings/blob/master/mqtt5/README.md#message) | Protocol-specific information for an MQTT 5 message.+<a name="messageBindingsObjectNATS"></a>`nats` | [NATS Message Binding](https://github.com/asyncapi/bindings/blob/master/nats/README.md#message) | Protocol-specific information for a NATS message.+<a name="messageBindingsObjectJMS"></a>`jms` | [JMS Message Binding](https://github.com/asyncapi/bindings/blob/master/jms/README.md#message) | Protocol-specific information for a JMS message.+<a name="messageBindingsObjectSNS"></a>`sns` | [SNS Message Binding](https://github.com/asyncapi/bindings/blob/master/sns/README.md#message) | Protocol-specific information for an SNS message.+<a name="messageBindingsObjectSolace"></a>`solace` | [Solace Server Binding](https://github.com/asyncapi/bindings/blob/master/solace#message) | Protocol-specific information for a Solace message.+<a name="messageBindingsObjectSQS"></a>`sqs` | [SQS Message Binding](https://github.com/asyncapi/bindings/blob/master/sqs/README.md#message) | Protocol-specific information for an SQS message.+<a name="messageBindingsObjectSTOMP"></a>`stomp` | [STOMP Message Binding](https://github.com/asyncapi/bindings/blob/master/stomp/README.md#message) | Protocol-specific information for a STOMP message.+<a name="messageBindingsObjectRedis"></a>`redis` | [Redis Message Binding](https://github.com/asyncapi/bindings/blob/master/redis#message) | Protocol-specific information for a Redis message.+<a name="messageBindingsObjectMercure"></a>`mercure` | [Mercure Message Binding](https://github.com/asyncapi/bindings/blob/master/mercure#message) | Protocol-specific information for a Mercure message.+<a name="messageBindingsObjectIBMMQ"></a>`ibmmq` | [IBM MQ Message Binding](https://github.com/asyncapi/bindings/tree/master/ibmmq#message-binding-object) | Protocol-specific information for an IBM MQ message.+<a name="messageBindingsObjectGooglePubSub"></a>`googlepubsub` | [Google Cloud Pub/Sub Message Binding](https://github.com/asyncapi/bindings/tree/master/googlepubsub#message) | Protocol-specific information for a Google Cloud Pub/Sub message.+<a name="messageBindingsObjectPulsar"></a>`pulsar` | [Pulsar Message Binding](https://github.com/asyncapi/bindings/tree/master/pulsar#message-binding-fields) | Protocol-specific information for a Pulsar message.+<a name="messageBindingsObjectROS2"></a>`ros2` | [ROS 2 Message Binding](https://github.com/asyncapi/bindings/tree/master/ros2#message-binding-fields) | Protocol-specific information for a ROS 2 message.++This object MAY be extended with [Specification Extensions](#specificationExtensions).++#### <a name="messageObject"></a>Message Object++Describes a message received on a given channel and operation.++##### Fixed Fields++Field Name | Type | Description+---|:---:|---+<a name="messageObjectHeaders"></a>headers | [Multi Format Schema Object](#multiFormatSchemaObject) &#124; [Schema Object](#schemaObject) &#124; [Reference Object](#referenceObject) | Schema definition of the application headers. Schema MUST be a map of key-value pairs. It **MUST NOT** define the protocol headers. If this is a [Schema Object](#schemaObject), then the `schemaFormat` will be assumed to be "application/vnd.aai.asyncapi+json;version=`asyncapi`" where the version is equal to the [AsyncAPI Version String](#A2SVersionString).+<a name="messageObjectPayload"></a>payload | [Multi Format Schema Object](#multiFormatSchemaObject) &#124; [Schema Object](#schemaObject) &#124; [Reference Object](#referenceObject) | Definition of the message payload. If this is a [Schema Object](#schemaObject), then the `schemaFormat` will be assumed to be "application/vnd.aai.asyncapi+json;version=`asyncapi`" where the version is equal to the [AsyncAPI Version String](#A2SVersionString).+<a name="messageObjectCorrelationId"></a>correlationId | [Correlation ID Object](#correlationIdObject) &#124; [Reference Object](#referenceObject) | Definition of the correlation ID used for message tracing or matching.+<a name="messageObjectContentType"></a>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.+<a name="messageObjectName"></a>name | `string` | A machine-friendly name for the message.+<a name="messageObjectTitle"></a>title | `string` | A human-friendly title for the message.+<a name="messageObjectSummary"></a>summary | `string` | A short summary of what the message is about.+<a name="messageObjectDescription"></a>description | `string` | A verbose explanation of the message. [CommonMark syntax](https://spec.commonmark.org/) can be used for rich text representation.+<a name="messageObjectTags"></a>tags | [Tags Object](#tagsObject) | A list of tags for logical grouping and categorization of messages.+<a name="messageObjectExternalDocs"></a>externalDocs | [External Documentation Object](#externalDocumentationObject) \| [Reference Object](#referenceObject) | Additional external documentation for this message.+<a name="messageObjectBindings"></a>bindings | [Message Bindings Object](#messageBindingsObject) \| [Reference Object](#referenceObject) | A map where the keys describe the name of the protocol and the values describe protocol-specific definitions for the message.+<a name="messageObjectExamples"></a>examples | [[Message Example Object](#messageExampleObject)] | List of examples.+<a name="messageObjectTraits"></a>traits | [[Message Trait Object](#messageTraitObject) &#124; [Reference Object](#referenceObject)] | A list of traits to apply to the message object. Traits MUST be merged using [traits merge mechanism](#traits-merge-mechanism). The resulting object MUST be a valid [Message Object](#messageObject).++This object MAY be extended with [Specification Extensions](#specificationExtensions).++##### Message Object Example++<!-- asyncapi-example-tester:{"name":"Message Object","json_pointer":"/components/messages/userSignedUp"} -->+```json+{+  "name": "UserSignup",+  "title": "User signup",+  "summary": "Action to sign a user up.",+  "description": "A longer description",+  "contentType": "application/json",+  "tags": [+    { "name": "user" },+    { "name": "signup" },+    { "name": "register" }+  ],+  "headers": {+    "type": "object",+    "properties": {+      "correlationId": {+        "description": "Correlation ID set by application",+        "type": "string"+      },+      "applicationInstanceId": {+        "description": "Unique identifier for a given instance of the publishing application",+        "type": "string"+      }+    }+  },+  "payload": {+    "type": "object",+    "properties": {+      "user": {+        "$ref": "#/components/schemas/userCreate"+      },+      "signup": {+        "$ref": "#/components/schemas/signup"+      }+    }+  },+  "correlationId": {+    "description": "Default Correlation ID",+    "location": "$message.header#/correlationId"+  },+  "traits": [+    { "$ref": "#/components/messageTraits/commonHeaders" }+  ],+  "examples": [+    {+      "name": "SimpleSignup",+      "summary": "A simple UserSignup example message",+      "headers": {+        "correlationId": "my-correlation-id",+        "applicationInstanceId": "myInstanceId"+      },+      "payload": {+        "user": {+          "someUserKey": "someUserValue"+        },+        "signup": {+          "someSignupKey": "someSignupValue"+        }+      }+    }+  ]+}+```++<!-- asyncapi-example-tester:{"name":"Message Object","json_pointer":"/components/messages/userSignedUp"} -->+```yaml+name: UserSignup+title: User signup+summary: Action to sign a user up.+description: A longer description+contentType: application/json+tags:+  - name: user+  - name: signup+  - name: register+headers:+  type: object+  properties:+    correlationId:+      description: Correlation ID set by application+      type: string+    applicationInstanceId:+      description: Unique identifier for a given instance of the publishing application+      type: string+payload:+  type: object+  properties:+    user:+      $ref: '#/components/schemas/userCreate'+    signup:+      $ref: '#/components/schemas/signup'+correlationId:+  description: Default Correlation ID+  location: $message.header#/correlationId+traits:+  - $ref: '#/components/messageTraits/commonHeaders'+examples:+  - name: SimpleSignup+    summary: A simple UserSignup example message+    headers:+      correlationId: my-correlation-id+      applicationInstanceId: myInstanceId+    payload:+      user:+        someUserKey: someUserValue+      signup:+        someSignupKey: someSignupValue+```++Example using Avro to define the payload:++<!-- asyncapi-example-tester:{"name":"Message Object","json_pointer":"/components/messages/userSignedUp"} -->+```json+{+  "name": "UserSignup",+  "title": "User signup",+  "summary": "Action to sign a user up.",+  "description": "A longer description",+  "tags": [+    { "name": "user" },+    { "name": "signup" },+    { "name": "register" }+  ],+  "payload": {+    "schemaFormat": "application/vnd.apache.avro+json;version=1.9.0",+    "schema": {+      "$ref": "./user-create.avsc"+    }+  }+}+```++<!-- asyncapi-example-tester:{"name":"Message Object","json_pointer":"/components/messages/userSignedUp"} -->+```yaml+name: UserSignup+title: User signup+summary: Action to sign a user up.+description: A longer description+tags:+  - name: user+  - name: signup+  - name: register+payload:+  schemaFormat: 'application/vnd.apache.avro+yaml;version=1.9.0'+  schema:+    $ref: './user-create.avsc'+```++#### <a name="messageTraitObject"></a>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).++##### Fixed Fields++Field Name | Type | Description+---|:---:|---+<a name="messageTraitObjectHeaders"></a>headers | [Multi Format Schema Object](#multiFormatSchemaObject) &#124; [Schema Object](#schemaObject) &#124; [Reference Object](#referenceObject) | Schema definition of the application headers. Schema MUST be a map of key-value pairs. It **MUST NOT** define the protocol headers. If this is a [Schema Object](#schemaObject), then the `schemaFormat` will be assumed to be "application/vnd.aai.asyncapi+json;version=`asyncapi`" where the version is equal to the [AsyncAPI Version String](#A2SVersionString).+<a name="messageTraitObjectCorrelationId"></a>correlationId | [Correlation ID Object](#correlationIdObject) &#124; [Reference Object](#referenceObject) | Definition of the correlation ID used for message tracing or matching.+<a name="messageTraitObjectContentType"></a>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.+<a name="messageTraitObjectName"></a>name | `string` | A machine-friendly name for the message.+<a name="messageTraitObjectTitle"></a>title | `string` | A human-friendly title for the message.+<a name="messageTraitObjectSummary"></a>summary | `string` | A short summary of what the message is about.+<a name="messageTraitObjectDescription"></a>description | `string` | A verbose explanation of the message. [CommonMark syntax](https://spec.commonmark.org/) can be used for rich text representation.+<a name="messageTraitObjectTags"></a>tags | [Tags Object](#tagsObject) | A list of tags for logical grouping and categorization of messages.+<a name="messageTraitObjectExternalDocs"></a>externalDocs | [External Documentation Object](#externalDocumentationObject) \| [Reference Object](#referenceObject) | Additional external documentation for this message.+<a name="messageTraitObjectBindings"></a>bindings | [Message Bindings Object](#messageBindingsObject) \| [Reference Object](#referenceObject) | A map where the keys describe the name of the protocol and the values describe protocol-specific definitions for the message.+<a name="messageTraitObjectExamples"></a>examples | [[Message Example Object](#messageExampleObject)] | List of examples.++This object MAY be extended with [Specification Extensions](#specificationExtensions).++##### Message Trait Object Example++<!-- asyncapi-example-tester:{"name":"Message Trait Object","json_pointer":"/components/messageTraits/commonHeaders"} -->+```json+{+  "contentType": "application/json"+}+```++<!-- asyncapi-example-tester:{"name":"Message Trait Object","json_pointer":"/components/messageTraits/commonHeaders"} -->+```yaml+contentType: application/json+```++#### <a name="messageExampleObject"></a> Message Example Object++Message Example Object represents an example of a [Message Object](#messageObject) and MUST contain either **headers** and/or **payload** fields.++##### Fixed Fields++Field Name | Type | Description+---|:---:|---+<a name="messageExampleObjectHeaders"></a>headers | `Map[string, any]` | The value of this field MUST validate against the [Message Object's headers](#messageObjectHeaders) field.+<a name="messageExampleObjectPayload"></a>payload | `any` | The value of this field MUST validate against the [Message Object's payload](#messageObjectPayload) field.+<a name="messageExampleObjectName"></a>name | `string` | A machine-friendly name.+<a name="messageExampleObjectSummary"></a>summary | `string` |  A short summary of what the example is about.++This object MAY be extended with [Specification Extensions](#specificationExtensions).++##### Message Example Object Example++<!-- asyncapi-example-tester:{"name":"Message Example Object","json_pointer":"/components/messages/userSignUp/examples/0"} -->+```json+{+  "name": "SimpleSignup",+  "summary": "A simple UserSignup example message",+  "headers": {+    "correlationId": "my-correlation-id",+    "applicationInstanceId": "myInstanceId"+  },+  "payload": {+    "user": {+      "someUserKey": "someUserValue"+    },+    "signup": {+      "someSignupKey": "someSignupValue"+    }+  }+}+```++<!-- asyncapi-example-tester:{"name":"Message Example Object","json_pointer":"/components/messages/userSignUp/examples/0"} -->+```yaml+name: SimpleSignup+summary: A simple UserSignup example message+headers:+  correlationId: my-correlation-id+  applicationInstanceId: myInstanceId+payload:+  user:+    someUserKey: someUserValue+  signup:+    someSignupKey: someSignupValue+```++#### <a name="tagsObject"></a>Tags Object++A Tags object is a list of [Tag Objects](#tagObject). An [Tag Object](#tagObject) in a list can be referenced by [Reference Object](#referenceObject).++#### <a name="tagObject"></a>Tag Object++Allows adding meta data to a single tag.++##### Fixed Fields++Field Name | Type | Description+---|:---:|---+<a name="tagObjectName"></a>name | `string` | **REQUIRED.** The name of the tag.+<a name="tagObjectDescription"></a>description | `string` | A short description for the tag. [CommonMark syntax](https://spec.commonmark.org/) can be used for rich text representation.+<a name="tagObjectExternalDocs"></a>externalDocs | [External Documentation Object](#externalDocumentationObject) \| [Reference Object](#referenceObject) | Additional external documentation for this tag.++This object MAY be extended with [Specification Extensions](#specificationExtensions).++##### Tag Object Example++<!-- asyncapi-example-tester:{"name":"Tag Object","json_pointer":"/components/tags/user"} -->+```json+{+ "name": "user",+ "description": "User-related messages"+}+```++<!-- asyncapi-example-tester:{"name":"Tag Object","json_pointer":"/components/tags/user"} -->+```yaml+name: user+description: User-related messages+```++#### <a name="externalDocumentationObject"></a>External Documentation Object++Allows referencing an external resource for extended documentation.++##### Fixed Fields++Field Name | Type | Description+---|:---:|---+<a name="externalDocDescription"></a>description | `string` | A short description of the target documentation. [CommonMark syntax](https://spec.commonmark.org/) can be used for rich text representation.+<a name="externalDocUrl"></a>url | `string` | **REQUIRED.** The URL for the target documentation. This MUST be in the form of an absolute URL.++This object MAY be extended with [Specification Extensions](#specificationExtensions).++##### External Documentation Object Example++<!-- asyncapi-example-tester:{"name":"External Docs Object","json_pointer":"/components/externalDocs/infoDocs"} -->+```json+{+  "description": "Find more info here",+  "url": "https://example.com"+}+```++<!-- asyncapi-example-tester:{"name":"External Docs Object","json_pointer":"/components/externalDocs/infoDocs"} -->+```yaml+description: Find more info here+url: https://example.com+```++#### <a name="referenceObject"></a>Reference Object++A simple object to allow referencing other components in the specification, internally and externally.++The Reference Object is defined by [JSON Reference](https://tools.ietf.org/html/draft-pbryan-zyp-json-ref-03) and follows the same structure, behavior and rules. A JSON Reference SHALL only be used to refer to a schema that is formatted in either JSON or YAML. In the case of a YAML-formatted Schema, the JSON Reference SHALL be applied to the JSON representation of that schema. The JSON representation SHALL be made by applying the conversion described [here](#format).++For this specification, reference resolution is done as defined by the JSON Reference specification and not by the JSON Schema specification.++##### Fixed Fields++Field Name | Type | Description+---|:---:|---+<a name="referenceRef"></a>$ref | `string` | **REQUIRED.** The reference string.++This object cannot be extended with additional properties and any properties added SHALL be ignored.++##### Reference Object Example++<!-- asyncapi-example-tester:{"name":"Reference Object","json_pointer":"/components/messages/userSignUp/payload"} -->+```json+{+  "$ref": "#/components/schemas/Pet"+}+```++<!-- asyncapi-example-tester:{"name":"Reference Object","json_pointer":"/components/messages/userSignUp/payload"} -->+```yaml+  $ref: '#/components/schemas/Pet'+```++#### <a name="componentsObject"></a>Components Object++Holds a set of reusable objects for different aspects of the AsyncAPI specification.+All objects defined within the components object will have no effect on the API unless they are explicitly referenced from properties outside the components object.++##### Fixed Fields++Field Name | Type | Description+---|:---|---+<a name="componentsSchemas"></a> schemas | Map[`string`, [Multi Format Schema Object](#multiFormatSchemaObject) \| [Schema Object](#schemaObject) \| [Reference Object](#referenceObject)] | An object to hold reusable [Schema Object](#schemaObject). If this is a [Schema Object](#schemaObject), then the `schemaFormat` will be assumed to be "application/vnd.aai.asyncapi+json;version=`asyncapi`" where the version is equal to the [AsyncAPI Version String](#A2SVersionString).+<a name="componentsServers"></a> servers | Map[`string`, [Server Object](#serverObject) \| [Reference Object](#referenceObject)] | An object to hold reusable [Server Objects](#serverObject).+<a name="componentsChannels"></a> channels | Map[`string`, [Channel Object](#channelObject) \| [Reference Object](#referenceObject)] | An object to hold reusable [Channel Objects](#channelObject).+<a name="componentsOperations"></a> operations | Map[`string`, [Operation Object](#operationObject) \| [Reference Object](#referenceObject)] | An object to hold reusable [Operation Objects](#operationObject).+<a name="componentsMessages"></a> messages | Map[`string`, [Message Object](#messageObject) \| [Reference Object](#referenceObject)] | An object to hold reusable [Message Objects](#messageObject).+<a name="componentsSecuritySchemes"></a> securitySchemes| Map[`string`, [Security Scheme Object](#securitySchemeObject) \| [Reference Object](#referenceObject)] | An object to hold reusable [Security Scheme Objects](#securitySchemeObject).+<a name="componentsServerVariables"></a> serverVariables | Map[`string`, [Server Variable Object](#serverVariableObject) \| [Reference Object](#referenceObject)] | An object to hold reusable [Server Variable Objects](#serverVariableObject).+<a name="componentsParameters"></a> parameters | Map[`string`, [Parameter Object](#parameterObject) \| [Reference Object](#referenceObject)] | An object to hold reusable [Parameter Objects](#parameterObject).+<a name="componentsCorrelationIDs"></a> correlationIds | Map[`string`, [Correlation ID Object](#correlationIdObject) \| [Reference Object](#referenceObject)] | An object to hold reusable [Correlation ID Objects](#correlationIdObject).+<a name="componentsReplies"></a>replies | Map[`string`, [Operation Reply Object](#operationReplyObject) \| [Reference Object](#referenceObject)] | An object to hold reusable [Operation Reply Objects](#operationReplyObject).+<a name="componentsReplyAddresses"></a> replyAddresses | Map[`string`, [Operation Reply Address Object](#operationReplyAddressObject) &#124; [Reference Object](#referenceObject)] | An object to hold reusable [Operation Reply Address Objects](#operationReplyAddressObject).+<a name="componentsExternalDocs"></a> externalDocs | Map[`string`, [External Documentation Object](#externalDocumentationObject) \| [Reference Object](#referenceObject)] | An object to hold reusable [External Documentation Objects](#externalDocumentationObject).+<a name="componentsTags"></a> tags | Map[`string`, [Tag Object](#tagObject) \| [Reference Object](#referenceObject)] | An object to hold reusable [Tag Objects](#tagObject).+<a name="componentsOperationTraits"></a> operationTraits | Map[`string`, [Operation Trait Object](#operationTraitObject) \| [Reference Object](#referenceObject)]  | An object to hold reusable [Operation Trait Objects](#operationTraitObject).+<a name="componentsMessageTraits"></a> messageTraits | Map[`string`, [Message Trait Object](#messageTraitObject) \| [Reference Object](#referenceObject)]  | An object to hold reusable [Message Trait Objects](#messageTraitObject).+<a name="componentsServerBindings"></a> serverBindings | Map[`string`, [Server Bindings Object](#serverBindingsObject) \| [Reference Object](#referenceObject)]  | An object to hold reusable [Server Bindings Objects](#serverBindingsObject).+<a name="componentsChannelBindings"></a> channelBindings | Map[`string`, [Channel Bindings Object](#channelBindingsObject) \| [Reference Object](#referenceObject)]  | An object to hold reusable [Channel Bindings Objects](#channelBindingsObject).+<a name="componentsOperationBindings"></a> operationBindings | Map[`string`, [Operation Bindings Object](#operationBindingsObject) \| [Reference Object](#referenceObject)]  | An object to hold reusable [Operation Bindings Objects](#operationBindingsObject).+<a name="componentsMessageBindings"></a> messageBindings | Map[`string`, [Message Bindings Object](#messageBindingsObject) \| [Reference Object](#referenceObject)]  | An object to hold reusable [Message Bindings Objects](#messageBindingsObject).++This object MAY be extended with [Specification Extensions](#specificationExtensions).++All the fixed fields declared above are objects that MUST use keys that match the regular expression: `^[a-zA-Z0-9\.\-_]+$`.++Field Name Examples:++```text+User+User_1+User_Name+user-name+my.org.User+```++##### Components Object Example++<!-- asyncapi-example-tester:{"name":"Components Object","json_pointer":""} -->+```json+{+  "components": {+    "schemas": {+      "Category": {+        "type": "object",+        "properties": {+          "id": {+            "type": "integer",+            "format": "int64"+          },+          "name": {+            "type": "string"+          }+        }+      },+      "Tag": {+        "type": "object",+        "properties": {+          "id": {+            "type": "integer",+            "format": "int64"+          },+          "name": {+            "type": "string"+          }+        }+      },+      "AvroExample": {+        "schemaFormat": "application/vnd.apache.avro+json;version=1.9.0",+        "schema": {+          "$ref": "./user-create.avsc"+        }+      }+    },+    "servers": {+      "development": {+        "host": "{stage}.in.mycompany.com:{port}",+        "description": "RabbitMQ broker",+        "protocol": "amqp",+        "protocolVersion": "0-9-1",+        "variables": {+          "stage": {+            "$ref": "#/components/serverVariables/stage"+          },+          "port": {+            "$ref": "#/components/serverVariables/port"+          }+        }+      }+    },+    "serverVariables": {+      "stage": {+        "default": "demo",+        "description": "This value is assigned by the service provider, in this example `mycompany.com`"+      },+      "port": {+        "enum": ["5671", "5672"],+        "default": "5672"+      }+    },+    "channels": {+      "user/signedup": {+        "subscribe": {+          "message": {+            "$ref": "#/components/messages/userSignUp"+          }+        }+      }+    },+    "messages": {+      "userSignUp": {+        "summary": "Action to sign a user up.",+        "description": "Multiline description of what this action does.\nHere you have another line.\n",+        "tags": [+          {+            "name": "user"+          },+          {+            "name": "signup"+          }+        ],+        "headers": {+          "type": "object",+          "properties": {+            "applicationInstanceId": {+              "description": "Unique identifier for a given instance of the publishing application",+              "type": "string"+            }+          }+        },+        "payload": {+          "type": "object",+          "properties": {+            "user": {+              "$ref": "#/components/schemas/userCreate"+            },+            "signup": {+              "$ref": "#/components/schemas/signup"+            }+          }+        }+      }+    },+    "parameters": {+      "userId": {+        "description": "Id of the user."+      }+    },+    "correlationIds": {+      "default": {+        "description": "Default Correlation ID",+        "location": "$message.header#/correlationId"+      }+    },+    "messageTraits": {+      "commonHeaders": {+        "headers": {+          "type": "object",+          "properties": {+            "my-app-header": {+              "type": "integer",+              "minimum": 0,+              "maximum": 100+            }+          }+        }+      }+    }+  }+}+```++<!-- asyncapi-example-tester:{"name":"Components Object","json_pointer":""} -->+```yaml+components:+  schemas:+    Category:+      type: object+      properties:+        id:+          type: integer+          format: int64+        name:+          type: string+    Tag:+      type: object+      properties:+        id:+          type: integer+          format: int64+        name:+          type: string+    AvroExample:+      schemaFormat: 'application/vnd.apache.avro+json;version=1.9.0'+      schema:+        $ref: './user-create.avsc'+  servers:+    development:+      host: '{stage}.in.mycompany.com:{port}'+      description: RabbitMQ broker+      protocol: amqp+      protocolVersion: 0-9-1+      variables:+        stage:+          $ref: '#/components/serverVariables/stage'+        port:+          $ref: '#/components/serverVariables/port'+  serverVariables:+    stage:+      default: demo+      description: |+        This value is assigned by the service provider, in this example+        `mycompany.com`+    port:+      enum:+        - '5671'+        - '5672'+      default: '5672'+  channels:+    user/signedup:+      subscribe:+        message:+          $ref: '#/components/messages/userSignUp'+  messages:+    userSignUp:+      summary: Action to sign a user up.+      description: |+        Multiline description of what this action does.+        Here you have another line.+      tags:+        - name: user+        - name: signup+      headers:+        type: object+        properties:+          applicationInstanceId:+            description: |+              Unique identifier for a given instance of the publishing+              application+            type: string+      payload:+        type: object+        properties:+          user:+            $ref: '#/components/schemas/userCreate'+          signup:+            $ref: '#/components/schemas/signup'+  parameters:+    userId:+      description: Id of the user.+  correlationIds:+    default:+      description: Default Correlation ID+      location: '$message.header#/correlationId'+  messageTraits:+    commonHeaders:+      headers:+        type: object+        properties:+          my-app-header:+            type: integer+            minimum: 0+            maximum: 100+```++#### <a name="multiFormatSchemaObject"></a>Multi Format Schema Object++The Multi Format Schema Object represents a schema definition. It differs from the [Schema Object](#schemaObject) in that it supports multiple schema formats or languages (e.g., JSON Schema, Avro, etc.).++##### Fixed Fields++Field Name | Type | Description+---|:---:|---+<a name="multiFormatSchemaObjectSchemaFormat"></a>schemaFormat | `string` | **Required**. A string containing the name of the schema format that is used to define the information. If `schemaFormat` is missing, it MUST default to `application/vnd.aai.asyncapi+json;version={{asyncapi}}` where `{{asyncapi}}` matches the [AsyncAPI Version String](#A2SVersionString). In such a case, this would make the Multi Format Schema Object equivalent to the [Schema Object](#schemaObject). When using [Reference Object](#referenceObject) within the schema, the `schemaFormat` of the resource being referenced MUST match the `schemaFormat` of the schema that contains the initial reference. For example, if you reference Avro `schema`, then `schemaFormat` of referencing resource and the resource being reference MUST match. <br/><br/>Check out the [supported schema formats table](#multiFormatSchemaFormatTable) for more information. Custom values are allowed but their implementation is OPTIONAL. A custom value MUST NOT refer to one of the schema formats listed in the [table](#multiFormatSchemaFormatTable).<br/><br/>When using [Reference Objects](#referenceObject) within the schema, the `schemaFormat` of the referenced resource MUST match the `schemaFormat` of the schema containing the reference.+<a name="multiFormatSchemaObjectSchema"></a>schema | `any` | **Required**. Definition of the message payload. It can be of any type but defaults to [Schema Object](#schemaObject). It MUST match the schema format defined in [`schemaFormat`](#multiFormatSchemaObjectSchemaFormat), including the encoding type. E.g., Avro should be inlined as either a YAML or JSON object instead of as a string to be parsed as YAML or JSON. Non-JSON-based schemas (e.g., Protobuf or XSD) MUST be inlined as a string.++This object MAY be extended with [Specification Extensions](#specificationExtensions).++##### <a name="multiFormatSchemaFormatTable"></a>Schema formats table++The following table contains a set of values that every implementation MUST support.++Name | Allowed values | Notes+---|:---:|---+[AsyncAPI 3.1.0 Schema Object](#schemaObject) | `application/vnd.aai.asyncapi;version=3.1.0`, `application/vnd.aai.asyncapi+json;version=3.1.0`, `application/vnd.aai.asyncapi+yaml;version=3.1.0` | This is the default when a `schemaFormat` is not provided.+[JSON Schema Draft 07](https://json-schema.org/specification-links.html#draft-7) | `application/schema+json;version=draft-07`, `application/schema+yaml;version=draft-07` |++The following table contains a set of values that every implementation is RECOMMENDED to support.++Name | Allowed values | Notes+---|:---:|---+[Avro 1.9.0 schema](https://avro.apache.org/docs/1.9.0/spec.html#schemas) | `application/vnd.apache.avro;version=1.9.0`, `application/vnd.apache.avro+json;version=1.9.0`, `application/vnd.apache.avro+yaml;version=1.9.0` |+[OpenAPI 3.0.0 Schema Object](https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#schemaObject) | `application/vnd.oai.openapi;version=3.0.0`, `application/vnd.oai.openapi+json;version=3.0.0`, `application/vnd.oai.openapi+yaml;version=3.0.0` |+[RAML 1.0 data type](https://github.com/raml-org/raml-spec/blob/master/versions/raml-10/raml-10.md/) | `application/raml+yaml;version=1.0` |+[Protocol Buffers](https://protobuf.dev/) | `application/vnd.google.protobuf;version=2`, `application/vnd.google.protobuf;version=3` |++##### Multi Format Schema Object Examples++###### Multi Format Schema Object Example with Avro++<!-- asyncapi-example-tester:{"name":"Multi Format Schema Object - Avro","json_pointer":""} -->+```yaml+channels:+  example:+    messages:+      myMessage:+        payload:+          schemaFormat: 'application/vnd.apache.avro;version=1.9.0'+          schema:+            type: record+            name: User+            namespace: com.company+            doc: User information+            fields:+              - name: displayName+                type: string+              - name: age+                type: int+```++#### <a name="schemaObject"></a>Schema Object++The Schema Object allows the definition of input and output data types.+These types can be objects, but also primitives and arrays. This object is a superset of the [JSON Schema Specification Draft 07](https://json-schema.org/). The empty schema (which allows any instance to validate) MAY be represented by the `boolean` value `true` and a schema which allows no instance to validate MAY be represented by the `boolean` value `false`.++Further information about the properties can be found in [JSON Schema Core](https://tools.ietf.org/html/draft-handrews-json-schema-01) and [JSON Schema Validation](https://tools.ietf.org/html/draft-handrews-json-schema-validation-01).+Unless stated otherwise, the property definitions follow the JSON Schema specification as referenced here. For other formats (e.g., Avro, RAML, etc) see [Multi Format Schema Object](#multiFormatSchemaObject).++##### Properties++The AsyncAPI Schema Object is a JSON Schema vocabulary which extends JSON Schema Core and Validation vocabularies. As such, any keyword available for those vocabularies is by definition available in AsyncAPI, and will work the exact same way, including but not limited to:++- title+- type+- required+- multipleOf+- maximum+- exclusiveMaximum+- minimum+- exclusiveMinimum+- maxLength+- minLength+- pattern (This string SHOULD be a valid regular expression, according to the [ECMA 262 regular expression](https://www.ecma-international.org/ecma-262/5.1/#sec-7.8.5) dialect)+- maxItems+- minItems+- uniqueItems+- maxProperties+- minProperties+- enum+- const+- examples+- if / then / else+- readOnly+- writeOnly+- properties+- patternProperties+- additionalProperties+- additionalItems+- items+- propertyNames+- contains+- allOf+- oneOf+- anyOf+- not++The following properties are taken from the JSON Schema definition but their definitions were adjusted to the AsyncAPI Specification.++- description - [CommonMark syntax](https://spec.commonmark.org/) can be used for rich text representation.+- format - See [Data Type Formats](#dataTypeFormat) for further details. While relying on JSON Schema's defined formats, the AsyncAPI Specification offers a few additional predefined formats.+- default - Use it to specify that property has a predefined value if no other value is present. Unlike JSON Schema, the value MUST conform to the defined type for the Schema Object defined at the same level. For example, of `type` is `string`, then `default` can be `"foo"` but cannot be `1`.++Alternatively, any time a Schema Object can be used, a [Reference Object](#referenceObject) can be used in its place. This allows referencing definitions in place of defining them inline. It is appropriate to clarify that the `$ref` keyword MUST follow the behavior described by [Reference Object](#referenceObject) instead of the one in [JSON Schema definition](https://json-schema.org/understanding-json-schema/structuring.html#ref).++In addition to the JSON Schema fields, the following AsyncAPI vocabulary fields MAY be used for further schema documentation:++##### Fixed Fields++Field Name | Type | Description+---|:---:|---+<a name="schemaObjectDiscriminator"></a>discriminator | `string` | Adds support for polymorphism. The discriminator is the schema property name that is used to differentiate between other schema that inherit this schema. The property name used MUST be defined at this schema and it MUST be in the `required` property list. When used, the value MUST be the name of this schema or any schema that inherits it. See [Composition and Inheritance](#schemaComposition) for more details.+<a name="schemaObjectExternalDocs"></a>externalDocs | [External Documentation Object](#externalDocumentationObject) \| [Reference Object](#referenceObject) | Additional external documentation for this schema.+<a name="schemaObjectDeprecated"></a> deprecated | `boolean` | Specifies that a schema is deprecated and SHOULD be transitioned out of usage. Default value is `false`.++This object MAY be extended with [Specification Extensions](#specificationExtensions).++###### <a name="schemaComposition"></a>Composition and Inheritance (Polymorphism)++The AsyncAPI Specification allows combining and extending model definitions using the `allOf` property of JSON Schema, in effect offering model composition.+`allOf` takes in an array of object definitions that are validated _independently_ but together compose a single object.++While composition offers model extensibility, it does not imply a hierarchy between the models.+To support polymorphism, AsyncAPI Specification adds the support of the `discriminator` field.+When used, the `discriminator` will be the name of the property used to decide which schema definition is used to validate the structure of the model.+As such, the `discriminator` field MUST be a required field.+There are two ways to define the value of a discriminator for an inheriting instance.++- Use the schema's name.+- Override the schema's name by overriding the property with a new value. If exists, this takes precedence over the schema's name.++As such, inline schema definitions, which do not have a given id, _cannot_ be used in polymorphism.++##### Schema Object Examples++###### Primitive Sample++<!-- asyncapi-example-tester:{"name":"Schema Object - Primitive","json_pointer":"/components/schemas/Email"} -->+```json+{+  "type": "string",+  "format": "email"+}+```++<!-- asyncapi-example-tester:{"name":"Schema Object - Primitive","json_pointer":"/components/schemas/Email"} -->+```yaml+type: string+format: email+```++###### Simple Model++<!-- asyncapi-example-tester:{"name":"Schema Object - Simple model","json_pointer":"/components/schemas/Person"} -->+```json+{+  "type": "object",+  "required": [+    "name"+  ],+  "properties": {+    "name": {+      "type": "string"+    },+    "address": {+      "$ref": "#/components/schemas/Address"+    },+    "age": {+      "type": "integer",+      "format": "int32",+      "minimum": 0+    }+  }+}+```++<!-- asyncapi-example-tester:{"name":"Schema Object - Simple model","json_pointer":"/components/schemas/Person"} -->+```yaml+type: object+required:+- name+properties:+  name:+    type: string+  address:+    $ref: '#/components/schemas/Address'+  age:+    type: integer+    format: int32+    minimum: 0+```++###### Model with Map/Dictionary Properties++For a simple string to string mapping:++<!-- asyncapi-example-tester:{"name":"Schema Object - Map-Dictionary model","json_pointer":"/components/schemas/Additional"} -->+```json+{+  "type": "object",+  "additionalProperties": {+    "type": "string"+  }+}+```++<!-- asyncapi-example-tester:{"name":"Schema Object - Map-Dictionary model","json_pointer":"/components/schemas/Additional"} -->+```yaml+type: object+additionalProperties:+  type: string+```++For a string to model mapping:++<!-- asyncapi-example-tester:{"name":"Schema Object - Allowing Complex model","json_pointer":"/components/schemas/WithComplex"} -->+```json+{+  "type": "object",+  "additionalProperties": {+    "$ref": "#/components/schemas/ComplexModel"+  }+}+```++<!-- asyncapi-example-tester:{"name":"Schema Object - Allowing Complex model","json_pointer":"/components/schemas/WithComplex"} -->+```yaml+type: object+additionalProperties:+  $ref: '#/components/schemas/ComplexModel'+```++###### Model with Example++<!-- asyncapi-example-tester:{"name":"Schema Object - With examples model","json_pointer":"/components/schemas/WithExamples"} -->+```json+{+  "type": "object",+  "properties": {+    "id": {+      "type": "integer",+      "format": "int64"+    },+    "name": {+      "type": "string"+    }+  },+  "required": [+    "name"+  ],+  "examples": [+    {+      "name": "Puma",+      "id": 1+    }+  ]+}+```++<!-- asyncapi-example-tester:{"name":"Schema Object - With examples model","json_pointer":"/components/schemas/WithExamples"} -->+```yaml+type: object+properties:+  id:+    type: integer+    format: int64+  name:+    type: string+required:+- name+examples:+- name: Puma+  id: 1+```++###### Model with Boolean Schemas++<!-- asyncapi-example-tester:{"name":"Schema Object - With boolean model","json_pointer":"/components/schemas/WithBoolean"} -->+```json+{+  "type": "object",+  "required": [+    "anySchema"+  ],+  "properties": {+    "anySchema": true,+    "cannotBeDefined": false+  }+}+```++<!-- asyncapi-example-tester:{"name":"Schema Object - With boolean model","json_pointer":"/components/schemas/WithBoolean"} -->+```yaml+type: object+required:+- anySchema+properties:+  anySchema: true+  cannotBeDefined: false+```++###### Models with Composition++<!-- asyncapi-example-tester:{"name":"Schema Object - With composition model","json_pointer":"/components/schemas/WithComposition"} -->+```json+{+  "schemas": {+    "ErrorModel": {+      "type": "object",+      "required": [+        "message",+        "code"+      ],+      "properties": {+        "message": {+          "type": "string"+        },+        "code": {+          "type": "integer",+          "minimum": 100,+          "maximum": 600+        }+      }+    },+    "ExtendedErrorModel": {+      "allOf": [+        {+          "$ref": "#/components/schemas/ErrorModel"+        },+        {+          "type": "object",+          "required": [+            "rootCause"+          ],+          "properties": {+            "rootCause": {+              "type": "string"+            }+          }+        }+      ]+    }+  }+}+```++<!-- asyncapi-example-tester:{"name":"Schema Object - With composition model","json_pointer":"/components/schemas/WithComposition"} -->+```yaml+schemas:+  ErrorModel:+    type: object+    required:+    - message+    - code+    properties:+      message:+        type: string+      code:+        type: integer+        minimum: 100+        maximum: 600+  ExtendedErrorModel:+    allOf:+    - $ref: '#/components/schemas/ErrorModel'+    - type: object+      required:+      - rootCause+      properties:+        rootCause:+          type: string+```++###### Models with Polymorphism Support++<!-- asyncapi-example-tester:{"name":"Schema Object - With polymorphism model","json_pointer":"/components/schemas/WithPolymorphism"} -->+```json+{+  "schemas": {+    "Pet": {+      "type": "object",+      "discriminator": "petType",+      "properties": {+        "name": {+          "type": "string"+        },+        "petType": {+          "type": "string"+        }+      },+      "required": [+        "name",+        "petType"+      ]+    },+    "Cat": {+      "description": "A representation of a cat. Note that `Cat` will be used as the discriminator value.",+      "allOf": [+        {+          "$ref": "#/components/schemas/Pet"+        },+        {+          "type": "object",+          "properties": {+            "huntingSkill": {+              "type": "string",+              "description": "The measured skill for hunting",+              "enum": [+                "clueless",+                "lazy",+                "adventurous",+                "aggressive"+              ]+            }+          },+          "required": [+            "huntingSkill"+          ]+        }+      ]+    },+    "Dog": {+      "description": "A representation of a dog. Note that `Dog` will be used as the discriminator value.",+      "allOf": [+        {+          "$ref": "#/components/schemas/Pet"+        },+        {+          "type": "object",+          "properties": {+            "packSize": {+              "type": "integer",+              "format": "int32",+              "description": "the size of the pack the dog is from",+              "minimum": 0+            }+          },+          "required": [+            "packSize"+          ]+        }+      ]+    },+    "StickInsect": {+      "description": "A representation of an Australian walking stick. Note that `StickBug` will be used as the discriminator value.",+      "allOf": [+        {+          "$ref": "#/components/schemas/Pet"+        },+        {+          "type": "object",+          "properties": {+            "petType": {+              "const": "StickBug"+            },+            "color": {+              "type": "string"+            }+          },+          "required": [+            "color"+          ]+        }+      ]+    }+  }+}+```++<!-- asyncapi-example-tester:{"name":"Schema Object - With polymorphism model","json_pointer":"/components/schemas/WithPolymorphism"} -->+```yaml+schemas:+  Pet:+    type: object+    discriminator: petType+    properties:+      name:+        type: string+      petType:+        type: string+    required:+    - name+    - petType+  ## applies to instances with `petType: "Cat"`+  ## because that is the schema name+  Cat:+    description: A representation of a cat+    allOf:+    - $ref: '#/components/schemas/Pet'+    - type: object+      properties:+        huntingSkill:+          type: string+          description: The measured skill for hunting+          enum:+          - clueless+          - lazy+          - adventurous+          - aggressive+      required:+      - huntingSkill+  ## applies to instances with `petType: "Dog"`+  ## because that is the schema name+  Dog:+    description: A representation of a dog+    allOf:+    - $ref: '#/components/schemas/Pet'+    - type: object+      properties:+        packSize:+          type: integer+          format: int32+          description: the size of the pack the dog is from+          minimum: 0+      required:+      - packSize+  ## applies to instances with `petType: "StickBug"`+  ## because that is the required value of the discriminator field,+  ## overriding the schema name+  StickInsect:+    description: A representation of an Australian walking stick+    allOf:+    - $ref: '#/components/schemas/Pet'+    - type: object+      properties:+        petType:+          const: StickBug+        color:+          type: string+      required:+      - color+```++#### <a name="securitySchemeObject"></a>Security Scheme Object++Defines a security scheme that can be used by the operations. Supported schemes are:++- User/Password.+- API key (either as user or as password).+- X.509 certificate.+- End-to-end encryption (either symmetric or asymmetric).+- HTTP authentication.+- HTTP API key.+- OAuth2's common flows (Implicit, Resource Owner Protected Credentials, Client Credentials and Authorization Code) as defined in [RFC6749](https://tools.ietf.org/html/rfc6749).+- [OpenID Connect Discovery](https://tools.ietf.org/html/draft-ietf-oauth-discovery-06).+- SASL (Simple Authentication and Security Layer) as defined in [RFC4422](https://tools.ietf.org/html/rfc4422).++##### Fixed Fields++Field Name | Type | Applies To | Description+---|:---:|---|---+<a name="securitySchemeObjectType"></a>type | `string` | Any | **REQUIRED**. The type of the security scheme. Valid values are `"userPassword"`, `"apiKey"`, `"X509"`, `"symmetricEncryption"`, `"asymmetricEncryption"`, `"httpApiKey"`, `"http"`, `"oauth2"`, `"openIdConnect"`, `"plain"`, `"scramSha256"`, `"scramSha512"`, and `"gssapi"`.+<a name="securitySchemeObjectDescription"></a>description | `string` | Any | A short description for security scheme. [CommonMark syntax](https://spec.commonmark.org/) MAY be used for rich text representation.+<a name="securitySchemeObjectName"></a>name | `string` | `httpApiKey` | **REQUIRED**. The name of the header, query or cookie parameter to be used.+<a name="securitySchemeObjectIn"></a>in | `string` | `apiKey` \| `httpApiKey` | **REQUIRED**. The location of the API key. Valid values are `"user"` and `"password"` for `apiKey` and `"query"`, `"header"` or `"cookie"` for `httpApiKey`.+<a name="securitySchemeObjectScheme"></a>scheme | `string` | `http` | **REQUIRED**. The name of the HTTP Authorization scheme to be used in the [Authorization header as defined in RFC7235](https://tools.ietf.org/html/rfc7235#section-5.1).+<a name="securitySchemeObjectBearerFormat"></a>bearerFormat | `string` | `http` (`"bearer"`) | A hint to the client to identify how the bearer token is formatted.  Bearer tokens are usually generated by an authorization server, so this information is primarily for documentation purposes.+<a name="securitySchemeFlows"></a>flows | [OAuth Flows Object](#oauthFlowsObject) | `oauth2` | **REQUIRED**. An object containing configuration information for the flow types supported.+<a name="securitySchemeOpenIdConnectUrl"></a>openIdConnectUrl | `string` | `openIdConnect` | **REQUIRED**. OpenId Connect URL to discover OAuth2 configuration values. This MUST be in the form of an absolute URL.+<a name="securitySchemeScopes"></a>scopes | [`string`] | `oauth2` \| `openIdConnect` | List of the needed scope names. An empty array means no scopes are needed.++This object MAY be extended with [Specification Extensions](#specificationExtensions).++##### Security Scheme Object Example++###### User/Password Authentication Sample++<!-- asyncapi-example-tester:{"name":"Security Scheme Object - user-pass","json_pointer":"/components/securitySchemes/userPasswordAuth"} -->+```json+{+  "type": "userPassword"+}+```++<!-- asyncapi-example-tester:{"name":"Security Scheme Object - user-pass","json_pointer":"/components/securitySchemes/userPasswordAuth"} -->+```yaml+type: userPassword+```++###### API Key Authentication Sample++<!-- asyncapi-example-tester:{"name":"Security Scheme Object - API key auth","json_pointer":"/components/securitySchemes/apiKeyAuth"} -->+```json+{+  "type": "apiKey",+  "in": "user"+}+```++<!-- asyncapi-example-tester:{"name":"Security Scheme Object - API key auth","json_pointer":"/components/securitySchemes/apiKeyAuth"} -->+```yaml+type: apiKey+in: user+```++###### X.509 Authentication Sample++<!-- asyncapi-example-tester:{"name":"Security Scheme Object - X.509","json_pointer":"/components/securitySchemes/X509Auth"} -->+```json+{+  "type": "X509"+}+```++<!-- asyncapi-example-tester:{"name":"Security Scheme Object - X.509","json_pointer":"/components/securitySchemes/X509Auth"} -->+```yaml+type: X509+```++###### End-to-end Encryption Authentication Sample++<!-- asyncapi-example-tester:{"name":"Security Scheme Object - end to end encryption","json_pointer":"/components/securitySchemes/symmetricEncryptionAuth"} -->+```json+{+  "type": "symmetricEncryption"+}+```++<!-- asyncapi-example-tester:{"name":"Security Scheme Object - end to end encryption","json_pointer":"/components/securitySchemes/symmetricEncryptionAuth"} -->+```yaml+type: symmetricEncryption+```++###### Basic Authentication Sample++<!-- asyncapi-example-tester:{"name":"Security Scheme Object - basic","json_pointer":"/components/securitySchemes/basicAuth"} -->+```json+{+  "type": "http",+  "scheme": "basic"+}+```++<!-- asyncapi-example-tester:{"name":"Security Scheme Object - basic","json_pointer":"/components/securitySchemes/basicAuth"} -->+```yaml+type: http+scheme: basic+```++###### API Key Sample++<!-- asyncapi-example-tester:{"name":"Security Scheme Object - API key","json_pointer":"/components/securitySchemes/httpApiAuth"} -->+```json+{+  "type": "httpApiKey",+  "name": "api_key",+  "in": "header"+}+```++<!-- asyncapi-example-tester:{"name":"Security Scheme Object - API key","json_pointer":"/components/securitySchemes/httpApiAuth"} -->+```yaml+type: httpApiKey+name: api_key+in: header+```++###### JWT Bearer Sample++<!-- asyncapi-example-tester:{"name":"Security Scheme Object - JWT","json_pointer":"/components/securitySchemes/JWTAuth"} -->+```json+{+  "type": "http",+  "scheme": "bearer",+  "bearerFormat": "JWT"+}+```++<!-- asyncapi-example-tester:{"name":"Security Scheme Object - JWT","json_pointer":"/components/securitySchemes/JWTAuth"} -->+```yaml+type: http+scheme: bearer+bearerFormat: JWT+```++###### Implicit OAuth2 Sample++<!-- asyncapi-example-tester:{"name":"Security Scheme Object - implicity OAuth2","json_pointer":"/components/securitySchemes/oauth"} -->+```json+{+  "type": "oauth2",+  "flows": {+    "implicit": {+      "authorizationUrl": "https://example.com/api/oauth/dialog",+      "availableScopes": {+        "write:pets": "modify pets in your account",+        "read:pets": "read your pets"+      }+    }+  },+  "scopes": [+    "write:pets"+  ]+}+```++<!-- asyncapi-example-tester:{"name":"Security Scheme Object - implicity OAuth2","json_pointer":"/components/securitySchemes/oauth"} -->+```yaml+type: oauth2+flows:+  implicit:+    authorizationUrl: https://example.com/api/oauth/dialog+    availableScopes:+      write:pets: modify pets in your account+      read:pets: read your pets+scopes:+  - 'write:pets'+```++###### SASL Sample++<!-- asyncapi-example-tester:{"name":"Security Scheme Object - SASL","json_pointer":"/components/securitySchemes/saslAuth"} -->+```json+{+  "type": "scramSha512"+}+```++<!-- asyncapi-example-tester:{"name":"Security Scheme Object - SASL","json_pointer":"/components/securitySchemes/saslAuth"} -->+```yaml+type: scramSha512+```++#### <a name="oauthFlowsObject"></a>OAuth Flows Object++Allows configuration of the supported OAuth Flows.++##### Fixed Fields++Field Name | Type | Description+---|:---:|---+<a name="oauthFlowsImplicit"></a>implicit| [OAuth Flow Object](#oauthFlowObject) | Configuration for the OAuth Implicit flow.+<a name="oauthFlowsPassword"></a>password| [OAuth Flow Object](#oauthFlowObject) | Configuration for the OAuth Resource Owner Protected Credentials flow.+<a name="oauthFlowsClientCredentials"></a>clientCredentials| [OAuth Flow Object](#oauthFlowObject) | Configuration for the OAuth Client Credentials flow.+<a name="oauthFlowsAuthorizationCode"></a>authorizationCode| [OAuth Flow Object](#oauthFlowObject) | Configuration for the OAuth Authorization Code flow.++This object MAY be extended with [Specification Extensions](#specificationExtensions).++#### <a name="oauthFlowObject"></a>OAuth Flow Object++Configuration details for a supported OAuth Flow++##### Fixed Fields++Field Name | Type | Applies To | Description+---|:---:|---|---+<a name="oauthFlowAuthorizationUrl"></a>authorizationUrl | `string` | `oauth2` (`"implicit"`, `"authorizationCode"`) | **REQUIRED**. The authorization URL to be used for this flow. This MUST be in the form of an absolute URL.+<a name="oauthFlowTokenUrl"></a>tokenUrl | `string` | `oauth2` (`"password"`, `"clientCredentials"`, `"authorizationCode"`) | **REQUIRED**. The token URL to be used for this flow. This MUST be in the form of an absolute URL.+<a name="oauthFlowRefreshUrl"></a>refreshUrl | `string` | `oauth2` | The URL to be used for obtaining refresh tokens. This MUST be in the form of an absolute URL.+<a name="oauthFlowScopes"></a>availableScopes | Map[`string`, `string`] | `oauth2` | **REQUIRED**. The available scopes for the OAuth2 security scheme. A map between the scope name and a short description for it.++This object MAY be extended with [Specification Extensions](#specificationExtensions).++##### OAuth Flow Object Examples++###### clientCredentials Oauth Flow Object Example++<!-- asyncapi-example-tester:{"name":"Security Scheme OAuth Flow Object","json_pointer":"/components/securitySchemes/oauth/flows/clientCredentials"} -->+```json+{+  "tokenUrl": "https://example.com/api/oauth/token",+  "availableScopes": {+    "write:pets": "modify pets in your account",+    "read:pets": "read your pets"+  }+}+```+<!-- asyncapi-example-tester:{"name":"Security Scheme OAuth Flow Object","json_pointer":"/components/securitySchemes/oauth/flows/clientCredentials"} -->+```yaml+tokenUrl: https://example.com/api/oauth/token+availableScopes:+  write:pets: modify pets in your account+  read:pets: read your pets+```++### <a name="correlationIdObject"></a>Correlation ID Object++An object that specifies an identifier at design time that can used for message tracing and correlation.++For specifying and computing the location of a Correlation ID, a [runtime expression](#runtimeExpression) is used.++#### Fixed Fields++Field Name | Type | Description+---|:---|---+description | `string` | An optional description of the identifier. [CommonMark syntax](https://spec.commonmark.org/) can be used for rich text representation.+location | `string` | **REQUIRED.** A [runtime expression](#runtimeExpression) that specifies the location of the correlation ID.++This object MAY be extended with [Specification Extensions](#specificationExtensions).++##### Examples++<!-- asyncapi-example-tester:{"name":"Message Correlation ID Object","json_pointer":"/components/correlationIds/default"} -->+```json+{+  "description": "Default Correlation ID",+  "location": "$message.header#/correlationId"+}+```++<!-- asyncapi-example-tester:{"name":"Message Correlation ID Object","json_pointer":"/components/correlationIds/default"} -->+```yaml+description: Default Correlation ID+location: $message.header#/correlationId+```++### <a name="runtimeExpression"></a>Runtime Expression++A runtime expression allows values to be defined based on information that will be available within the message.+This mechanism is used by [Correlation ID Object](#correlationIdObject) and [Operation Reply Address Object](#operationReplyAddressObject).++The runtime expression is defined by the following [ABNF](https://tools.ietf.org/html/rfc5234) syntax:++```text+      expression = ( "$message" "." source )+      source = ( header-reference | payload-reference )+      header-reference = "header" ["#" fragment]+      payload-reference = "payload" ["#" fragment]+      fragment = a JSON Pointer [RFC 6901](https://tools.ietf.org/html/rfc6901)+```++The table below provides examples of runtime expressions and examples of their use in a value:++#### <a name="runtimeExpressionExamples"></a>Examples++Source Location | Example expression  | Notes+---|:---|:---|+Message Header Property | `$message.header#/MQMD/CorrelId` | Correlation ID is set using the `CorrelId` value from the `MQMD` header.+Message Payload Property | `$message.payload#/messageId` | Correlation ID is set using the `messageId` value from the message payload.++Runtime expressions preserve the type of the referenced value.++### <a name="traitsMergeMechanism"></a>Traits Merge Mechanism++Traits MUST be merged with the target object using the [JSON Merge Patch](https://tools.ietf.org/html/rfc7386) algorithm in the same order they are defined. A property on a trait MUST NOT override the same property on the target object.++#### Example++An object like the following:++```yaml+description: A longer description.+traits:+  - name: UserSignup+    description: Description from trait.+  - tags:+      - name: user+```++Would look like the following after applying traits:++```yaml+name: UserSignup+description: A longer description.+tags:+  - name: user+```++### <a name="specificationExtensions"></a>Specification Extensions++While the AsyncAPI Specification tries to accommodate most use cases, additional data can be added to extend the specification at certain points.++The extensions properties are implemented as patterned fields that are always prefixed by `"x-"`.++Field Pattern | Type | Description+---|:---:|---+<a name="infoExtensions"></a>`^x-[\w\d\.\x2d_]+$` | Any | Allows extensions to the AsyncAPI Schema. The field name MUST begin with `x-`, for example, `x-internal-id`. The value can be `null`, a primitive, an array or an object. Can have any valid JSON format value.++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).++### <a name="dataTypeFormat"></a>Data Type Formats++Primitives have an optional modifier property: `format`.+The AsyncAPI specification uses several known formats to more finely define the data type being used.+However, the `format` property is an open `string`-valued property, and can have any value to support documentation needs.+Formats such as `"email"`, `"uuid"`, etc., can be used even though they are not defined by this specification.+Types that are not accompanied by a `format` property follow their definition from the JSON Schema.+Tools that do not recognize a specific `format` MAY default back to the `type` alone, as if the `format` was not specified.++The formats defined by the AsyncAPI Specification are:++Common Name | `type` | [`format`](#dataTypeFormat) | Comments+----------- | ------ | -------- | --------+integer | `integer` | `int32` | signed 32 bits+long | `integer` | `int64` | signed 64 bits+float | `number` | `float` | |+double | `number` | `double` | |+string | `string` | | |+byte | `string` | `byte` | base64 encoded characters+binary | `string` | `binary` | any sequence of octets+boolean | `boolean` | | |+date | `string` | `date` | As defined by `full-date` - [RFC3339](https://www.rfc-editor.org/rfc/rfc3339.html#section-5.6)+dateTime | `string` | `date-time` | As defined by `date-time` - [RFC3339](https://www.rfc-editor.org/rfc/rfc3339.html#section-5.6)+password | `string` | `password` | Used to hint UIs the input needs to be obscured.
+ reference/base-doc.json view
@@ -0,0 +1,726 @@+{+  "asyncapi": "3.1.0",+  "info": {+    "title": "AsyncAPI",+    "version": "1.x.x",+    "description": "This is a very good base doc, probably.",+    "termsOfService": "https://asyncapi.org/terms/",+    "license": {+      "name": "Apache 2.0",+      "url": "https://www.apache.org/licenses/LICENSE-2.0.html"+    },+    "externalDocs": {+      "description": "Find more info here",+      "url": "https://www.asyncapi.org"+    },+    "tags": [+      {+        "name": "e-commerce"+      }+    ]+  },+  "servers": {+    "production": {+      "host": "rabbitmq.in.mycompany.com:5672",+      "pathname": "/v1",+      "protocol": "amqp",+      "protocolVersion": "1.0",+      "description": "Production RabbitMQ broker (uses the `production` vhost).",+      "title": "Production Server",+      "summary": "Production environment server",+      "security": [+        {+          "type": "http",+          "scheme": "bearer"+        }+      ],+      "tags": [+        {+          "name": "production",+          "description": "Production environment"+        }+      ],+      "externalDocs": {+        "description": "Additional documentation for the production server",+        "url": "https://example.com/docs/production"+      },+      "bindings": {+        "amqp": {+          "exchange": "my-exchange",+          "queue": "my-queue"+        }+      }+    },+    "staging": {+      "host": "rabbitmq.in.mycompany.com:5672",+      "pathname": "/v1",+      "protocol": "amqp",+      "protocolVersion": "1.0",+      "description": "Staging RabbitMQ broker (uses the `staging` vhost).",+      "title": "Staging Server",+      "summary": "Staging environment server",+      "security": [+        {+          "type": "apiKey",+          "in": "user",+          "description": "Provide your API key as the user and leave the password empty."+        }+      ],+      "tags": [+        {+          "name": "staging",+          "description": "Staging environment"+        }+      ],+      "externalDocs": {+        "description": "Additional documentation for the staging server",+        "url": "https://example.com/docs/staging"+      },+      "bindings": {+        "amqp": {+          "exchange": "my-exchange",+          "queue": "my-queue"+        }+      }+    },+    "rabbitmqInProd": {+      "host": "{prod}.in.mycompany.com",+      "protocol": "amqp",+      "description": "Production server"+    },+    "rabbitmqInStaging": {+      "host": "{stage}.in.mycompany.com",+      "protocol": "amqp",+      "description": "Staging server"+    }+  },+  "channels": {+    "user": {+      "address": "users.{userId}",+      "title": "Users channel",+      "description": "This channel is used to exchange messages about user events.",+      "messages": {+        "userSignedUp": {+          "$ref": "#/components/messages/userSignedUp"+        },+        "userCompletedOrder": {+          "$ref": "#/components/messages/userCompletedOrder"+        }+      },+      "parameters": {+        "userId": {+          "$ref": "#/components/parameters/userId"+        }+      },+      "servers": [+        {+          "$ref": "#/servers/production"+        }+      ],+      "bindings": {+        "amqp": {+          "is": "queue",+          "queue": {+            "exclusive": true+          }+        }+      },+      "tags": [+        {+          "name": "user",+          "description": "User-related messages"+        }+      ],+      "externalDocs": {+        "description": "Find more info here",+        "url": "https://example.com"+      }+    },+    "userSignup": {+      "address": "users.signup",+      "description": "Channel for user signups",+      "messages": {+        "userSignedUp": {+          "$ref": "#/components/messages/userSignedUp"+        }+      }+    },+    "userSignupReply": {+      "address": "users.signup.reply",+      "description": "Channel for user signup replies",+      "messages": {+        "userSignedUpReply": {+          "summary": "User signup reply message",+          "payload": {+            "type": "object",+            "properties": {+              "status": {+                "type": "string",+                "description": "Status of the signup process"+              },+              "message": {+                "type": "string",+                "description": "Additional information"+              }+            }+          }+        }+      }+    }+  },+  "operations": {+    "sendUserSignUp": {+      "action": "send",+      "title": "User sign up",+      "summary": "Action to sign a user up.",+      "description": "A longer description",+      "channel": {+        "$ref": "#/channels/user"+      },+      "security": [+        {+          "type": "oauth2",+          "description": "The oauth security descriptions",+          "flows": {+            "clientCredentials": {+              "tokenUrl": "https://example.com/api/oauth/dialog",+              "availableScopes": {+                "subscribe:auth_revocations": "Scope required for authorization revocation topic"+              }+            }+          },+          "scopes": [+            "subscribe:auth_revocations"+          ]+        }+      ],+      "tags": [+        {+          "name": "user"+        },+        {+          "name": "signup"+        },+        {+          "name": "register"+        }+      ],+      "bindings": {+        "amqp": {+          "ack": false+        }+      },+      "messages": [+        {+          "$ref": "#/channels/user/messages/userSignedUp"+        }+      ],+      "reply": {+        "address": {+          "location": "$message.header#/replyTo"+        },+        "channel": {+          "$ref": "#/channels/userSignupReply"+        },+        "messages": [+          {+            "$ref": "#/channels/userSignupReply/messages/userSignedUpReply"+          }+        ]+      },+      "traits": []+    }+  },+  "components": {+    "schemas": {+      "Category": {+        "type": "object",+        "properties": {+          "id": {+            "type": "integer",+            "format": "int64"+          }+        }+      },+      "AvroExample": {+        "schemaFormat": "application/vnd.apache.avro+json;version=1.9.0",+        "schema": {+          "type": "record",+          "name": "UserCreate",+          "namespace": "com.example",+          "fields": [+            {+              "name": "id",+              "type": "int"+            },+            {+              "name": "name",+              "type": "string"+            }+          ]+        }+      },+      "userCreate": {+        "type": "object",+        "properties": {+          "id": {+            "type": "string",+            "description": "The ID of the user"+          },+          "name": {+            "type": "string",+            "description": "The name of the user"+          },+          "email": {+            "type": "string",+            "format": "email",+            "description": "The email of the user"+          }+        },+        "required": [+          "id",+          "name",+          "email"+        ]+      },+      "signup": {+        "type": "object",+        "properties": {+          "timestamp": {+            "type": "string",+            "format": "date-time",+            "description": "The timestamp of the signup"+          },+          "source": {+            "type": "string",+            "description": "The source of the signup"+          }+        },+        "required": [+          "timestamp",+          "source"+        ]+      },+      "ComplexModel": {+        "type": "object",+        "properties": {+          "id": {+            "type": "integer",+            "format": "int64"+          },+          "name": {+            "type": "string"+          }+        }+      },+      "Address": {+        "type": "object",+        "properties": {+          "street": {+            "type": "string"+          },+          "city": {+            "type": "string"+          },+          "state": {+            "type": "string"+          },+          "zip": {+            "type": "string"+          }+        }+      },+      "ErrorModel": {+        "type": "object",+        "properties": {+          "code": {+            "type": "integer",+            "format": "int32"+          },+          "message": {+            "type": "string"+          }+        }+      },+      "Pet": {+        "type": "object",+        "properties": {+          "id": {+            "type": "integer",+            "format": "int64"+          },+          "name": {+            "type": "string"+          },+          "tag": {+            "type": "string"+          }+        }+      }+    },+    "servers": {+      "development": {+        "host": "{stage}.in.mycompany.com",+        "protocol": "amqp",+        "description": "RabbitMQ broker",+        "bindings": {+          "$ref": "#/components/serverBindings/devAmqp"+        },+        "variables": {+          "stage": {+            "$ref": "#/components/serverVariables/stage"+          }+        },+        "security": [+          {+            "$ref": "#/components/securitySchemes/oauth"+          }+        ]+      }+    },+    "serverVariables": {+      "stage": {+        "default": "demo",+        "description": "This value is assigned by the service provider in this example of `mycompany.com`"+      }+    },+    "channels": {+      "user": {+        "address": "users.{userId}",+        "title": "Users channel",+        "description": "This channel is used to exchange messages about user events.",+        "messages": {+          "userSignedUp": {+            "$ref": "#/components/messages/userSignUp"+          }+        },+        "parameters": {+          "userId": {+            "$ref": "#/components/parameters/userId"+          }+        },+        "servers": [+          {+            "$ref": "#/components/servers/development"+          }+        ],+        "bindings": {+          "$ref": "#/components/channelBindings/user"+        },+        "tags": [+          {+            "$ref": "#/components/tags/user"+          }+        ],+        "externalDocs": {+          "$ref": "#/components/externalDocs/infoDocs"+        }+      }+    },+    "messages": {+      "userSignUp": {+        "summary": "Action to sign a user up.",+        "traits": [+          {+            "$ref": "#/components/messageTraits/commonHeaders"+          }+        ],+        "payload": {+          "$ref": "#/components/schemas/Category"+        },+        "correlationId": {+          "$ref": "#/components/correlationIds/default"+        },+        "bindings": {+          "$ref": "#/components/messageBindings/user"+        },+        "examples": []+      },+      "userSignedUp": {+        "name": "UserSignup",+        "title": "User signup",+        "summary": "Action to sign a user up.",+        "description": "A longer description",+        "contentType": "application/json",+        "tags": [+          {+            "name": "user"+          },+          {+            "name": "signup"+          },+          {+            "name": "register"+          }+        ],+        "headers": {+          "type": "object",+          "properties": {+            "correlationId": {+              "description": "Correlation ID set by application",+              "type": "string"+            },+            "applicationInstanceId": {+              "description": "Unique identifier for a given instance of the publishing application",+              "type": "string"+            }+          }+        },+        "payload": {+          "type": "object",+          "properties": {+            "user": {+              "$ref": "#/components/schemas/userCreate"+            },+            "signup": {+              "$ref": "#/components/schemas/signup"+            }+          }+        },+        "correlationId": {+          "description": "Default Correlation ID",+          "location": "$message.header#/correlationId"+        },+        "traits": [+          {+            "$ref": "#/components/messageTraits/commonHeaders"+          }+        ],+        "examples": [+          {+            "name": "SimpleSignup",+            "summary": "A simple UserSignup example message",+            "headers": {+              "correlationId": "my-correlation-id",+              "applicationInstanceId": "myInstanceId"+            },+            "payload": {+              "user": {+                "someUserKey": "someUserValue"+              },+              "signup": {+                "someSignupKey": "someSignupValue"+              }+            }+          }+        ]+      },+      "userSignedUpReply": {+        "name": "UserSignupReply",+        "title": "User signup reply",+        "summary": "User signup reply message",+        "contentType": "application/json",+        "payload": {+          "type": "object",+          "properties": {+            "status": {+              "type": "string",+              "description": "Status of the signup process"+            },+            "message": {+              "type": "string",+              "description": "Additional information"+            }+          }+        }+      },+      "userCompletedOrder": {+        "summary": "User completed order event",+        "contentType": "application/json",+        "payload": {+          "type": "object",+          "properties": {+            "orderId": {+              "type": "string",+              "description": "The ID of the order"+            },+            "userId": {+              "type": "string",+              "description": "The ID of the user"+            },+            "amount": {+              "type": "number",+              "description": "The total amount of the order"+            }+          }+        }+      }+    },+    "parameters": {+      "userId": {+        "description": "Id of the user."+      }+    },+    "correlationIds": {+      "default": {+        "description": "Default Correlation ID",+        "location": "$message.header#/correlationId"+      }+    },+    "operations": {+      "sendUserSignUp": {+        "action": "send",+        "title": "User sign up",+        "channel": {+          "$ref": "#/channels/user"+        },+        "bindings": {+          "$ref": "#/components/operationBindings/sendUser"+        },+        "traits": [+          {+            "$ref": "#/components/operationTraits/binding"+          }+        ],+        "reply": {+          "$ref": "#/components/replies/signupReply"+        }+      }+    },+    "replies": {+      "signupReply": {+        "address": {+          "$ref": "#/components/replyAddresses/signupReply"+        },+        "channel": {+          "$ref": "#/channels/userSignupReply"+        }+      }+    },+    "replyAddresses": {+      "signupReply": {+        "location": "$message.header#/replyTo"+      }+    },+    "securitySchemes": {+      "userPasswordAuth": {+        "type": "userPassword",+        "description": "User password security scheme"+      },+      "apiKeyAuth": {+        "type": "apiKey",+        "description": "API key security scheme",+        "in": "user"+      },+      "X509Auth": {+        "type": "X509",+        "description": "X509 security scheme"+      },+      "symmetricEncryptionAuth": {+        "type": "symmetricEncryption",+        "description": "Symmetric encryption security scheme"+      },+      "basicAuth": {+        "type": "http",+        "description": "Basic security scheme",+        "scheme": "basic"+      },+      "httpApiAuth": {+        "type": "httpApiKey",+        "name": "API Key Sample",+        "description": "api_key",+        "in": "header"+      },+      "JWTAuth": {+        "type": "http",+        "scheme": "bearer",+        "bearerFormat": "JWT"+      },+      "saslAuth": {+        "type": "scramSha256",+        "description": "SASL security scheme"+      },+      "oauth": {+        "type": "oauth2",+        "description": "The oauth security descriptions",+        "flows": {+          "clientCredentials": {+            "tokenUrl": "https://example.com/api/oauth/dialog",+            "availableScopes": {+              "subscribe:auth_revocations": "Scope required for authorization revocation topic"+            }+          }+        },+        "scopes": [+          "subscribe:auth_revocations"+        ]+      }+    },+    "operationTraits": {+      "binding": {+        "bindings": {+          "amqp": {+            "ack": false+          }+        }+      },+      "kafka": {+        "bindings": {+          "kafka": {+            "groupId": false+          }+        }+      }+    },+    "messageTraits": {+      "commonHeaders": {+        "headers": {+          "type": "object",+          "properties": {+            "my-app-header": {+              "type": "integer",+              "minimum": 0,+              "maximum": 100+            }+          }+        }+      }+    },+    "tags": {+      "user": {+        "name": "user",+        "description": "User-related messages"+      }+    },+    "externalDocs": {+      "infoDocs": {+        "url": "https://example.com/docs",+        "description": "Find more info here"+      }+    },+    "serverBindings": {+      "devAmqp": {+        "amqp": {+          "exchange": "my-exchange",+          "queue": "my-queue"+        }+      }+    },+    "channelBindings": {+      "user": {+        "amqp": {+          "is": "queue",+          "queue": {+            "exclusive": true+          }+        }+      }+    },+    "operationBindings": {+      "sendUser": {+        "amqp": {+          "ack": false+        }+      }+    },+    "messageBindings": {+      "user": {+        "amqp": {+          "contentEncoding": "gzip",+          "messageType": "user.signup",+          "bindingVersion": "0.3.0"+        }+      }+    }+  }+}
+ reference/examples/adeo-kafka-request-reply-asyncapi.yml view
@@ -0,0 +1,298 @@+asyncapi: 3.1.0+info:+  title: Adeo AsyncAPI Case Study+  version: '%REPLACED_BY_MAVEN%'+  description: >+    This Adeo specification illustrates how ADEO uses AsyncAPI to document some+    of their exchanges.+  contact:+    name: AsyncAPI Community+    email: case-study@asyncapi.com+  tags:+    - name: costing+      description: Costing channels, used by Costing clients.+servers:+  production:+    host: prod.url:9092+    protocol: kafka+    description: Kafka PRODUCTION cluster+    security:+      - $ref: '#/components/securitySchemes/sasl-ssl'+    bindings:+      kafka:+        schemaRegistryUrl: https://schema-registry.prod.url/+  staging:+    host: staging.url:9092+    protocol: kafka+    description: Kafka STAGING cluster for `uat` and `preprod` environments+    security:+      - $ref: '#/components/securitySchemes/sasl-ssl'+    bindings:+      kafka:+        schemaRegistryUrl: https://schema-registry.prod.url/+  dev:+    host: dev.url:9092+    protocol: kafka+    description: Kafka DEV cluster for `dev` and `sit` environments+    security:+      - $ref: '#/components/securitySchemes/sasl-ssl'+    bindings:+      kafka:+        schemaRegistryUrl: https://schema-registry.prod.url/+channels:+  costingRequestChannel:+    address: adeo-{env}-case-study-COSTING-REQUEST-{version}+    description: >+      Use this topic to do a Costing Request to Costing product. We use the+      [**RecordNameStrategy**](https://docs.confluent.io/platform/current/schema-registry/serdes-develop/index.html#subject-name-strategy)+      to infer the messages schema. You have to define+      `value.subject.name.strategy` to+      `io.confluent.kafka.serializers.subject.RecordNameStrategy` in your+      producer to use the schema we manage. The schema below illustrates how+      Costing Request messages are handled.+      ![](https://user-images.githubusercontent.com/5501911/188920831-689cec5f-8dc3-460b-8794-0b54ec8b0ac8.png)+    parameters:+      env:+        $ref: '#/components/parameters/Env'+      version:+        $ref: '#/components/parameters/Version'+    bindings:+      kafka:+        replicas: 3+        partitions: 3+        topicConfiguration:+          cleanup.policy:+            - delete+          retention.ms: 60000000+    messages:+      CostingRequest:+        $ref: '#/components/messages/costingRequestV1'+  costingResponseChannel:+    address: null+    description: >+      This topic is used to REPLY Costing Requests and is targeted by the+      `REPLY_TOPIC` header. **You must grant PUBLISH access to our `svc-ccr-app`+      service account.**. We use the+      [**RecordNameStrategy**](https://docs.confluent.io/platform/current/schema-registry/serdes-develop/index.html#subject-name-strategy)+      to infer the messages schema. +      +      Topic should follow pattern "adeo-{env}-case-study-COSTING-RESPONSE-{version}"++      You have to define+      `key.subject.name.strategy` and `value.subject.name.strategy` to+      `io.confluent.kafka.serializers.subject.RecordNameStrategy` in your+      consumer. The schema below illustrates how Costing Response messages are+      handled.+           ![](https://user-images.githubusercontent.com/5501911/188920831-689cec5f-8dc3-460b-8794-0b54ec8b0ac8.png)++    bindings:+      kafka:+        x-key.subject.name.strategy:+          type: string+          description: >+            We use the RecordNameStrategy to infer the messages schema. Use+            `key.subject.name.strategy=io.confluent.kafka.serializers.subject.RecordNameStrategy`+            in your consumer configuration.+        x-value.subject.name.strategy:+          type: string+          description: >+            We use the RecordNameStrategy to infer the messages schema. Use+            `value.subject.name.strategy=io.confluent.kafka.serializers.subject.RecordNameStrategy`+            in your consumer configuration.+    tags:+      - name: costing+    messages:+      costingResponse:+        $ref: '#/components/messages/costingResponse'+operations:+  receiveACostingRequest:+    action: receive+    channel:+      $ref: '#/channels/costingRequestChannel'+    reply:+      channel:+        $ref: '#/channels/costingResponseChannel'+      address:+        location: $message.header#/REPLY_TOPIC+    summary: |+      [COSTING] Request one or more Costing calculation for any product+    description: >+      You can try a costing request using our [Conduktor producer+      template](https://conduktor.url/)+    tags:+      - name: costing+    bindings:+      kafka:+        groupId:+          type: string+          description: >+            The groupId must be prefixed by your `svc` account, deliver by the+            Adeo Kafka team. This `svc` must have the write access to the topic.+        x-value.subject.name.strategy:+          type: string+          description: >+            We use the RecordNameStrategy to infer the messages schema. Use+            `value.subject.name.strategy=io.confluent.kafka.serializers.subject.RecordNameStrategy`+            in your producer configuration.++components:+  correlationIds:+    costingCorrelationId:+      description: >+        This correlation ID is used for message tracing and messages+        correlation. This correlation ID is generated at runtime based on the+        `REQUEST_ID` and sent to the RESPONSE message.+      location: $message.header#/REQUEST_ID+  messages:+    costingRequestV1:+      name: CostingRequestV1+      title: Costing Request V1+      summary: Costing Request V1 inputs.+      tags:+        - name: costing+      correlationId:+        $ref: '#/components/correlationIds/costingCorrelationId'+      headers:+        type: object+        required:+          - REQUESTER_ID+          - REQUESTER_CODE+          - REQUEST_ID+          - REPLY_TOPIC+        properties:+          REQUEST_ID:+            $ref: '#/components/schemas/RequestId'+          REPLY_TOPIC:+            $ref: '#/components/schemas/ReplyTopic'+          REQUESTER_ID:+            $ref: '#/components/schemas/RequesterId'+          REQUESTER_CODE:+            $ref: '#/components/schemas/RequesterCode'+      payload:+        schemaFormat: application/vnd.apache.avro;version=1.9.0+        schema:+          $ref: https://www.asyncapi.com/resources/casestudies/adeo/CostingRequestPayload.avsc+    costingResponse:+      name: CostingResponse+      title: Costing Response+      summary: Costing Response ouputs.+      tags:+        - name: costing+      description: >+        Please refer to the `CostingResponseKey.avsc` schema, available on [our+        github project](https://github.url/).+      correlationId:+        $ref: '#/components/correlationIds/costingCorrelationId'+      headers:+        type: object+        properties:+          CALCULATION_ID:+            $ref: '#/components/schemas/MessageId'+          CORRELATION_ID:+            $ref: '#/components/schemas/CorrelationId'+          REQUEST_TIMESTAMP:+            type: string+            format: date-time+            description: Timestamp of the costing request+          CALCULATION_TIMESTAMP:+            type: string+            format: date-time+            description: Technical timestamp for the costing calculation+      payload:+        schemaFormat: application/vnd.apache.avro;version=1.9.0+        schema:+          $ref: https://www.asyncapi.com/resources/casestudies/adeo/CostingResponsePayload.avsc+  schemas:+    RequesterId:+      type: string+      description: The Costing requester service account used to produce costing request.+      examples:+        - svc-ecollect-app+    RequesterCode:+      type: string+      description: >-+        The Costing requester code (generally the BU Code). The requester code+        is useful to get the dedicated context (tenant).+      examples:+        - 1+    MessageId:+      type: string+      format: uuid+      description: A unique Message ID.+      examples:+        - 1fa6ef40-8f47-40a8-8cf6-f8607d0066ef+    RequestId:+      type: string+      format: uuid+      description: >-+        A unique Request ID needed to define a `CORRELATION_ID` for exchanges,+        which will be sent back in the Costing Responses.+      examples:+        - 1fa6ef40-8f47-40a8-8cf6-f8607d0066ef+    CorrelationId:+      type: string+      format: uuid+      description: >-+        A unique Correlation ID defined from the `REQUEST_ID` or the+        `MESSAGE_ID` provided in the Costing Request.+      examples:+        - 1fa6ef40-8f47-40a8-8cf6-f8607d0066ef+    BuCode:+      type: string+      description: The Business Unit code for which data are applicable.+      examples:+        - 1+    ReplyTopic:+      type: string+      description: >+        The Kafka topic where to send the Costing Response. This is required for+        the [Return Address EIP+        pattern](https://www.enterpriseintegrationpatterns.com/patterns/messaging/ReturnAddress.html).+        **You must grant WRITE access to our `svc-ccr-app` service account.**+      examples:+        - adeo-case-study-COSTING-RESPONSE-V1+    ErrorStep:+      type: string+      description: |+        The woker that has thrown the error.+      examples:+        - EXPOSE_RESULT+    ErrorMessage:+      type: string+      description: |+        The error message describing the error.+      examples:+        - Error message+    ErrorCode:+      type: string+      description: |+        The error code.+      examples:+        - CURRENCY_NOT_FOUND+  parameters:+    Env:+      description: Adeo Kafka Environement for messages publications.+      enum:+        - dev+        - sit+        - uat1+        - preprod+        - prod+    Version:+      description: the topic version you want to use+      examples:+        - V1+      default: V1+  securitySchemes:+    sasl-ssl:+      type: plain+      x-sasl.jaas.config: >-+        org.apache.kafka.common.security.plain.PlainLoginModule required+        username="<CLUSTER_API_KEY>" password="<CLUSTER_API_SECRET>";+      x-security.protocol: SASL_SSL+      x-ssl.endpoint.identification.algorithm: https+      x-sasl.mechanism: PLAIN+      description: >+        Use [SASL authentication with SSL+        encryption](https://docs.confluent.io/platform/current/security/security_tutorial.html#configure-clients)+        to connect to the ADEO Broker.
+ reference/examples/anyof-asyncapi.yml view
@@ -0,0 +1,36 @@+asyncapi: 3.1.0+info:+  title: AnyOf example+  version: 1.0.0+channels:+  test:+    address: test+    messages:+      testMessages:+        $ref: '#/components/messages/testMessages'+operations:+  test:+    action: receive+    channel:+      $ref: '#/channels/test'+    messages:+      - $ref: '#/channels/test/messages/testMessages'+components:+  messages:+    testMessages:+      payload:+        anyOf:+          - $ref: '#/components/schemas/objectWithKey'+          - $ref: '#/components/schemas/objectWithKey2'+  schemas:+    objectWithKey:+      type: object+      properties:+        key:+          type: string+          additionalProperties: false+    objectWithKey2:+      type: object+      properties:+        key2:+          type: string
+ reference/examples/application-headers-asyncapi.yml view
@@ -0,0 +1,86 @@+asyncapi: 3.1.0+info:+  title: Application Headers example+  version: 1.0.0+  description: A cut of the Streetlights API to test application header changes supporting+  license:+    name: Apache 2.0+    url: 'https://www.apache.org/licenses/LICENSE-2.0'+defaultContentType: application/json+servers:+  production:+    host: 'test.mosquitto.org:{port}'+    protocol: mqtt+    description: Test broker+    variables:+      port:+        description: Secure connection (TLS) is available through port 8883.+        default: '1883'+        enum:+          - '1883'+          - '8883'+channels:+  lightingMeasured:+    address: 'smartylighting/streetlights/1/0/event/{streetlightId}/lighting/measured'+    messages:+      lightMeasured:+        $ref: '#/components/messages/lightMeasured'+    parameters:+      streetlightId:+        $ref: '#/components/parameters/streetlightId'+operations:+  receiveLightMeasurement:+    action: receive+    channel:+      $ref: '#/channels/lightingMeasured'+    summary: >-+      Inform about environmental lighting conditions of a particular+      streetlight.+    messages:+      - $ref: '#/channels/lightingMeasured/messages/lightMeasured'+components:+  messages:+    lightMeasured:+      name: lightMeasured+      title: Light measured+      summary: >-+        Inform about environmental lighting conditions of a particular+        streetlight.+      correlationId:+        location: $message.header#/MQMD/CorrelId+      contentType: application/json+      headers:+        type: object+        properties:+          MQMD:+            type: object+            properties:+              CorrelId:+                type: string+                minLength: 24+                maxLength: 24+                format: binary+          applicationInstanceId:+            $ref: '#/components/schemas/applicationInstanceId'+      payload:+        $ref: '#/components/schemas/lightMeasuredPayload'+  schemas:+    lightMeasuredPayload:+      type: object+      properties:+        lumens:+          type: integer+          minimum: 0+          description: Light intensity measured in lumens.+        sentAt:+          $ref: '#/components/schemas/sentAt'+    sentAt:+      type: string+      format: date-time+      description: Date and time when the message was sent.+    applicationInstanceId:+      description: Unique identifier for a given instance of the publishing application+      type: string+  parameters:+    streetlightId:+      description: The ID of the streetlight.
+ reference/examples/correlation-id-asyncapi.yml view
@@ -0,0 +1,180 @@+asyncapi: 3.1.0+info:+  title: Correlation ID Example+  version: 1.0.0+  description: A cut of the Streetlights API to test Correlation ID+  license:+    name: Apache 2.0+    url: 'https://www.apache.org/licenses/LICENSE-2.0'+defaultContentType: application/json+servers:+  production:+    host: 'test.mosquitto.org:{port}'+    protocol: mqtt+    description: Test broker+    variables:+      port:+        description: Secure connection (TLS) is available through port 8883.+        default: '1883'+        enum:+          - '1883'+          - '8883'+    security:+      - $ref: '#/components/securitySchemes/apiKey'+      - type: oauth2+        description: Flows to support OAuth 2.0+        flows:+          implicit:+            authorizationUrl: 'https://authserver.example/auth'+            availableScopes:+              'streetlights:on': Ability to switch lights on+              'streetlights:off': Ability to switch lights off+              'streetlights:dim': Ability to dim the lights+          password:+            tokenUrl: 'https://authserver.example/token'+            availableScopes:+              'streetlights:on': Ability to switch lights on+              'streetlights:off': Ability to switch lights off+              'streetlights:dim': Ability to dim the lights+          clientCredentials:+            tokenUrl: 'https://authserver.example/token'+            availableScopes:+              'streetlights:on': Ability to switch lights on+              'streetlights:off': Ability to switch lights off+              'streetlights:dim': Ability to dim the lights+          authorizationCode:+            authorizationUrl: 'https://authserver.example/auth'+            tokenUrl: 'https://authserver.example/token'+            refreshUrl: 'https://authserver.example/refresh'+            availableScopes:+              'streetlights:on': Ability to switch lights on+              'streetlights:off': Ability to switch lights off+              'streetlights:dim': Ability to dim the lights+        scopes:+          - 'streetlights:on'+          - 'streetlights:off'+          - 'streetlights:dim'+      - $ref: '#/components/securitySchemes/openIdConnectWellKnown'+channels:+  lightingMeasured:+    address: 'smartylighting/streetlights/1/0/event/{streetlightId}/lighting/measured'+    messages:+      lightMeasured:+        $ref: '#/components/messages/lightMeasured'+    parameters:+      streetlightId:+        $ref: '#/components/parameters/streetlightId'+  lightsDim:+    address: 'smartylighting/streetlights/1/0/action/{streetlightId}/dim'+    messages:+      dimLight:+        $ref: '#/components/messages/dimLight'+    parameters:+      streetlightId:+        $ref: '#/components/parameters/streetlightId'+operations:+  receiveLightMeasurement:+    action: receive+    channel:+      $ref: '#/channels/lightingMeasured'+    summary: >-+      Inform about environmental lighting conditions of a particular+      streetlight.+    messages:+      - $ref: '#/channels/lightingMeasured/messages/lightMeasured'+  dimLight:+    action: send+    channel:+      $ref: '#/channels/lightsDim'+    messages:+      - $ref: '#/channels/lightsDim/messages/dimLight'+components:+  messages:+    lightMeasured:+      name: lightMeasured+      title: Light measured+      summary: >-+        Inform about environmental lighting conditions of a particular+        streetlight.+      correlationId:+        location: $message.header#/MQMD/CorrelId+      contentType: application/json+      payload:+        $ref: '#/components/schemas/lightMeasuredPayload'+    dimLight:+      name: dimLight+      title: Dim light+      summary: Command a particular streetlight to dim the lights.+      correlationId:+        $ref: '#/components/correlationIds/sentAtCorrelator'+      payload:+        $ref: '#/components/schemas/dimLightPayload'+  schemas:+    lightMeasuredPayload:+      type: object+      properties:+        lumens:+          type: integer+          minimum: 0+          description: Light intensity measured in lumens.+        sentAt:+          $ref: '#/components/schemas/sentAt'+    dimLightPayload:+      type: object+      properties:+        percentage:+          type: integer+          description: Percentage to which the light should be dimmed to.+          minimum: 0+          maximum: 100+        sentAt:+          $ref: '#/components/schemas/sentAt'+    sentAt:+      type: string+      format: date-time+      description: Date and time when the message was sent.+  parameters:+    streetlightId:+      description: The ID of the streetlight.+  correlationIds:+    sentAtCorrelator:+      description: Data from message payload used as correlation ID+      location: $message.payload#/sentAt+  securitySchemes:+    apiKey:+      type: apiKey+      in: user+      description: Provide your API key as the user and leave the password empty.+    supportedOauthFlows:+      type: oauth2+      description: Flows to support OAuth 2.0+      flows:+        implicit:+          authorizationUrl: 'https://authserver.example/auth'+          availableScopes:+            'streetlights:on': Ability to switch lights on+            'streetlights:off': Ability to switch lights off+            'streetlights:dim': Ability to dim the lights+        password:+          tokenUrl: 'https://authserver.example/token'+          availableScopes:+            'streetlights:on': Ability to switch lights on+            'streetlights:off': Ability to switch lights off+            'streetlights:dim': Ability to dim the lights+        clientCredentials:+          tokenUrl: 'https://authserver.example/token'+          availableScopes:+            'streetlights:on': Ability to switch lights on+            'streetlights:off': Ability to switch lights off+            'streetlights:dim': Ability to dim the lights+        authorizationCode:+          authorizationUrl: 'https://authserver.example/auth'+          tokenUrl: 'https://authserver.example/token'+          refreshUrl: 'https://authserver.example/refresh'+          availableScopes:+            'streetlights:on': Ability to switch lights on+            'streetlights:off': Ability to switch lights off+            'streetlights:dim': Ability to dim the lights+    openIdConnectWellKnown:+      type: openIdConnect+      openIdConnectUrl: 'https://authserver.example/.well-known'
+ reference/examples/gitter-streaming-asyncapi.yml view
@@ -0,0 +1,178 @@+asyncapi: 3.1.0+id: 'tag:stream.gitter.im,2022:api'+info:+  title: Gitter Streaming API+  version: 1.0.0+servers:+  production:+    host: stream.gitter.im+    pathname: /v1+    protocol: https+    protocolVersion: '1.1'+    security:+      - $ref: '#/components/securitySchemes/httpBearerToken'+channels:+  rooms:+    address: '/rooms/{roomId}/{resource}'+    messages:+      chatMessage:+        $ref: '#/components/messages/chatMessage'+      heartbeat:+        $ref: '#/components/messages/heartbeat'+    parameters:+      roomId:+        description: Id of the Gitter room.+        examples:+          - 53307860c3599d1de448e19d+      resource:+        enum:+          - chatMessages+          - events+        description: The resource to consume.+operations:+  sendRoomInfo:+    action: send+    channel:+      $ref: '#/channels/rooms'+    bindings:+      http:+        method: POST+    messages:+      - $ref: '#/channels/rooms/messages/chatMessage'+      - $ref: '#/channels/rooms/messages/heartbeat'+components:+  securitySchemes:+    httpBearerToken:+      type: http+      scheme: bearer+  messages:+    chatMessage:+      summary: >-+        A message represents an individual chat message sent to a room. They are+        a sub-resource of a room.+      payload:+        schemaFormat: application/schema+yaml;version=draft-07+        schema:+          type: object+          properties:+            id:+              type: string+              description: ID of the message.+            text:+              type: string+              description: Original message in plain-text/markdown.+            html:+              type: string+              description: HTML formatted message.+            sent:+              type: string+              format: date-time+              description: ISO formatted date of the message.+            fromUser:+              type: object+              description: User that sent the message.+              properties:+                id:+                  type: string+                  description: Gitter User ID.+                username:+                  type: string+                  description: Gitter/GitHub username.+                displayName:+                  type: string+                  description: Gitter/GitHub user real name.+                url:+                  type: string+                  description: Path to the user on Gitter.+                avatarUrl:+                  type: string+                  format: uri+                  description: User avatar URI.+                avatarUrlSmall:+                  type: string+                  format: uri+                  description: User avatar URI (small).+                avatarUrlMedium:+                  type: string+                  format: uri+                  description: User avatar URI (medium).+                v:+                  type: number+                  description: Version.+                gv:+                  type: string+                  description: Stands for "Gravatar version" and is used for cache busting.+            unread:+              type: boolean+              description: Boolean that indicates if the current user has read the message.+            readBy:+              type: number+              description: Number of users that have read the message.+            urls:+              type: array+              description: List of URLs present in the message.+              items:+                type: string+                format: uri+            mentions:+              type: array+              description: List of @Mentions in the message.+              items:+                type: object+                properties:+                  screenName:+                    type: string+                  userId:+                    type: string+                  userIds:+                    type: array+                    items:+                      type: string+            issues:+              type: array+              description: 'List of #Issues referenced in the message.'+              items:+                type: object+                properties:+                  number:+                    type: string+            meta:+              type: array+              description: Metadata. This is currently not used for anything.+              items: {}+            v:+              type: number+              description: Version.+            gv:+              type: string+              description: Stands for "Gravatar version" and is used for cache busting.+      bindings:+        http:+          headers:+            type: object+            properties:+              Transfer-Encoding: +                type: string+                const: chunked+              Trailer: +                type: string+                const: \r\n+    heartbeat:+      summary: Its purpose is to keep the connection alive.+      payload:+        schemaFormat: application/schema+yaml;version=draft-07+        schema:+          type: string+          enum:+            - "\r\n"+      bindings:+        http:+          headers:+            type: object+            properties:+              Transfer-Encoding: +                type: string+                const: chunked+              Trailer: +                type: string+                const: \r\n
+ reference/examples/kraken-websocket-request-reply-message-filter-in-reply-asyncapi.yml view
@@ -0,0 +1,388 @@+asyncapi: 3.1.0++info:+  title: Kraken Websockets API+  version: '1.8.0'+  description: |+    WebSockets API offers real-time market data updates. WebSockets is a bidirectional protocol offering fastest real-time data, helping you build real-time applications. The public message types presented below do not require authentication. Private-data messages can be subscribed on a separate authenticated endpoint. ++    ### General Considerations++    - TLS with SNI (Server Name Indication) is required in order to establish a Kraken WebSockets API connection. See Cloudflare's [What is SNI?](https://www.cloudflare.com/learning/ssl/what-is-sni/) guide for more details.+    - All messages sent and received via WebSockets are encoded in JSON format+    - All decimal fields (including timestamps) are quoted to preserve precision.+    - Timestamps should not be considered unique and not be considered as aliases for transaction IDs. Also, the granularity of timestamps is not representative of transaction rates.+    - At least one private message should be subscribed to keep the authenticated client connection open.+    - Please use REST API endpoint [AssetPairs](https://www.kraken.com/features/api#get-tradable-pairs) to fetch the list of pairs which can be subscribed via WebSockets API. For example, field 'wsname' gives the supported pairs name which can be used to subscribe.+    - Cloudflare imposes a connection/re-connection rate limit (per IP address) of approximately 150 attempts per rolling 10 minutes. If this is exceeded, the IP is banned for 10 minutes.+    - Recommended reconnection behaviour is to (1) attempt reconnection instantly up to a handful of times if the websocket is dropped randomly during normal operation but (2) after maintenance or extended downtime, attempt to reconnect no more quickly than once every 5 seconds. There is no advantage to reconnecting more rapidly after maintenance during cancel_only mode.+++channels:+  currencyExchange:+    address: /+    messages:+      ping:+        $ref: '#/components/messages/ping'+      pong:+        $ref: '#/components/messages/pong'+      heartbeat:+        $ref: '#/components/messages/heartbeat'+      systemStatus:+        $ref: '#/components/messages/systemStatus'+      subscriptionStatus:+        $ref: '#/components/messages/subscriptionStatus'+      subscribe:+        $ref: '#/components/messages/subscribe'+      unsubscribe:+        $ref: '#/components/messages/unsubscribe'+      dummyCurrencyInfo:+        $ref: '#/components/messages/dummyCurrencyInfo'++      +operations:+  receivePing:+    action: receive+    channel: +      $ref: '#/channels/currencyExchange'+    reply:+      channel: +        $ref: '#/channels/currencyExchange'+      messages:+        - $ref: '#/channels/currencyExchange/messages/pong'+    messages:+      - $ref: '#/channels/currencyExchange/messages/ping'+  sendHeartbeat:+    action: send+    channel: +      $ref: '#/channels/currencyExchange'+    messages:+      - $ref: '#/channels/currencyExchange/messages/heartbeat'+  systemStatus:+    action: send+    channel: +      $ref: '#/channels/currencyExchange'+    messages:+      - $ref: '#/channels/currencyExchange/messages/systemStatus'+  receiveSubscribeRequest:+    action: receive+    channel: +      $ref: '#/channels/currencyExchange'+    reply:+      channel: +        $ref: '#/channels/currencyExchange'+      messages:+        - $ref: '#/channels/currencyExchange/messages/subscriptionStatus'+        - $ref: '#/channels/currencyExchange/messages/dummyCurrencyInfo'+    messages:+      - $ref: '#/channels/currencyExchange/messages/subscribe'+  receiveUnsubscribeRequest:+    action: receive+    channel: +      $ref: '#/channels/currencyExchange'+    reply:+      channel: +        $ref: '#/channels/currencyExchange'   +      messages:+        - $ref: '#/channels/currencyExchange/messages/subscriptionStatus'+    messages:+      - $ref: '#/channels/currencyExchange/messages/unsubscribe'+       +       +components:+  messages:+    dummyCurrencyInfo:+      summary: Dummy message with no real life details+      description: It is here in this example to showcase that there is an additional message that normally is of a complex structure. It represents actually currency exchange value to show a reply to operation receiveSubscribeRequest with more than one possible message.+      payload:+        type: object+        properties:+          event:+            type: string+            const: currencyInfo+          reqid:+            $ref: '#/components/schemas/reqid'+          data:+            type: object+        required:+          - event+      correlationId:+        location: '$message.payload#/reqid'++    ping:+      summary: Ping server to determine whether connection is alive+      description: Client can ping server to determine whether connection is alive, server responds with pong. This is an application level ping as opposed to default ping in websockets standard which is server initiated+      payload:+        $ref: '#/components/schemas/ping'+      correlationId:+        location: '$message.payload#/reqid'+        +    pong:+      summary: Pong is a response to ping message+      description: Server pong response to a ping to determine whether connection is alive. This is an application level pong as opposed to default pong in websockets standard which is sent by client in response to a ping+      payload:+        $ref: '#/components/schemas/pong' +      correlationId:+        location: '$message.payload#/reqid'++    subscribe:+      description: Subscribe to a topic on a single or multiple currency pairs.+      payload:+        $ref: '#/components/schemas/subscribe'+      correlationId:+        location: '$message.payload#/reqid'+    unsubscribe:+      description: Unsubscribe, can specify a channelID or multiple currency pairs.+      payload:+        $ref: '#/components/schemas/unsubscribe'+      correlationId:+        location: '$message.payload#/reqid'+    subscriptionStatus:+      description: Subscription status response to subscribe, unsubscribe or exchange initiated unsubscribe.+      payload:+        $ref: '#/components/schemas/subscriptionStatus'+      examples:+        - payload:+            channelID: 10001+            channelName: ohlc-5+            event: subscriptionStatus+            pair: XBT/EUR+            reqid: 42+            status: unsubscribed+            subscription:+              interval: 5+              name: ohlc+        - payload:+            errorMessage: Subscription depth not supported+            event: subscriptionStatus+            pair: XBT/USD+            status: error+            subscription:+              depth: 42+              name: book++    systemStatus:+      description: Status sent on connection or system status changes.+      payload:+        $ref: '#/components/schemas/systemStatus' +        +    heartbeat:+      description: Server heartbeat sent if no subscription traffic within 1 second (approximately)+      payload:+        $ref: '#/components/schemas/heartbeat' +        +        +  schemas:+    ping:+      type: object+      properties:+        event:+          type: string+          const: ping+        reqid:+          $ref: '#/components/schemas/reqid'+      required:+        - event+    heartbeat:+      type: object+      properties:+        event:+          type: string+          const: heartbeat+    pong:+      type: object+      properties:+        event:+          type: string+          const: pong+        reqid:+          $ref: '#/components/schemas/reqid'+    systemStatus:+      type: object+      properties:+        event:+          type: string+          const: systemStatus+        connectionID:+          type: integer+          description: The ID of the connection+        status:+          $ref: '#/components/schemas/status'+        version:+          type: string+    status:+      type: string+      enum:+        - online+        - maintenance+        - cancel_only+        - limit_only+        - post_only+    subscribe:+      type: object+      properties:+        event:+          type: string+          const: subscribe+        reqid:+          $ref: '#/components/schemas/reqid'+        pair:+          $ref: '#/components/schemas/pair'+        subscription:+          type: object+          properties:+            depth:+              $ref: '#/components/schemas/depth'+            interval:+              $ref: '#/components/schemas/interval'+            name:+              $ref: '#/components/schemas/name'+            ratecounter:+              $ref: '#/components/schemas/ratecounter'+            snapshot:+              $ref: '#/components/schemas/snapshot'+            token:+              $ref: '#/components/schemas/token'+          required:+            - name+      required:+        - event+    unsubscribe:+      type: object+      properties:+        event:+          type: string+          const: unsubscribe+        reqid:+          $ref: '#/components/schemas/reqid'+        pair:+          $ref: '#/components/schemas/pair'+        subscription:+          type: object+          properties:+            depth:+              $ref: '#/components/schemas/depth'+            interval:+              $ref: '#/components/schemas/interval'+            name:+              $ref: '#/components/schemas/name'+            token:+              $ref: '#/components/schemas/token'+          required:+            - name+      required:+        - event+    subscriptionStatus:+      type: object+      oneOf:+        - $ref: '#/components/schemas/subscriptionStatusError'+        - $ref: '#/components/schemas/subscriptionStatusSuccess'+    subscriptionStatusError:+      allOf:+        - properties:+            errorMessage:+              type: string+          required:+            - errorMessage+        - $ref: '#/components/schemas/subscriptionStatusCommon'+    subscriptionStatusSuccess:+      allOf:+        - properties:+            channelID:+              type: integer+              description: ChannelID on successful subscription, applicable to public messages only.+            channelName:+              type: string+              description: Channel Name on successful subscription. For payloads 'ohlc' and 'book', respective interval or depth will be added as suffix.+          required:+            - channelID+            - channelName+        - $ref: '#/components/schemas/subscriptionStatusCommon'+    subscriptionStatusCommon:+      type: object+      required:+         - event+      properties:+        event:+          type: string+          const: subscriptionStatus+        reqid:+          $ref: '#/components/schemas/reqid'+        pair:+          $ref: '#/components/schemas/pair'+        status:+          $ref: '#/components/schemas/status'+        subscription:+          required:+            - name+          type: object+          properties:+            depth:+              $ref: '#/components/schemas/depth'+            interval:+              $ref: '#/components/schemas/interval'+            maxratecount:+              $ref: '#/components/schemas/maxratecount'+            name:+              $ref: '#/components/schemas/name'+            token:+              $ref: '#/components/schemas/token'+    interval:+      type: integer+      description: Time interval associated with ohlc subscription in minutes.+      default: 1+      enum:+        - 1+        - 5+        - 15+        - 30+        - 60+        - 240+        - 1440+        - 10080+        - 21600+    name:+      type: string+      description: The name of the channel you subscribe too.+      enum:+        - book+        - ohlc+        - openOrders+        - ownTrades+        - spread+        - ticker+        - trade+    token:+      type: string+      description: base64-encoded authentication token for private-data endpoints.+    depth:+      type: integer+      default: 10+      enum:+        - 10+        - 25+        - 100+        - 500+        - 1000+      description: Depth associated with book subscription in number of levels each side.+    maxratecount:+      type: integer+      description: Max rate-limit budget. Compare to the ratecounter field in the openOrders updates to check whether you are approaching the rate limit.+    ratecounter:+      type: boolean+      default: false+      description: Whether to send rate-limit counter in updates (supported only for openOrders subscriptions)+    snapshot:+      type: boolean+      default: true+      description: Whether to send historical feed data snapshot upon subscription (supported only for ownTrades subscriptions)+    reqid:+      type: integer+      description: client originated ID reflected in response message.+    pair:+      type: array+      description: Array of currency pairs.+      items:+        type: string+        description: Format of each pair is "A/B", where A and B are ISO 4217-A3 for standardized assets and popular unique symbol if not standardized.+        pattern: '[A-Z\s]+\/[A-Z\s]+'
+ reference/examples/kraken-websocket-request-reply-multiple-channels-asyncapi.yml view
@@ -0,0 +1,394 @@+asyncapi: 3.1.0++info:+  title: Kraken Websockets API+  version: '1.8.0'+  description: |+    WebSockets API offers real-time market data updates. WebSockets is a bidirectional protocol offering fastest real-time data, helping you build real-time applications. The public message types presented below do not require authentication. Private-data messages can be subscribed on a separate authenticated endpoint. ++    ### General Considerations++    - TLS with SNI (Server Name Indication) is required in order to establish a Kraken WebSockets API connection. See Cloudflare's [What is SNI?](https://www.cloudflare.com/learning/ssl/what-is-sni/) guide for more details.+    - All messages sent and received via WebSockets are encoded in JSON format+    - All decimal fields (including timestamps) are quoted to preserve precision.+    - Timestamps should not be considered unique and not be considered as aliases for transaction IDs. Also, the granularity of timestamps is not representative of transaction rates.+    - At least one private message should be subscribed to keep the authenticated client connection open.+    - Please use REST API endpoint [AssetPairs](https://www.kraken.com/features/api#get-tradable-pairs) to fetch the list of pairs which can be subscribed via WebSockets API. For example, field 'wsname' gives the supported pairs name which can be used to subscribe.+    - Cloudflare imposes a connection/re-connection rate limit (per IP address) of approximately 150 attempts per rolling 10 minutes. If this is exceeded, the IP is banned for 10 minutes.+    - Recommended reconnection behaviour is to (1) attempt reconnection instantly up to a handful of times if the websocket is dropped randomly during normal operation but (2) after maintenance or extended downtime, attempt to reconnect no more quickly than once every 5 seconds. There is no advantage to reconnecting more rapidly after maintenance during cancel_only mode.+++channels:+  ping:+    address: /+    messages:+      ping:+        $ref: '#/components/messages/ping'+  pong:+    address: /+    messages:+      pong:+        $ref: '#/components/messages/pong'++  heartbeat:+    address: /+    messages:+      heartbeat:+        $ref: '#/components/messages/heartbeat'+      +  systemStatus:+    address: /+    messages:+      systemStatus:+        $ref: '#/components/messages/systemStatus'+      +  currencyInfo:+    address: /+    messages:+      subscriptionStatus:+        $ref: '#/components/messages/subscriptionStatus'+      dummyCurrencyInfo:+        $ref: '#/components/messages/dummyCurrencyInfo'++  subscribe:+    address: /+    messages:+      subscribe:+        $ref: '#/components/messages/subscribe'++  unsubscribe:+    address: /+    messages:+      unsubscribe:+        $ref: '#/components/messages/unsubscribe'+      +operations:+  receivePing:+    action: receive+    channel: +      $ref: '#/channels/ping'+    reply:+      channel: +        $ref: '#/channels/pong'+  heartbeat:+    action: send+    channel: +      $ref: '#/channels/heartbeat' +  systemStatus:+    action: send+    channel: +      $ref: '#/channels/systemStatus' +  subscribe:+    action: receive+    channel: +      $ref: '#/channels/subscribe'+    reply:+      channel: +        $ref: '#/channels/currencyInfo'+  unsubscribe:+    action: receive+    channel: +      $ref: '#/channels/unsubscribe'+    reply:+      channel: +        $ref: '#/channels/currencyInfo'+      messages:+        - $ref: '#/channels/currencyInfo/messages/subscriptionStatus'   +       +       +components:+  messages:+    dummyCurrencyInfo:+      summary: Dummy message with no real life details+      description: It is here in this example to showcase that there is an additional message that normally is of a complex structure. It represents actually currency exchange value to show a reply to operation receiveSubscribeRequest with more than one possible message.+      payload:+        type: object+        properties:+          event:+            type: string+            const: currencyInfo+          reqid:+            $ref: '#/components/schemas/reqid'+          data:+            type: object+        required:+          - event+      correlationId:+        location: '$message.payload#/reqid'+    ping:+      summary: Ping server to determine whether connection is alive+      description: Client can ping server to determine whether connection is alive, server responds with pong. This is an application level ping as opposed to default ping in websockets standard which is server initiated+      payload:+        $ref: '#/components/schemas/ping'+      correlationId:+        location: $message.payload#/reqid+        +    pong:+      summary: Pong is a response to ping message+      description: Server pong response to a ping to determine whether connection is alive. This is an application level pong as opposed to default pong in websockets standard which is sent by client in response to a ping+      payload:+        $ref: '#/components/schemas/pong' +      correlationId:+        location: $message.payload#/reqid++    subscribe:+      description: Subscribe to a topic on a single or multiple currency pairs.+      payload:+        $ref: '#/components/schemas/subscribe'+      correlationId:+        location: $message.payload#/reqid+    unsubscribe:+      description: Unsubscribe, can specify a channelID or multiple currency pairs.+      payload:+        $ref: '#/components/schemas/unsubscribe'+      correlationId:+        location: $message.payload#/reqid+    subscriptionStatus:+      description: Subscription status response to subscribe, unsubscribe or exchange initiated unsubscribe.+      payload:+        $ref: '#/components/schemas/subscriptionStatus'+      examples:+        - payload:+            channelID: 10001+            channelName: ohlc-5+            event: subscriptionStatus+            pair: XBT/EUR+            reqid: 42+            status: unsubscribed+            subscription:+              interval: 5+              name: ohlc+        - payload:+            errorMessage: Subscription depth not supported+            event: subscriptionStatus+            pair: XBT/USD+            status: error+            subscription:+              depth: 42+              name: book++    systemStatus:+      description: Status sent on connection or system status changes.+      payload:+        $ref: '#/components/schemas/systemStatus' +        +    heartbeat:+      description: Server heartbeat sent if no subscription traffic within 1 second (approximately)+      payload:+        $ref: '#/components/schemas/heartbeat' +        +        +  schemas:+    ping:+      type: object+      properties:+        event:+          type: string+          const: ping+        reqid:+          $ref: '#/components/schemas/reqid'+      required:+        - event+    heartbeat:+      type: object+      properties:+        event:+          type: string+          const: heartbeat+    pong:+      type: object+      properties:+        event:+          type: string+          const: pong+        reqid:+          $ref: '#/components/schemas/reqid'+    systemStatus:+      type: object+      properties:+        event:+          type: string+          const: systemStatus+        connectionID:+          type: integer+          description: The ID of the connection+        status:+          $ref: '#/components/schemas/status'+        version:+          type: string+    status:+      type: string+      enum:+        - online+        - maintenance+        - cancel_only+        - limit_only+        - post_only+    subscribe:+      type: object+      properties:+        event:+          type: string+          const: subscribe+        reqid:+          $ref: '#/components/schemas/reqid'+        pair:+          $ref: '#/components/schemas/pair'+        subscription:+          type: object+          properties:+            depth:+              $ref: '#/components/schemas/depth'+            interval:+              $ref: '#/components/schemas/interval'+            name:+              $ref: '#/components/schemas/name'+            ratecounter:+              $ref: '#/components/schemas/ratecounter'+            snapshot:+              $ref: '#/components/schemas/snapshot'+            token:+              $ref: '#/components/schemas/token'+          required:+            - name+      required:+        - event+    unsubscribe:+      type: object+      properties:+        event:+          type: string+          const: unsubscribe+        reqid:+          $ref: '#/components/schemas/reqid'+        pair:+          $ref: '#/components/schemas/pair'+        subscription:+          type: object+          properties:+            depth:+              $ref: '#/components/schemas/depth'+            interval:+              $ref: '#/components/schemas/interval'+            name:+              $ref: '#/components/schemas/name'+            token:+              $ref: '#/components/schemas/token'+          required:+            - name+      required:+        - event+    subscriptionStatus:+      type: object+      oneOf:+        - $ref: '#/components/schemas/subscriptionStatusError'+        - $ref: '#/components/schemas/subscriptionStatusSuccess'+    subscriptionStatusError:+      allOf:+        - properties:+            errorMessage:+              type: string+          required:+            - errorMessage+        - $ref: '#/components/schemas/subscriptionStatusCommon'+    subscriptionStatusSuccess:+      allOf:+        - properties:+            channelID:+              type: integer+              description: ChannelID on successful subscription, applicable to public messages only.+            channelName:+              type: string+              description: Channel Name on successful subscription. For payloads 'ohlc' and 'book', respective interval or depth will be added as suffix.+          required:+            - channelID+            - channelName+        - $ref: '#/components/schemas/subscriptionStatusCommon'+    subscriptionStatusCommon:+      type: object+      required:+         - event+      properties:+        event:+          type: string+          const: subscriptionStatus+        reqid:+          $ref: '#/components/schemas/reqid'+        pair:+          $ref: '#/components/schemas/pair'+        status:+          $ref: '#/components/schemas/status'+        subscription:+          required:+            - name+          type: object+          properties:+            depth:+              $ref: '#/components/schemas/depth'+            interval:+              $ref: '#/components/schemas/interval'+            maxratecount:+              $ref: '#/components/schemas/maxratecount'+            name:+              $ref: '#/components/schemas/name'+            token:+              $ref: '#/components/schemas/token'+    interval:+      type: integer+      description: Time interval associated with ohlc subscription in minutes.+      default: 1+      enum:+        - 1+        - 5+        - 15+        - 30+        - 60+        - 240+        - 1440+        - 10080+        - 21600+    name:+      type: string+      description: The name of the channel you subscribe too.+      enum:+        - book+        - ohlc+        - openOrders+        - ownTrades+        - spread+        - ticker+        - trade+    token:+      type: string+      description: base64-encoded authentication token for private-data endpoints.+    depth:+      type: integer+      default: 10+      enum:+        - 10+        - 25+        - 100+        - 500+        - 1000+      description: Depth associated with book subscription in number of levels each side.+    maxratecount:+      type: integer+      description: Max rate-limit budget. Compare to the ratecounter field in the openOrders updates to check whether you are approaching the rate limit.+    ratecounter:+      type: boolean+      default: false+      description: Whether to send rate-limit counter in updates (supported only for openOrders subscriptions)+    snapshot:+      type: boolean+      default: true+      description: Whether to send historical feed data snapshot upon subscription (supported only for ownTrades subscriptions)+    reqid:+      type: integer+      description: client originated ID reflected in response message.+    pair:+      type: array+      description: Array of currency pairs.+      items:+        type: string+        description: Format of each pair is "A/B", where A and B are ISO 4217-A3 for standardized assets and popular unique symbol if not standardized.+        pattern: '[A-Z\s]+\/[A-Z\s]+'
+ reference/examples/mercure-asyncapi.yml view
@@ -0,0 +1,58 @@+asyncapi: 3.1.0+info:+  title: Mercure Hub Example+  version: 1.0.0+  description: This example demonstrates how to define a Mercure hub.+defaultContentType: application/ld+json+servers:+  production:+    host: demo.mercure.rocks+    pathname: /.well-known/mercure+    protocol: mercure+channels:+  books:+    address: 'https://example.com/books/{id}'+    messages:+      book:+        $ref: '#/components/messages/book'+    description: >-+      Every time a resource of type `http://schema.org/Book` is created or+      modified, a JSON-LD representation of the new version of this resource+      must be pushed in this Mercure topic.+    parameters:+      id:+        description: ID of the book+operations:+  ReceiveBooksInfo:+    action: receive+    channel:+      $ref: '#/channels/books'+    messages:+      - $ref: '#/channels/books/messages/book'+  SendBooksInfo:+    action: send+    channel:+      $ref: '#/channels/books'+    messages:+      - $ref: '#/channels/books/messages/book'+components:+  messages:+    book:+      summary: The content of a book resource.+      externalDocs:+        url: 'https://schema.org/Book'+      payload:+        type: object+        properties:+          '@id':+            type: string+            format: iri-reference+          '@type':+            type: string+            format: iri-reference+          name:+            type: string+          isbn:+            type: string+          abstract:+            type: string
+ reference/examples/not-asyncapi.yml view
@@ -0,0 +1,29 @@+asyncapi: 3.1.0+info:+  title: Not example+  version: 1.0.0+channels:+  test:+    address: test+    messages:+      testMessages:+        $ref: '#/components/messages/testMessages'+operations:+  onTestMsg:+    action: receive+    channel:+      $ref: '#/channels/test'+    messages:+      - $ref: '#/channels/test/messages/testMessages'+components:+  messages:+    testMessages:+      payload:+        $ref: '#/components/schemas/testSchema'+  schemas:+    testSchema:+      type: object+      properties:+        key:+          not:+            type: integer
+ reference/examples/oneof-asyncapi.yml view
@@ -0,0 +1,57 @@+asyncapi: 3.1.0+info:+  title: OneOf example+  version: 1.0.0+channels:+  test:+    address: test+    messages:+      testMessages:+        $ref: '#/components/messages/testMessages'+  test2:+    address: test2+    messages:+      objectWithKey:+        payload:+          $ref: '#/components/schemas/objectWithKey'+      objectWithKey2:+        payload:+          $ref: '#/components/schemas/objectWithKey2'+operations:+  onTestMsg:+    action: receive+    channel:+      $ref: '#/channels/test'+    messages:+      - $ref: '#/channels/test/messages/testMessages'+  sendTest:+    action: send+    channel:+      $ref: '#/channels/test2'+    messages:+      - $ref: '#/channels/test2/messages/objectWithKey'+      - $ref: '#/channels/test2/messages/objectWithKey2'+components:+  messages:+    testMessages:+      payload:+        oneOf:+          - $ref: '#/components/schemas/objectWithKey'+          - $ref: '#/components/schemas/objectWithKey2'+    testMessage1:+      payload:+        $ref: '#/components/schemas/objectWithKey'+    testMessage2:+      payload:+        $ref: '#/components/schemas/objectWithKey2'+  schemas:+    objectWithKey:+      type: object+      properties:+        key:+          type: string+    objectWithKey2:+      type: object+      properties:+        key2:+          type: string
+ reference/examples/operation-security-asyncapi.yml view
@@ -0,0 +1,117 @@+asyncapi: 3.1.0+info:+  title: Notifications+  version: 1.0.0+  description: >-+    This contract defines HTTP Push notification for  application authorization+    revocation topic+channels:+  authRevoke:+    address: AUTHORIZATION_REVOCATION+    messages:+      message:+        $ref: '#/components/messages/message'+operations:+  sendAuthRevoke:+    action: send+    channel:+      $ref: '#/channels/authRevoke'+    security:+      - type: oauth2+        description: The oauth security descriptions+        flows:+          clientCredentials:+            tokenUrl: 'https://example.com/api/oauth/dialog'+            availableScopes:+              'subscribe:auth_revocations': Scope required for authorization revocation topic+        scopes:+          - 'subscribe:auth_revocations'+    bindings:+      http:+        method: POST+    messages:+      - $ref: '#/channels/authRevoke/messages/message'+components:+  messages:+    message:+      headers:+        type: object+        properties:+          X-SIGNATURE:+            description: ECC message signature+            type: string+          Content-Type:+              type: string+              enum:+                - application/json+      payload:+        type: object+        properties:+          metadata:+            $ref: '#/components/schemas/MetaData'+          notification:+            $ref: '#/components/schemas/Notification'+  schemas:+    MetaData:+      type: object+      properties:+        topic:+          type: string+          description: Topic subscribed to.+        schemaVersion:+          type: string+          description: The schema for this topic.+        deprecated:+          type: boolean+          description: If this is a deprecated schema or topic.+          default: 'false'+    Notification:+      type: object+      properties:+        notificationId:+          type: string+          description: The notification Id.+        eventDate:+          type: string+          description: The event date associated with this notification in UTC.+        publishDate:+          type: string+          description: The message publish date in UTC.+        publishAttemptCount:+          type: integer+          description: The number of attempts made to publish this message.+        data:+          $ref: '#/components/schemas/AuthorizationRevocationData'+    AuthorizationRevocationData:+      type: object+      description: The Authorization Revocation payload.+      properties:+        username:+          type: string+          description: The username for the user.+        userId:+          type: string+          description: The immutable public userId for the user+        eiasToken:+          type: string+          description: The legacy eiasToken specific to the user+        revokeReason:+          type: string+          enum:+            - REVOKED_BY_APP+            - REVOKED_BY_USER+            - REVOKED_BY_ADMIN+            - PASSWORD_CHANGE+          description: The reason for authorization revocation+        revocationDate:+          type: string+          description: Date and time when the authorization was revoked+  securitySchemes:+    petstore_auth:+      type: oauth2+      description: The oauth security descriptions+      flows:+        clientCredentials:+          tokenUrl: 'https://example.com/api/oauth/dialog'+          availableScopes:+            'subscribe:auth_revocations': Scope required for authorization revocation topic
+ reference/examples/rpc-client-asyncapi.yml view
@@ -0,0 +1,72 @@+asyncapi: 3.1.0+id: 'urn:example:rpcclient'+info:+  title: RPC Client Example+  version: 1.0.0+  description: This example demonstrates how to define an RPC client.+defaultContentType: application/json+servers:+  production:+    host: rabbitmq.example.org+    protocol: amqp+channels:+  queue:+    address: '{queue}'+    messages:+      receiveSumResult:+        correlationId:+          location: $message.header#/correlation_id+        payload:+          type: object+          properties:+            result:+              type: number+              examples:+                - 7+    parameters:+      queue: {}+    bindings:+      amqp:+        is: queue+        queue:+          exclusive: true+  rpc_queue:+    address: rpc_queue+    messages:+      requestSum:+        correlationId:+          location: $message.header#/correlation_id+        payload:+          type: object+          properties:+            numbers:+              type: array+              items:+                type: number+              examples:+                - - 4+                  - 3+    bindings:+      amqp:+        is: queue+        queue:+          durable: false+operations:+  receiveSumResult:+    action: receive+    channel:+      $ref: '#/channels/queue'+    bindings:+      amqp:+        ack: false+    messages:+      - $ref: '#/channels/queue/messages/receiveSumResult'+  requestSum:+    action: send+    channel:+      $ref: '#/channels/rpc_queue'+    bindings:+      amqp:+        ack: true+    messages:+      - $ref: '#/channels/rpc_queue/messages/requestSum'
+ reference/examples/rpc-server-asyncapi.yml view
@@ -0,0 +1,69 @@+asyncapi: 3.1.0+id: 'urn:example:rpcserver'+info:+  title: RPC Server Example+  version: 1.0.0+  description: This example demonstrates how to define an RPC server.+defaultContentType: application/json+servers:+  production:+    host: rabbitmq.example.org+    protocol: amqp+channels:+  queue:+    address: '{queue}'+    messages:+      sendSumResult:+        correlationId:+          location: $message.header#/correlation_id+        payload:+          type: object+          properties:+            result:+              type: number+              examples:+                - 7+    parameters:+      queue: {}+    bindings:+      amqp:+        is: queue+        queue:+          exclusive: true+  rpc_queue:+    address: rpc_queue+    messages:+      sum:+        correlationId:+          location: $message.header#/correlation_id+        payload:+          type: object+          properties:+            numbers:+              type: array+              items:+                type: number+              examples:+                - - 4+                  - 3+    bindings:+      amqp:+        is: queue+        queue:+          durable: false+operations:+  sendSumResult:+    action: send+    channel:+      $ref: '#/channels/queue'+    bindings:+      amqp:+        ack: true+    messages:+      - $ref: '#/channels/queue/messages/sendSumResult'+  sum:+    action: receive+    channel:+      $ref: '#/channels/rpc_queue'+    messages:+      - $ref: '#/channels/rpc_queue/messages/sum'
+ reference/examples/simple-asyncapi.yml view
@@ -0,0 +1,31 @@+asyncapi: 3.1.0+info:+  title: Account Service+  version: 1.0.0+  description: This service is in charge of processing user signups+channels:+  userSignedup:+    address: user/signedup+    messages:+      UserSignedUp:+        $ref: '#/components/messages/UserSignedUp'+operations:+  sendUserSignedup:+    action: send+    channel:+      $ref: '#/channels/userSignedup'+    messages:+      - $ref: '#/channels/userSignedup/messages/UserSignedUp'+components:+  messages:+    UserSignedUp:+      payload:+        type: object+        properties:+          displayName:+            type: string+            description: Name of the user+          email:+            type: string+            format: email+            description: Email of the user
+ reference/examples/slack-rtm-asyncapi.yml view
@@ -0,0 +1,982 @@+asyncapi: 3.1.0+id: 'wss://wss-primary.slack.com/websocket'+info:+  title: Slack Real Time Messaging API+  version: 1.0.0+servers:+  production:+    host: slack.com+    pathname: /api/rtm.connect+    protocol: https+    protocolVersion: '1.1'+    security:+      - $ref: '#/components/securitySchemes/token'+channels:+  root:+    address: /+    messages:+      outgoingMessage:+        $ref: '#/components/messages/outgoingMessage'+      hello:+        $ref: '#/components/messages/hello'+      connectionError:+        $ref: '#/components/messages/connectionError'+      accountsChanged:+        $ref: '#/components/messages/accountsChanged'+      botAdded:+        $ref: '#/components/messages/botAdded'+      botChanged:+        $ref: '#/components/messages/botChanged'+      channelArchive:+        $ref: '#/components/messages/channelArchive'+      channelCreated:+        $ref: '#/components/messages/channelCreated'+      channelDeleted:+        $ref: '#/components/messages/channelDeleted'+      channelHistoryChanged:+        $ref: '#/components/messages/channelHistoryChanged'+      channelJoined:+        $ref: '#/components/messages/channelJoined'+      channelLeft:+        $ref: '#/components/messages/channelLeft'+      channelMarked:+        $ref: '#/components/messages/channelMarked'+      channelRename:+        $ref: '#/components/messages/channelRename'+      channelUnarchive:+        $ref: '#/components/messages/channelUnarchive'+      commandsChanged:+        $ref: '#/components/messages/commandsChanged'+      dndUpdated:+        $ref: '#/components/messages/dndUpdated'+      dndUpdatedUser:+        $ref: '#/components/messages/dndUpdatedUser'+      emailDomainChanged:+        $ref: '#/components/messages/emailDomainChanged'+      emojiRemoved:+        $ref: '#/components/messages/emojiRemoved'+      emojiAdded:+        $ref: '#/components/messages/emojiAdded'+      fileChange:+        $ref: '#/components/messages/fileChange'+      fileCommentAdded:+        $ref: '#/components/messages/fileCommentAdded'+      fileCommentDeleted:+        $ref: '#/components/messages/fileCommentDeleted'+      fileCommentEdited:+        $ref: '#/components/messages/fileCommentEdited'+      fileCreated:+        $ref: '#/components/messages/fileCreated'+      fileDeleted:+        $ref: '#/components/messages/fileDeleted'+      filePublic:+        $ref: '#/components/messages/filePublic'+      fileShared:+        $ref: '#/components/messages/fileShared'+      fileUnshared:+        $ref: '#/components/messages/fileUnshared'+      goodbye:+        $ref: '#/components/messages/goodbye'+      groupArchive:+        $ref: '#/components/messages/groupArchive'+      groupClose:+        $ref: '#/components/messages/groupClose'+      groupHistoryChanged:+        $ref: '#/components/messages/groupHistoryChanged'+      groupJoined:+        $ref: '#/components/messages/groupJoined'+      groupLeft:+        $ref: '#/components/messages/groupLeft'+      groupMarked:+        $ref: '#/components/messages/groupMarked'+      groupOpen:+        $ref: '#/components/messages/groupOpen'+      groupRename:+        $ref: '#/components/messages/groupRename'+      groupUnarchive:+        $ref: '#/components/messages/groupUnarchive'+      imClose:+        $ref: '#/components/messages/imClose'+      imCreated:+        $ref: '#/components/messages/imCreated'+      imMarked:+        $ref: '#/components/messages/imMarked'+      imOpen:+        $ref: '#/components/messages/imOpen'+      manualPresenceChange:+        $ref: '#/components/messages/manualPresenceChange'+      memberJoinedChannel:+        $ref: '#/components/messages/memberJoinedChannel'+      message:+        $ref: '#/components/messages/message'+operations:+  receiveOutgoingMessage:+    action: receive+    channel:+      $ref: '#/channels/root'+    messages:+      - $ref: '#/channels/root/messages/outgoingMessage'+  sendMessages:+    action: send+    channel:+      $ref: '#/channels/root'+    messages:+      - $ref: '#/channels/root/messages/hello'+      - $ref: '#/channels/root/messages/connectionError'+      - $ref: '#/channels/root/messages/accountsChanged'+      - $ref: '#/channels/root/messages/botAdded'+      - $ref: '#/channels/root/messages/botChanged'+      - $ref: '#/channels/root/messages/channelArchive'+      - $ref: '#/channels/root/messages/channelCreated'+      - $ref: '#/channels/root/messages/channelDeleted'+      - $ref: '#/channels/root/messages/channelHistoryChanged'+      - $ref: '#/channels/root/messages/channelJoined'+      - $ref: '#/channels/root/messages/channelLeft'+      - $ref: '#/channels/root/messages/channelMarked'+      - $ref: '#/channels/root/messages/channelRename'+      - $ref: '#/channels/root/messages/channelUnarchive'+      - $ref: '#/channels/root/messages/commandsChanged'+      - $ref: '#/channels/root/messages/dndUpdated'+      - $ref: '#/channels/root/messages/dndUpdatedUser'+      - $ref: '#/channels/root/messages/emailDomainChanged'+      - $ref: '#/channels/root/messages/emojiRemoved'+      - $ref: '#/channels/root/messages/emojiAdded'+      - $ref: '#/channels/root/messages/fileChange'+      - $ref: '#/channels/root/messages/fileCommentAdded'+      - $ref: '#/channels/root/messages/fileCommentDeleted'+      - $ref: '#/channels/root/messages/fileCommentEdited'+      - $ref: '#/channels/root/messages/fileCreated'+      - $ref: '#/channels/root/messages/fileDeleted'+      - $ref: '#/channels/root/messages/filePublic'+      - $ref: '#/channels/root/messages/fileShared'+      - $ref: '#/channels/root/messages/fileUnshared'+      - $ref: '#/channels/root/messages/goodbye'+      - $ref: '#/channels/root/messages/groupArchive'+      - $ref: '#/channels/root/messages/groupClose'+      - $ref: '#/channels/root/messages/groupHistoryChanged'+      - $ref: '#/channels/root/messages/groupJoined'+      - $ref: '#/channels/root/messages/groupLeft'+      - $ref: '#/channels/root/messages/groupMarked'+      - $ref: '#/channels/root/messages/groupOpen'+      - $ref: '#/channels/root/messages/groupRename'+      - $ref: '#/channels/root/messages/groupUnarchive'+      - $ref: '#/channels/root/messages/imClose'+      - $ref: '#/channels/root/messages/imCreated'+      - $ref: '#/channels/root/messages/imMarked'+      - $ref: '#/channels/root/messages/imOpen'+      - $ref: '#/channels/root/messages/manualPresenceChange'+      - $ref: '#/channels/root/messages/memberJoinedChannel'+      - $ref: '#/channels/root/messages/message'+components:+  securitySchemes:+    token:+      type: httpApiKey+      name: token+      in: query+  schemas:+    attachment:+      type: object+      properties:+        fallback:+          type: string+        color:+          type: string+        pretext:+          type: string+        author_name:+          type: string+        author_link:+          type: string+          format: uri+        author_icon:+          type: string+          format: uri+        title:+          type: string+        title_link:+          type: string+          format: uri+        text:+          type: string+        fields:+          type: array+          items:+            type: object+            properties:+              title:+                type: string+              value:+                type: string+              short:+                type: boolean+        image_url:+          type: string+          format: uri+        thumb_url:+          type: string+          format: uri+        footer:+          type: string+        footer_icon:+          type: string+          format: uri+        ts:+          type: number+  messages:+    hello:+      summary: First event received upon connection.+      payload:+        type: object+        properties:+          type:+            type: string+            enum:+              - hello+    connectionError:+      summary: Event received when a connection error happens.+      payload:+        type: object+        properties:+          type:+            type: string+            enum:+              - error+          error:+            type: object+            properties:+              code:+                type: number+              msg:+                type: string+    accountsChanged:+      summary: The list of accounts a user is signed into has changed.+      payload:+        type: object+        properties:+          type:+            type: string+            enum:+              - accounts_changed+    botAdded:+      summary: A bot user was added.+      payload:+        type: object+        properties:+          type:+            type: string+            enum:+              - bot_added+          bot:+            type: object+            properties:+              id:+                type: string+              app_id:+                type: string+              name:+                type: string+              icons:+                type: object+                additionalProperties:+                  type: string+    botChanged:+      summary: A bot user was changed.+      payload:+        type: object+        properties:+          type:+            type: string+            enum:+              - bot_added+          bot:+            type: object+            properties:+              id:+                type: string+              app_id:+                type: string+              name:+                type: string+              icons:+                type: object+                additionalProperties:+                  type: string+    channelArchive:+      summary: A channel was archived.+      payload:+        type: object+        properties:+          type:+            type: string+            enum:+              - channel_archive+          channel:+            type: string+          user:+            type: string+    channelCreated:+      summary: A channel was created.+      payload:+        type: object+        properties:+          type:+            type: string+            enum:+              - channel_created+          channel:+            type: object+            properties:+              id:+                type: string+              name:+                type: string+              created:+                type: number+              creator:+                type: string+    channelDeleted:+      summary: A channel was deleted.+      payload:+        type: object+        properties:+          type:+            type: string+            enum:+              - channel_deleted+          channel:+            type: string+    channelHistoryChanged:+      summary: Bulk updates were made to a channel's history.+      payload:+        type: object+        properties:+          type:+            type: string+            enum:+              - channel_history_changed+          latest:+            type: string+          ts:+            type: string+          event_ts:+            type: string+    channelJoined:+      summary: You joined a channel.+      payload:+        type: object+        properties:+          type:+            type: string+            enum:+              - channel_joined+          channel:+            type: object+            properties:+              id:+                type: string+              name:+                type: string+              created:+                type: number+              creator:+                type: string+    channelLeft:+      summary: You left a channel.+      payload:+        type: object+        properties:+          type:+            type: string+            enum:+              - channel_left+          channel:+            type: string+    channelMarked:+      summary: Your channel read marker was updated.+      payload:+        type: object+        properties:+          type:+            type: string+            enum:+              - channel_marked+          channel:+            type: string+          ts:+            type: string+    channelRename:+      summary: A channel was renamed.+      payload:+        type: object+        properties:+          type:+            type: string+            enum:+              - channel_rename+          channel:+            type: object+            properties:+              id:+                type: string+              name:+                type: string+              created:+                type: number+    channelUnarchive:+      summary: A channel was unarchived.+      payload:+        type: object+        properties:+          type:+            type: string+            enum:+              - channel_unarchive+          channel:+            type: string+          user:+            type: string+    commandsChanged:+      summary: A slash command has been added or changed.+      payload:+        type: object+        properties:+          type:+            type: string+            enum:+              - commands_changed+          event_ts:+            type: string+    dndUpdated:+      summary: Do not Disturb settings changed for the current user.+      payload:+        type: object+        properties:+          type:+            type: string+            enum:+              - dnd_updated+          user:+            type: string+          dnd_status:+            type: object+            properties:+              dnd_enabled:+                type: boolean+              next_dnd_start_ts:+                type: number+              next_dnd_end_ts:+                type: number+              snooze_enabled:+                type: boolean+              snooze_endtime:+                type: number+    dndUpdatedUser:+      summary: Do not Disturb settings changed for a member.+      payload:+        type: object+        properties:+          type:+            type: string+            enum:+              - dnd_updated_user+          user:+            type: string+          dnd_status:+            type: object+            properties:+              dnd_enabled:+                type: boolean+              next_dnd_start_ts:+                type: number+              next_dnd_end_ts:+                type: number+    emailDomainChanged:+      summary: The workspace email domain has changed.+      payload:+        type: object+        properties:+          type:+            type: string+            enum:+              - email_domain_changed+          email_domain:+            type: string+          event_ts:+            type: string+    emojiRemoved:+      summary: A custom emoji has been removed.+      payload:+        type: object+        properties:+          type:+            type: string+            enum:+              - emoji_changed+          subtype:+            type: string+            enum:+              - remove+          names:+            type: array+            items:+              type: string+          event_ts:+            type: string+    emojiAdded:+      summary: A custom emoji has been added.+      payload:+        type: object+        properties:+          type:+            type: string+            enum:+              - emoji_changed+          subtype:+            type: string+            enum:+              - add+          name:+            type: string+          value:+            type: string+            format: uri+          event_ts:+            type: string+    fileChange:+      summary: A file was changed.+      payload:+        type: object+        properties:+          type:+            type: string+            enum:+              - file_change+          file_id:+            type: string+          file:+            type: object+            properties:+              id:+                type: string+    fileCommentAdded:+      summary: A file comment was added.+      payload:+        type: object+        properties:+          type:+            type: string+            enum:+              - file_comment_added+          comment: {}+          file_id:+            type: string+          file:+            type: object+            properties:+              id:+                type: string+    fileCommentDeleted:+      summary: A file comment was deleted.+      payload:+        type: object+        properties:+          type:+            type: string+            enum:+              - file_comment_deleted+          comment:+            type: string+          file_id:+            type: string+          file:+            type: object+            properties:+              id:+                type: string+    fileCommentEdited:+      summary: A file comment was edited.+      payload:+        type: object+        properties:+          type:+            type: string+            enum:+              - file_comment_edited+          comment: {}+          file_id:+            type: string+          file:+            type: object+            properties:+              id:+                type: string+    fileCreated:+      summary: A file was created.+      payload:+        type: object+        properties:+          type:+            type: string+            enum:+              - file_created+          file_id:+            type: string+          file:+            type: object+            properties:+              id:+                type: string+    fileDeleted:+      summary: A file was deleted.+      payload:+        type: object+        properties:+          type:+            type: string+            enum:+              - file_deleted+          file_id:+            type: string+          event_ts:+            type: string+    filePublic:+      summary: A file was made public.+      payload:+        type: object+        properties:+          type:+            type: string+            enum:+              - file_public+          file_id:+            type: string+          file:+            type: object+            properties:+              id:+                type: string+    fileShared:+      summary: A file was shared.+      payload:+        type: object+        properties:+          type:+            type: string+            enum:+              - file_shared+          file_id:+            type: string+          file:+            type: object+            properties:+              id:+                type: string+    fileUnshared:+      summary: A file was unshared.+      payload:+        type: object+        properties:+          type:+            type: string+            enum:+              - file_unshared+          file_id:+            type: string+          file:+            type: object+            properties:+              id:+                type: string+    goodbye:+      summary: The server intends to close the connection soon.+      payload:+        type: object+        properties:+          type:+            type: string+            enum:+              - goodbye+    groupArchive:+      summary: A private channel was archived.+      payload:+        type: object+        properties:+          type:+            type: string+            enum:+              - group_archive+          channel:+            type: string+    groupClose:+      summary: You closed a private channel.+      payload:+        type: object+        properties:+          type:+            type: string+            enum:+              - group_close+          user:+            type: string+          channel:+            type: string+    groupHistoryChanged:+      summary: Bulk updates were made to a private channel's history.+      payload:+        type: object+        properties:+          type:+            type: string+            enum:+              - group_history_changed+          latest:+            type: string+          ts:+            type: string+          event_ts:+            type: string+    groupJoined:+      summary: You joined a private channel.+      payload:+        type: object+        properties:+          type:+            type: string+            enum:+              - group_joined+          channel:+            type: object+            properties:+              id:+                type: string+              name:+                type: string+              created:+                type: number+              creator:+                type: string+    groupLeft:+      summary: You left a private channel.+      payload:+        type: object+        properties:+          type:+            type: string+            enum:+              - group_left+          channel:+            type: string+    groupMarked:+      summary: A private channel read marker was updated.+      payload:+        type: object+        properties:+          type:+            type: string+            enum:+              - group_marked+          channel:+            type: string+          ts:+            type: string+    groupOpen:+      summary: You opened a private channel.+      payload:+        type: object+        properties:+          type:+            type: string+            enum:+              - group_open+          user:+            type: string+          channel:+            type: string+    groupRename:+      summary: A private channel was renamed.+      payload:+        type: object+        properties:+          type:+            type: string+            enum:+              - group_rename+          channel:+            type: object+            properties:+              id:+                type: string+              name:+                type: string+              created:+                type: number+    groupUnarchive:+      summary: A private channel was unarchived.+      payload:+        type: object+        properties:+          type:+            type: string+            enum:+              - group_unarchive+          channel:+            type: string+          user:+            type: string+    imClose:+      summary: You closed a DM.+      payload:+        type: object+        properties:+          type:+            type: string+            enum:+              - im_close+          channel:+            type: string+          user:+            type: string+    imCreated:+      summary: A DM was created.+      payload:+        type: object+        properties:+          type:+            type: string+            enum:+              - im_created+          channel:+            type: object+            properties:+              id:+                type: string+              name:+                type: string+              created:+                type: number+              creator:+                type: string+          user:+            type: string+    imMarked:+      summary: A direct message read marker was updated.+      payload:+        type: object+        properties:+          type:+            type: string+            enum:+              - im_marked+          channel:+            type: string+          ts:+            type: string+    imOpen:+      summary: You opened a DM.+      payload:+        type: object+        properties:+          type:+            type: string+            enum:+              - im_open+          channel:+            type: string+          user:+            type: string+    manualPresenceChange:+      summary: You manually updated your presence.+      payload:+        type: object+        properties:+          type:+            type: string+            enum:+              - manual_presence_change+          presence:+            type: string+    memberJoinedChannel:+      summary: A user joined a public or private channel.+      payload:+        type: object+        properties:+          type:+            type: string+            enum:+              - member_joined_channel+          user:+            type: string+          channel:+            type: string+          channel_type:+            type: string+            enum:+              - C+              - G+          team:+            type: string+          inviter:+            type: string+    memberLeftChannel:+      summary: A user left a public or private channel.+      payload:+        type: object+        properties:+          type:+            type: string+            enum:+              - member_left_channel+          user:+            type: string+          channel:+            type: string+          channel_type:+            type: string+            enum:+              - C+              - G+          team:+            type: string+    message:+      summary: A message was sent to a channel.+      payload:+        type: object+        properties:+          type:+            type: string+            enum:+              - message+          user:+            type: string+          channel:+            type: string+          text:+            type: string+          ts:+            type: string+          attachments:+            type: array+            items:+              $ref: '#/components/schemas/attachment'+          edited:+            type: object+            properties:+              user:+                type: string+              ts:+                type: string+    outgoingMessage:+      summary: A message was sent to a channel.+      payload:+        type: object+        properties:+          id:+            type: number+          type:+            type: string+            enum:+              - message+          channel:+            type: string+          text:+            type: string
+ reference/examples/social-media/backend/asyncapi.yaml view
@@ -0,0 +1,83 @@+asyncapi: 3.1.0+info:+  title: Website Backend+  version: 1.0.0+servers:+  websiteWebSocketServer:+    $ref: '../common/servers.yaml#/websiteWebSocketServer'+  mosquitto:+    host: test.mosquitto.org+    protocol: mqtt+    tags:+      - name: 'env:production'+        description: This environment is meant for production use case+      - name: 'kind:remote'+        description: This server is a remote server. Not exposed by the application+      - name: 'visibility:public'+        description: This resource is public and available to everyone+    bindings:+      mqtt:+        clientId: websocketServer+channels:+  notifyAllCommentLiked:+    address: comment/liked+    messages:+      commentLiked:+        $ref: '../common/messages.yaml#/commentLiked'+    description: Notify all the services that a comment has been liked.+    servers:+      - $ref: '#/servers/mosquitto'+  newLikeComment:+    address: like/comment+    messages:+      likeComment:+        $ref: '../common/messages.yaml#/likeComment'+    description: When a comment like is received from the frontend.+    servers:+      - $ref: '#/servers/websiteWebSocketServer'+  commentsCountChange:+    address: 'comment/{commentId}/changed'+    messages:+      commentChanged:+        $ref: '../common/messages.yaml#/commentChanged'+    description: >-+      When an event from the broker arrives telling us to update the comment+      likes count on the frontend.+    servers:+      - $ref: '#/servers/mosquitto'+    parameters:+      commentId:+        $ref: '../common/parameters.yaml#/commentId'+  updateCommentsCount:+    address: update/comment/likes+    messages:+      updateCommentLikes:+        $ref: '../common/messages.yaml#/updateCommentLikes'+    description: Update comment likes count in the frontend.+    servers:+      - $ref: '#/servers/websiteWebSocketServer'+operations:+  sendCommentLiked:+    action: send+    channel:+      $ref: '#/channels/notifyAllCommentLiked'+    messages:+      - $ref: '#/channels/notifyAllCommentLiked/messages/commentLiked'+  receiveCommentLike:+    action: receive+    channel:+      $ref: '#/channels/newLikeComment'+    messages:+      - $ref: '#/channels/newLikeComment/messages/likeComment'+  receiveCommentChange:+    action: receive+    channel:+      $ref: '#/channels/commentsCountChange'+    messages:+      - $ref: '#/channels/commentsCountChange/messages/commentChanged'+  sendCommentLikeUpdate:+    action: send+    channel:+      $ref: '#/channels/updateCommentsCount'+    messages:+      - $ref: '#/channels/updateCommentsCount/messages/updateCommentLikes'
+ reference/examples/social-media/comments-service/asyncapi.yaml view
@@ -0,0 +1,52 @@+asyncapi: 3.1.0+info:+  title: Comments Service+  version: 1.0.0+  description: This service is in charge of processing all the events related to comments.+servers:+  mosquitto:+    host: test.mosquitto.org+    protocol: mqtt+    tags:+      - name: 'env:production'+        description: This environment is meant for production use case+      - name: 'kind:remote'+        description: This server is a remote server. Not exposed by the application+      - name: 'visibility:public'+        description: This resource is public and available to everyone+    bindings:+      mqtt:+        clientId: comment-service+channels:+  commentLiked:+    address: comment/liked+    messages:+      commentLiked:+        $ref: '../common/messages.yaml#/commentLiked'+    description: >-+      Updates the likes count in the database and sends the new count to the+      broker.+  commentCountChange:+    address: 'comment/{commentId}/changed'+    messages:+      commentChanged:+        $ref: '../common/messages.yaml#/commentChanged'+    description: >-+      Sends the new count to the broker after it has been updated in the+      database.+    parameters:+      commentId:+        $ref: '../common/parameters.yaml#/commentId'+operations:+  receiveCommentLiked:+    action: receive+    channel:+      $ref: '#/channels/commentLiked'+    messages:+      - $ref: '#/channels/commentLiked/messages/commentLiked'+  sendCommentChange:+    action: send+    channel:+      $ref: '#/channels/commentCountChange'+    messages:+      - $ref: '#/channels/commentCountChange/messages/commentChanged'
+ reference/examples/social-media/frontend/asyncapi.yaml view
@@ -0,0 +1,33 @@+asyncapi: 3.1.0+info:+  title: Website WebSocket Client+  version: 1.0.0+servers:+  websiteWebSocketServer:+    $ref: '../common/servers.yaml#/websiteWebSocketServer'+channels:+  likeComment:+    address: like/comment+    messages:+      likeComment:+        $ref: '../common/messages.yaml#/likeComment'+    description: Notify the backend that a comment has been liked.+  updateCommentLike:+    address: update/comment/likes+    messages:+      updateCommentLikes:+        $ref: '../common/messages.yaml#/updateCommentLikes'+    description: Update the UI when the comment likes count is updated.+operations:+  sendLikeComment:+    action: send+    channel:+      $ref: '#/channels/likeComment'+    messages:+      - $ref: '#/channels/likeComment/messages/likeComment'+  receiveUpdateCommentLiked:+    action: receive+    channel:+      $ref: '#/channels/updateCommentLike'+    messages:+      - $ref: '#/channels/updateCommentLike/messages/updateCommentLikes'
+ reference/examples/social-media/notification-service/asyncapi.yaml view
@@ -0,0 +1,34 @@+asyncapi: 3.1.0+info:+  title: Notifications Service+  version: 1.0.0+servers:+  mosquitto:+    host: test.mosquitto.org+    protocol: mqtt+    tags:+      - name: 'env:production'+        description: This environment is meant for production use case+      - name: 'kind:remote'+        description: This server is a remote server. Not exposed by the application+      - name: 'visibility:public'+        description: This resource is public and available to everyone+    bindings:+      mqtt:+        clientId: notification-service+channels:+  commentLiked:+    address: comment/liked+    messages:+      commentLiked:+        $ref: '../common/messages.yaml#/commentLiked'+    description: >-+      When a "comment has been liked" message is received, it sends an SMS or+      push notification to the author.+operations:+  receiveCommentLiked:+    action: receive+    channel:+      $ref: '#/channels/commentLiked'+    messages:+      - $ref: '#/channels/commentLiked/messages/commentLiked'
+ reference/examples/social-media/public-api/asyncapi.yaml view
@@ -0,0 +1,35 @@+asyncapi: 3.1.0+info:+  title: Public API+  version: 1.0.0+  description: Public API for others to interact with the system+servers:+  mosquitto:+    host: test.mosquitto.org+    protocol: mqtt+    tags:+      - name: 'env:production'+        description: This environment is meant for production use case+      - name: 'kind:remote'+        description: This server is a remote server. Not exposed by the application+      - name: 'visibility:public'+        description: This resource is public and available to everyone+    bindings:+      mqtt:+        clientId: public-api+channels:+  commentLiked:+    address: comment/liked+    messages:+      commentLiked:+        $ref: '../common/messages.yaml#/commentLiked'+    description: >-+      Others are publishing to you, whenever a comment is liked, for you to do+      react to such an event.+operations:+  receiveCommentLiked:+    action: receive+    channel:+      $ref: '#/channels/commentLiked'+    messages:+      - $ref: '#/channels/commentLiked/messages/commentLiked'
+ reference/examples/streetlights-kafka-asyncapi.yml view
@@ -0,0 +1,199 @@+asyncapi: 3.1.0+info:+  title: Streetlights Kafka API+  version: 1.0.0+  description: "The Smartylighting Streetlights API allows you to remotely manage the city lights.\n\n### Check out its awesome features:\n\n* Turn a specific streetlight on/off \U0001F303\n* Dim a specific streetlight \U0001F60E\n* Receive real-time information about environmental lighting conditions \U0001F4C8\n"+  license:+    name: Apache 2.0+    url: 'https://www.apache.org/licenses/LICENSE-2.0'+defaultContentType: application/json+servers:+  scram-connections:+    host: 'test.mykafkacluster.org:18092'+    protocol: kafka-secure+    description: Test broker secured with scramSha256+    security:+      - $ref: '#/components/securitySchemes/saslScram'+    tags:+      - name: 'env:test-scram'+        description: >-+          This environment is meant for running internal tests through+          scramSha256+      - name: 'kind:remote'+        description: This server is a remote server. Not exposed by the application+      - name: 'visibility:private'+        description: This resource is private and only available to certain users+  mtls-connections:+    host: 'test.mykafkacluster.org:28092'+    protocol: kafka-secure+    description: Test broker secured with X509+    security:+      - $ref: '#/components/securitySchemes/certs'+    tags:+      - name: 'env:test-mtls'+        description: This environment is meant for running internal tests through mtls+      - name: 'kind:remote'+        description: This server is a remote server. Not exposed by the application+      - name: 'visibility:private'+        description: This resource is private and only available to certain users+channels:+  lightingMeasured:+    address: 'smartylighting.streetlights.1.0.event.{streetlightId}.lighting.measured'+    messages:+      lightMeasured:+        $ref: '#/components/messages/lightMeasured'+    description: The topic on which measured values may be produced and consumed.+    parameters:+      streetlightId:+        $ref: '#/components/parameters/streetlightId'+  lightTurnOn:+    address: 'smartylighting.streetlights.1.0.action.{streetlightId}.turn.on'+    messages:+      turnOn:+        $ref: '#/components/messages/turnOnOff'+    parameters:+      streetlightId:+        $ref: '#/components/parameters/streetlightId'+  lightTurnOff:+    address: 'smartylighting.streetlights.1.0.action.{streetlightId}.turn.off'+    messages:+      turnOff:+        $ref: '#/components/messages/turnOnOff'+    parameters:+      streetlightId:+        $ref: '#/components/parameters/streetlightId'+  lightsDim:+    address: 'smartylighting.streetlights.1.0.action.{streetlightId}.dim'+    messages:+      dimLight:+        $ref: '#/components/messages/dimLight'+    parameters:+      streetlightId:+        $ref: '#/components/parameters/streetlightId'+operations:+  receiveLightMeasurement:+    action: receive+    channel:+      $ref: '#/channels/lightingMeasured'+    summary: >-+      Inform about environmental lighting conditions of a particular+      streetlight.+    traits:+      - $ref: '#/components/operationTraits/kafka'+    messages:+      - $ref: '#/channels/lightingMeasured/messages/lightMeasured'+  turnOn:+    action: send+    channel:+      $ref: '#/channels/lightTurnOn'+    traits:+      - $ref: '#/components/operationTraits/kafka'+    messages:+      - $ref: '#/channels/lightTurnOn/messages/turnOn'+  turnOff:+    action: send+    channel:+      $ref: '#/channels/lightTurnOff'+    traits:+      - $ref: '#/components/operationTraits/kafka'+    messages:+      - $ref: '#/channels/lightTurnOff/messages/turnOff'+  dimLight:+    action: send+    channel:+      $ref: '#/channels/lightsDim'+    traits:+      - $ref: '#/components/operationTraits/kafka'+    messages:+      - $ref: '#/channels/lightsDim/messages/dimLight'+components:+  messages:+    lightMeasured:+      name: lightMeasured+      title: Light measured+      summary: >-+        Inform about environmental lighting conditions of a particular+        streetlight.+      contentType: application/json+      traits:+        - $ref: '#/components/messageTraits/commonHeaders'+      payload:+        $ref: '#/components/schemas/lightMeasuredPayload'+    turnOnOff:+      name: turnOnOff+      title: Turn on/off+      summary: Command a particular streetlight to turn the lights on or off.+      traits:+        - $ref: '#/components/messageTraits/commonHeaders'+      payload:+        $ref: '#/components/schemas/turnOnOffPayload'+    dimLight:+      name: dimLight+      title: Dim light+      summary: Command a particular streetlight to dim the lights.+      traits:+        - $ref: '#/components/messageTraits/commonHeaders'+      payload:+        $ref: '#/components/schemas/dimLightPayload'+  schemas:+    lightMeasuredPayload:+      type: object+      properties:+        lumens:+          type: integer+          minimum: 0+          description: Light intensity measured in lumens.+        sentAt:+          $ref: '#/components/schemas/sentAt'+    turnOnOffPayload:+      type: object+      properties:+        command:+          type: string+          enum:+            - 'on'+            - 'off'+          description: Whether to turn on or off the light.+        sentAt:+          $ref: '#/components/schemas/sentAt'+    dimLightPayload:+      type: object+      properties:+        percentage:+          type: integer+          description: Percentage to which the light should be dimmed to.+          minimum: 0+          maximum: 100+        sentAt:+          $ref: '#/components/schemas/sentAt'+    sentAt:+      type: string+      format: date-time+      description: Date and time when the message was sent.+  securitySchemes:+    saslScram:+      type: scramSha256+      description: Provide your username and password for SASL/SCRAM authentication+    certs:+      type: X509+      description: Download the certificate files from service provider+  parameters:+    streetlightId:+      description: The ID of the streetlight.+  messageTraits:+    commonHeaders:+      headers:+        type: object+        properties:+          my-app-header:+            type: integer+            minimum: 0+            maximum: 100+  operationTraits:+    kafka:+      bindings:+        kafka:+          clientId:+            type: string+            enum:+              - my-app-id
+ reference/examples/streetlights-mqtt-asyncapi.yml view
@@ -0,0 +1,253 @@+asyncapi: 3.1.0+info:+  title: Streetlights MQTT API+  version: 1.0.0+  description: "The Smartylighting Streetlights API allows you to remotely manage the city lights.\n\n### Check out its awesome features:\n\n* Turn a specific streetlight on/off \U0001F303\n* Dim a specific streetlight \U0001F60E\n* Receive real-time information about environmental lighting conditions \U0001F4C8\n"+  license:+    name: Apache 2.0+    url: 'https://www.apache.org/licenses/LICENSE-2.0'+defaultContentType: application/json+servers:+  production:+    host: 'test.mosquitto.org:{port}'+    protocol: mqtt+    description: Test broker+    variables:+      port:+        description: Secure connection (TLS) is available through port 8883.+        default: '1883'+        enum:+          - '1883'+          - '8883'+    security:+      - $ref: '#/components/securitySchemes/apiKey'+      - type: oauth2+        description: Flows to support OAuth 2.0+        flows:+          implicit:+            authorizationUrl: 'https://authserver.example/auth'+            availableScopes:+              'streetlights:on': Ability to switch lights on+              'streetlights:off': Ability to switch lights off+              'streetlights:dim': Ability to dim the lights+          password:+            tokenUrl: 'https://authserver.example/token'+            availableScopes:+              'streetlights:on': Ability to switch lights on+              'streetlights:off': Ability to switch lights off+              'streetlights:dim': Ability to dim the lights+          clientCredentials:+            tokenUrl: 'https://authserver.example/token'+            availableScopes:+              'streetlights:on': Ability to switch lights on+              'streetlights:off': Ability to switch lights off+              'streetlights:dim': Ability to dim the lights+          authorizationCode:+            authorizationUrl: 'https://authserver.example/auth'+            tokenUrl: 'https://authserver.example/token'+            refreshUrl: 'https://authserver.example/refresh'+            availableScopes:+              'streetlights:on': Ability to switch lights on+              'streetlights:off': Ability to switch lights off+              'streetlights:dim': Ability to dim the lights+        scopes:+          - 'streetlights:on'+          - 'streetlights:off'+          - 'streetlights:dim'+      - $ref: '#/components/securitySchemes/openIdConnectWellKnown'+    tags:+      - name: 'env:production'+        description: This environment is meant for production use case+      - name: 'kind:remote'+        description: This server is a remote server. Not exposed by the application+      - name: 'visibility:public'+        description: This resource is public and available to everyone+channels:+  lightingMeasured:+    address: 'smartylighting/streetlights/1/0/event/{streetlightId}/lighting/measured'+    messages:+      lightMeasured:+        $ref: '#/components/messages/lightMeasured'+    description: The topic on which measured values may be produced and consumed.+    parameters:+      streetlightId:+        $ref: '#/components/parameters/streetlightId'+  lightTurnOn:+    address: 'smartylighting/streetlights/1/0/action/{streetlightId}/turn/on'+    messages:+      turnOn:+        $ref: '#/components/messages/turnOnOff'+    parameters:+      streetlightId:+        $ref: '#/components/parameters/streetlightId'+  lightTurnOff:+    address: 'smartylighting/streetlights/1/0/action/{streetlightId}/turn/off'+    messages:+      turnOff:+        $ref: '#/components/messages/turnOnOff'+    parameters:+      streetlightId:+        $ref: '#/components/parameters/streetlightId'+  lightsDim:+    address: 'smartylighting/streetlights/1/0/action/{streetlightId}/dim'+    messages:+      dimLight:+        $ref: '#/components/messages/dimLight'+    parameters:+      streetlightId:+        $ref: '#/components/parameters/streetlightId'+operations:+  receiveLightMeasurement:+    action: receive+    channel:+      $ref: '#/channels/lightingMeasured'+    summary: >-+      Inform about environmental lighting conditions of a particular+      streetlight.+    traits:+      - $ref: '#/components/operationTraits/mqtt'+    messages:+      - $ref: '#/channels/lightingMeasured/messages/lightMeasured'+  turnOn:+    action: send+    channel:+      $ref: '#/channels/lightTurnOn'+    traits:+      - $ref: '#/components/operationTraits/mqtt'+    messages:+      - $ref: '#/channels/lightTurnOn/messages/turnOn'+  turnOff:+    action: send+    channel:+      $ref: '#/channels/lightTurnOff'+    traits:+      - $ref: '#/components/operationTraits/mqtt'+    messages:+      - $ref: '#/channels/lightTurnOff/messages/turnOff'+  dimLight:+    action: send+    channel:+      $ref: '#/channels/lightsDim'+    traits:+      - $ref: '#/components/operationTraits/mqtt'+    messages:+      - $ref: '#/channels/lightsDim/messages/dimLight'+components:+  messages:+    lightMeasured:+      name: lightMeasured+      title: Light measured+      summary: >-+        Inform about environmental lighting conditions of a particular+        streetlight.+      contentType: application/json+      traits:+        - $ref: '#/components/messageTraits/commonHeaders'+      payload:+        $ref: '#/components/schemas/lightMeasuredPayload'+    turnOnOff:+      name: turnOnOff+      title: Turn on/off+      summary: Command a particular streetlight to turn the lights on or off.+      traits:+        - $ref: '#/components/messageTraits/commonHeaders'+      payload:+        $ref: '#/components/schemas/turnOnOffPayload'+    dimLight:+      name: dimLight+      title: Dim light+      summary: Command a particular streetlight to dim the lights.+      traits:+        - $ref: '#/components/messageTraits/commonHeaders'+      payload:+        $ref: '#/components/schemas/dimLightPayload'+  schemas:+    lightMeasuredPayload:+      type: object+      properties:+        lumens:+          type: integer+          minimum: 0+          description: Light intensity measured in lumens.+        sentAt:+          $ref: '#/components/schemas/sentAt'+    turnOnOffPayload:+      type: object+      properties:+        command:+          type: string+          enum:+            - 'on'+            - 'off'+          description: Whether to turn on or off the light.+        sentAt:+          $ref: '#/components/schemas/sentAt'+    dimLightPayload:+      type: object+      properties:+        percentage:+          type: integer+          description: Percentage to which the light should be dimmed to.+          minimum: 0+          maximum: 100+        sentAt:+          $ref: '#/components/schemas/sentAt'+    sentAt:+      type: string+      format: date-time+      description: Date and time when the message was sent.+  securitySchemes:+    apiKey:+      type: apiKey+      in: user+      description: Provide your API key as the user and leave the password empty.+    supportedOauthFlows:+      type: oauth2+      description: Flows to support OAuth 2.0+      flows:+        implicit:+          authorizationUrl: 'https://authserver.example/auth'+          availableScopes:+            'streetlights:on': Ability to switch lights on+            'streetlights:off': Ability to switch lights off+            'streetlights:dim': Ability to dim the lights+        password:+          tokenUrl: 'https://authserver.example/token'+          availableScopes:+            'streetlights:on': Ability to switch lights on+            'streetlights:off': Ability to switch lights off+            'streetlights:dim': Ability to dim the lights+        clientCredentials:+          tokenUrl: 'https://authserver.example/token'+          availableScopes:+            'streetlights:on': Ability to switch lights on+            'streetlights:off': Ability to switch lights off+            'streetlights:dim': Ability to dim the lights+        authorizationCode:+          authorizationUrl: 'https://authserver.example/auth'+          tokenUrl: 'https://authserver.example/token'+          refreshUrl: 'https://authserver.example/refresh'+          availableScopes:+            'streetlights:on': Ability to switch lights on+            'streetlights:off': Ability to switch lights off+            'streetlights:dim': Ability to dim the lights+    openIdConnectWellKnown:+      type: openIdConnect+      openIdConnectUrl: 'https://authserver.example/.well-known'+  parameters:+    streetlightId:+      description: The ID of the streetlight.+  messageTraits:+    commonHeaders:+      headers:+        type: object+        properties:+          my-app-header:+            type: integer+            minimum: 0+            maximum: 100+  operationTraits:+    mqtt:+      bindings:+        mqtt:+          qos: 1
+ reference/examples/streetlights-operation-security-asyncapi.yml view
@@ -0,0 +1,240 @@+asyncapi: 3.1.0+info:+  title: Streetlights Kafka API+  version: 1.0.0+  description: "The Smartylighting Streetlights API allows you to remotely manage the city lights.\n\n### Check out its awesome features:\n\n* Turn a specific streetlight on/off \U0001F303\n* Dim a specific streetlight \U0001F60E\n* Receive real-time information about environmental lighting conditions \U0001F4C8\n"+  license:+    name: Apache 2.0+    url: 'https://www.apache.org/licenses/LICENSE-2.0'+defaultContentType: application/json+servers:+  test:+    host: 'test.mykafkacluster.org:8092'+    protocol: kafka-secure+    description: Test broker+    security:+      - $ref: '#/components/securitySchemes/saslScram'+  test_oauth:+    host: 'test.mykafkacluster.org:8093'+    protocol: kafka-secure+    description: Test port for oauth+    security:+      - type: oauth2+        description: The oauth security descriptions+        flows:+          clientCredentials:+            tokenUrl: 'https://example.com/api/oauth/dialog'+            availableScopes:+              'streetlights:read': Scope required for subscribing to channel+              'streetlights:write': Scope required for publishing to channel+        scopes:+          - 'streetlights:write'+          - 'streetlights:read'+channels:+  lightingMeasured:+    address: 'smartylighting.streetlights.1.0.event.{streetlightId}.lighting.measured'+    messages:+      lightMeasured:+        $ref: '#/components/messages/lightMeasured'+    description: The topic on which measured values may be produced and consumed.+    servers:+      - $ref: '#/servers/test'+    parameters:+      streetlightId:+        $ref: '#/components/parameters/streetlightId'+  lightTurnOn:+    address: 'smartylighting.streetlights.1.0.action.{streetlightId}.turn.on'+    messages:+      turnOn:+        $ref: '#/components/messages/turnOnOff'+    servers:+      - $ref: '#/servers/test_oauth'+    parameters:+      streetlightId:+        $ref: '#/components/parameters/streetlightId'+  lightTurnOff:+    address: 'smartylighting.streetlights.1.0.action.{streetlightId}.turn.off'+    messages:+      turnOff:+        $ref: '#/components/messages/turnOnOff'+    servers:+      - $ref: '#/servers/test_oauth'+    parameters:+      streetlightId:+        $ref: '#/components/parameters/streetlightId'+  lightsDim:+    address: 'smartylighting.streetlights.1.0.action.{streetlightId}.dim'+    messages:+      dimLight:+        $ref: '#/components/messages/dimLight'+    servers:+      - $ref: '#/servers/test_oauth'+    parameters:+      streetlightId:+        $ref: '#/components/parameters/streetlightId'+operations:+  receiveLightMeasurement:+    action: receive+    channel:+      $ref: '#/channels/lightingMeasured'+    summary: >-+      Inform about environmental lighting conditions of a particular+      streetlight.+    traits:+      - $ref: '#/components/operationTraits/kafka'+    messages:+      - $ref: '#/channels/lightingMeasured/messages/lightMeasured'+  turnOn:+    action: send+    channel:+      $ref: '#/channels/lightTurnOn'+    security:+      - type: oauth2+        description: The oauth security descriptions+        flows:+          clientCredentials:+            tokenUrl: 'https://example.com/api/oauth/dialog'+            availableScopes:+              'streetlights:read': Scope required for subscribing to channel+              'streetlights:write': Scope required for publishing to channel+        scopes:+          - 'streetlights:read'+    traits:+      - $ref: '#/components/operationTraits/kafka'+    messages:+      - $ref: '#/channels/lightTurnOn/messages/turnOn'+  turnOff:+    action: send+    channel:+      $ref: '#/channels/lightTurnOff'+    security:+      - type: oauth2+        description: The oauth security descriptions+        flows:+          clientCredentials:+            tokenUrl: 'https://example.com/api/oauth/dialog'+            availableScopes:+              'streetlights:read': Scope required for subscribing to channel+              'streetlights:write': Scope required for publishing to channel+        scopes:+          - 'streetlights:read'+    traits:+      - $ref: '#/components/operationTraits/kafka'+    messages:+      - $ref: '#/channels/lightTurnOff/messages/turnOff'+  dimLight:+    action: send+    channel:+      $ref: '#/channels/lightsDim'+    security:+      - type: oauth2+        description: The oauth security descriptions+        flows:+          clientCredentials:+            tokenUrl: 'https://example.com/api/oauth/dialog'+            availableScopes:+              'streetlights:read': Scope required for subscribing to channel+              'streetlights:write': Scope required for publishing to channel+        scopes:+          - 'streetlights:read'+    traits:+      - $ref: '#/components/operationTraits/kafka'+    messages:+      - $ref: '#/channels/lightsDim/messages/dimLight'+components:+  messages:+    lightMeasured:+      name: lightMeasured+      title: Light measured+      summary: >-+        Inform about environmental lighting conditions of a particular+        streetlight.+      contentType: application/json+      traits:+        - $ref: '#/components/messageTraits/commonHeaders'+      payload:+        $ref: '#/components/schemas/lightMeasuredPayload'+    turnOnOff:+      name: turnOnOff+      title: Turn on/off+      summary: Command a particular streetlight to turn the lights on or off.+      traits:+        - $ref: '#/components/messageTraits/commonHeaders'+      payload:+        $ref: '#/components/schemas/turnOnOffPayload'+    dimLight:+      name: dimLight+      title: Dim light+      summary: Command a particular streetlight to dim the lights.+      traits:+        - $ref: '#/components/messageTraits/commonHeaders'+      payload:+        $ref: '#/components/schemas/dimLightPayload'+  schemas:+    lightMeasuredPayload:+      type: object+      properties:+        lumens:+          type: integer+          minimum: 0+          description: Light intensity measured in lumens.+        sentAt:+          $ref: '#/components/schemas/sentAt'+    turnOnOffPayload:+      type: object+      properties:+        command:+          type: string+          enum:+            - 'on'+            - 'off'+          description: Whether to turn on or off the light.+        sentAt:+          $ref: '#/components/schemas/sentAt'+    dimLightPayload:+      type: object+      properties:+        percentage:+          type: integer+          description: Percentage to which the light should be dimmed to.+          minimum: 0+          maximum: 100+        sentAt:+          $ref: '#/components/schemas/sentAt'+    sentAt:+      type: string+      format: date-time+      description: Date and time when the message was sent.+  securitySchemes:+    saslScram:+      type: scramSha256+      description: Provide your username and password for SASL/SCRAM authentication+    streetlights_auth:+      type: oauth2+      description: The oauth security descriptions+      flows:+        clientCredentials:+          tokenUrl: 'https://example.com/api/oauth/dialog'+          availableScopes:+            'streetlights:read': Scope required for subscribing to channel+            'streetlights:write': Scope required for publishing to channel+  parameters:+    streetlightId:+      description: The ID of the streetlight.+  messageTraits:+    commonHeaders:+      headers:+        type: object+        properties:+          my-app-header:+            type: integer+            minimum: 0+            maximum: 100+  operationTraits:+    kafka:+      bindings:+        kafka:+          clientId:+            type: string+            enum:+              - my-app-id
+ reference/examples/websocket-gemini-asyncapi.yml view
@@ -0,0 +1,301 @@+asyncapi: 3.1.0+info:+  title: Gemini Market Data Websocket API+  version: 1.0.0+  description: >+    Market data is a public API that streams all the market data on a given+    symbol.+++    You can quickly play with the API using+    [websocat](https://github.com/vi/websocat#installation) like this:++    ```bash++    websocat wss://api.gemini.com/v1/marketdata/btcusd?heartbeat=true -S++    ```+  contact:+    name: Gemini+    url: 'https://www.gemini.com/'+  externalDocs:+    url: 'https://docs.sandbox.gemini.com/websocket-api/#market-data'+servers:+  public:+    host: api.gemini.com+    protocol: wss+channels:+  marketDataV1:+    address: '/v1/marketdata/{symbol}'+    messages:+      marketData:+        $ref: '#/components/messages/marketData'+    parameters:+      symbol:+        enum:+          - btcusd+          - ethbtc+          - ethusd+          - zecusd+          - zecbtc+          - zeceth+          - zecbch+          - zecltc+          - bchusd+          - bchbtc+          - bcheth+          - ltcusd+          - ltcbtc+          - ltceth+          - ltcbch+          - batusd+          - daiusd+          - linkusd+          - oxtusd+          - batbtc+          - linkbtc+          - oxtbtc+          - bateth+          - linketh+          - oxteth+          - ampusd+          - compusd+          - paxgusd+          - mkrusd+          - zrxusd+          - kncusd+          - manausd+          - storjusd+          - snxusd+          - crvusd+          - balusd+          - uniusd+          - renusd+          - umausd+          - yfiusd+          - btcdai+          - ethdai+          - aaveusd+          - filusd+          - btceur+          - btcgbp+          - etheur+          - ethgbp+          - btcsgd+          - ethsgd+          - sklusd+          - grtusd+          - bntusd+          - 1inchusd+          - enjusd+          - lrcusd+          - sandusd+          - cubeusd+          - lptusd+          - bondusd+          - maticusd+          - injusd+          - sushiusd+        description: >+          Symbols are formatted as CCY1CCY2 where prices are in CCY2 and+          quantities are in CCY1. To read more click+          [here](https://docs.sandbox.gemini.com/websocket-api/#symbols-and-minimums).+    bindings:+      ws:+        bindingVersion: 0.1.0+        query:+          type: object+          description: >+            The semantics of entry type filtering is:+++            If any entry type is specified as true or false, all of them must be+            explicitly flagged true to show up in the response++            If no entry types filtering parameters are included in the url, then+            all entry types will appear in the response+++            NOTE: top_of_book has no meaning and initial book events are empty+            when only trades is specified+          properties:+            heartbeat:+              type: boolean+              default: false+              description: >-+                Optionally add this parameter and set to true to receive a+                heartbeat every 5 seconds+            top_of_book:+              type: boolean+              default: false+              description: >-+                If absent or false, receive full order book depth; if present+                and true, receive top of book only. Only applies to bids and+                offers.+            bids:+              type: boolean+              default: true+              description: Include bids in change events+            offers:+              type: boolean+              default: true+              description: Include asks in change events+            trades:+              type: boolean+              default: true+              description: Include trade events+            auctions:+              type: boolean+              default: true+              description: Include auction events+operations:+  sendMarketData:+    action: send+    channel:+      $ref: '#/channels/marketDataV1'+    summary: Receive market updates on a given symbol+    messages:+      - $ref: '#/channels/marketDataV1/messages/marketData'+components:+  messages:+    marketData:+      summary: Message with marked data information.+      description: >+        The initial response message will show the existing state of the order+        book. Subsequent messages will show all executed trades, as well as all+        other changes to the order book from orders placed or canceled.+      payload:+        $ref: '#/components/schemas/market'+      examples:+        - name: updateMessage+          summary: >-+            Example of an update message that contains a change in price+            information.+          payload:+            type: update+            eventId: 36902233362+            timestamp: 1619769673+            timestampms: 1619769673527+            socket_sequence: 661+            events:+              - type: change+                side: bid+                price: 54350.40+                remaining: 0.002+                delta: 0.002+                reason: place+        - name: heartbeatMessage+          summary: Example of additional heartbeat message when you enable them.+          payload:+            type: heartbeat+            socket_sequence: 1656+  schemas:+    market:+      type: object+      oneOf:+        - $ref: '#/components/schemas/heartbeat'+        - $ref: '#/components/schemas/update'+    heartbeat:+      allOf:+        - properties:+            type:+              type: string+              const: heartbeat+          required:+            - type+        - $ref: '#/components/schemas/default'+    update:+      allOf:+        - properties:+            type:+              type: string+              const: update+            eventId:+              type: integer+              description: >-+                A monotonically increasing sequence number indicating when this+                change occurred. These numbers are persistent and consistent+                between market data connections.+            events:+              $ref: '#/components/schemas/events'+            timestamp:+              type: number+              description: >-+                The timestamp in seconds for this group of events (included for+                compatibility reasons). We recommend using the timestampms field+                instead.+            timestampms:+              type: number+              description: The timestamp in milliseconds for this group of events.+          required:+            - type+            - eventId+            - events+            - timestamp+            - timestampms+        - $ref: '#/components/schemas/default'+    default:+      type: object+      description: >-+        This object is always part of the payload. In case of type=heartbeat,+        these are the only fields.+      required:+        - type+        - socket_sequence+      properties:+        socket_sequence:+          type: integer+          description: >-+            zero-indexed monotonic increasing sequence number attached to each+            message sent - if there is a gap in this sequence, you have missed a+            message. If you choose to enable heartbeats, then heartbeat and+            update messages will share a single increasing sequence. See+            [Sequence+            Numbers](https://docs.sandbox.gemini.com/websocket-api/#sequence-numbers)+            for more information.+    events:+      type: array+      description: >-+        Either a change to the order book, or the indication that a trade has+        occurred.+      items:+        type: object+        additionalProperties: false+        properties:+          type:+            type: string+            enum:+              - trade+              - change+              - 'auction, block_trade'+          price:+            type: number+            multipleOf: 0.01+            description: The price of this order book entry.+          side:+            type: string+            enum:+              - bid+              - side+          reason:+            type: string+            enum:+              - place+              - trade+              - cancel+              - initial+            description: >-+              Indicates why the change has occurred. initial is for the initial+              response message, which will show the entire existing state of the+              order book.+          remaining:+            type: number+            description: >-+              The quantity remaining at that price level after this change+              occurred. May be zero if all orders at this price level have been+              filled or canceled.+          delta:+            type: number+            description: >-+              The quantity changed. May be negative, if an order is filled or+              canceled. For initial messages, delta will equal remaining.
+ src/Data/AsyncAPI.hs view
@@ -0,0 +1,48 @@+-- | Umbrella module for the AsyncAPI 3.1.0 data-model library.+--+-- Re-exports the model ('Data.AsyncAPI.Internal', 'Data.AsyncAPI.Internal.Schema',+-- 'Data.AsyncAPI.Internal.Types'), the ordered-encoding helpers, the validator,+-- and both optic interfaces.+--+-- == Optics+--+-- Both optic libraries are re-exported under their module names; import one+-- of 'Data.AsyncAPI.Lens' or 'Data.AsyncAPI.Optics' qualified to use the+-- prisms (they share constructor names with different types). The lens+-- field @id@ on 'AsyncAPI' shadows 'Prelude.id' when imported unqualified.+--+-- == Roundtrip contract+--+-- Aeson's key-map loses source order on decode, so every map-typed field and+-- every @x-@ extension map is re-inserted /sorted by key/ on decode; encoding+-- always emits fixed fields in the specification's table order, omits absent+-- optional fields, and appends @x-@ extensions last. The contract is:+-- structural 'Eq' equality plus byte-stable 'Data.Aeson.encode' output.+--+-- See the specification:+-- <https://www.asyncapi.com/docs/reference/specification/v3.1.0 AsyncAPI 3.1.0>.+module Data.AsyncAPI+  ( -- * Model+    module Data.AsyncAPI.Internal,+    module Data.AsyncAPI.Internal.Schema,+    module Data.AsyncAPI.Internal.Types,++    -- * Encoding helpers+    module Data.AsyncAPI.Internal.Encoding,++    -- * Validation+    module Data.AsyncAPI.Validation,++    -- * Optics+    module Data.AsyncAPI.Lens,+    module Data.AsyncAPI.Optics,+  )+where++import Data.AsyncAPI.Internal+import Data.AsyncAPI.Internal.Encoding+import Data.AsyncAPI.Internal.Schema+import Data.AsyncAPI.Internal.Types+import Data.AsyncAPI.Lens qualified+import Data.AsyncAPI.Optics qualified+import Data.AsyncAPI.Validation
+ src/Data/AsyncAPI/Internal.hs view
@@ -0,0 +1,2122 @@+-- | The AsyncAPI 3.1.0 object model. Each type mirrors one section of the+-- specification; field order in every 'ToJSON' instance follows the Fixed+-- Fields table of that section.+module Data.AsyncAPI.Internal+  ( -- * Root+    AsyncAPI (..),+    emptyAsyncAPI,++    -- * Info family+    Info (..),+    emptyInfo,+    Contact (..),+    emptyContact,+    License (..),+    emptyLicense,++    -- * Servers+    Servers,+    Server (..),+    emptyServer,+    ServerVariable (..),+    emptyServerVariable,++    -- * Channels+    Channels,+    Channel (..),+    emptyChannel,+    Parameters,+    Parameter (..),+    emptyParameter,++    -- * Messages+    Messages,+    Message (..),+    emptyMessage,+    MessageTrait (..),+    emptyMessageTrait,+    MessageExample (..),+    emptyMessageExample,+    CorrelationId (..),+    emptyCorrelationId,+    SchemaDefinition (..),++    -- * Operations+    Operations,+    Operation (..),+    emptyOperation,+    OperationAction (..),+    OperationTrait (..),+    emptyOperationTrait,+    OperationReply (..),+    emptyOperationReply,+    OperationReplyAddress (..),+    emptyOperationReplyAddress,++    -- * Shared metadata+    Tags,+    Tag (..),+    ExternalDocumentation (..),+    Reference (..),+    Referenced (..),++    -- * Security+    SecurityScheme (..),+    emptySecurityScheme,+    SecuritySchemeType (..),+    ApiKeyLocation (..),+    OAuthFlows (..),+    emptyOAuthFlows,+    OAuthFlow (..),+    emptyOAuthFlow,++    -- * Bindings+    ServerBindings (..),+    emptyServerBindings,+    ChannelBindings (..),+    emptyChannelBindings,+    OperationBindings (..),+    emptyOperationBindings,+    MessageBindings (..),+    emptyMessageBindings,++    -- * Schema formats+    MultiFormatSchema (..),+    emptyMultiFormatSchema,++    -- * Components+    Components (..),+    emptyComponents,++    -- * Encoding helpers (re-exported for instances in this module)+    module Data.AsyncAPI.Internal.Encoding,+    module Data.AsyncAPI.Internal.Types,+  )+where++import Data.Aeson (FromJSON (..), ToJSON (..), Value (..), withObject, withText, (.!=), (.:), (.:?))+import Data.Aeson.KeyMap qualified as KM+import Data.AsyncAPI.Internal.Encoding+import Data.AsyncAPI.Internal.Referenced+import Data.AsyncAPI.Internal.Schema+import Data.AsyncAPI.Internal.Types+import Data.HashMap.Strict.InsOrd (InsOrdHashMap)+import Data.HashMap.Strict.InsOrd qualified as InsOrd+import Data.Text (Text)+import GHC.Generics (Generic)++-- $ root+--+-- [AsyncAPI 3.1.0 — AsyncAPI Object](https://www.asyncapi.com/docs/reference/specification/v3.1.0#A2SObject)++-- | The root document object of an AsyncAPI 3.1.0 document.+--+-- [AsyncAPI 3.1.0 — AsyncAPI Object](https://www.asyncapi.com/docs/reference/specification/v3.1.0#A2SObject)+data AsyncAPI = AsyncAPI+  { -- | **REQUIRED.** Specification version.+    -- [AsyncAPI Version String](https://www.asyncapi.com/docs/reference/specification/v3.1.0#A2SVersionString)+    _asyncAPIAsyncAPI :: Version,+    -- | Application identifier.+    -- [Identifier](https://www.asyncapi.com/docs/reference/specification/v3.1.0#A2SIdString)+    _asyncAPIId :: Maybe Id,+    -- | **REQUIRED.** Metadata about the API.+    -- [Info Object](https://www.asyncapi.com/docs/reference/specification/v3.1.0#infoObject)+    _asyncAPIInfo :: Info,+    -- | Connection details of servers.+    -- [Servers Object](https://www.asyncapi.com/docs/reference/specification/v3.1.0#serversObject)+    _asyncAPIServers :: Maybe Servers,+    -- | Default content type for message payloads.+    -- [Default Content Type](https://www.asyncapi.com/docs/reference/specification/v3.1.0#defaultContentTypeString)+    _asyncAPIDefaultContentType :: Maybe ContentType,+    -- | The channels used by this application.+    -- [Channels Object](https://www.asyncapi.com/docs/reference/specification/v3.1.0#channelsObject)+    _asyncAPIChannels :: Maybe Channels,+    -- | The operations this application MUST implement.+    -- [Operations Object](https://www.asyncapi.com/docs/reference/specification/v3.1.0#operationsObject)+    _asyncAPIOperations :: Maybe Operations,+    -- | Reusable objects.+    -- [Components Object](https://www.asyncapi.com/docs/reference/specification/v3.1.0#componentsObject)+    _asyncAPIComponents :: Maybe Components,+    -- | Specification extensions (@x-@).+    -- [Specification Extensions](https://www.asyncapi.com/docs/reference/specification/v3.1.0#specificationExtensions)+    _asyncAPIExtensions :: InsOrdHashMap Text Value+  }+  deriving (Eq, Show, Generic)++-- | A document with only the required fields set.+emptyAsyncAPI :: Version -> Info -> AsyncAPI+emptyAsyncAPI v i =+  AsyncAPI+    { _asyncAPIAsyncAPI = v,+      _asyncAPIId = Nothing,+      _asyncAPIInfo = i,+      _asyncAPIServers = Nothing,+      _asyncAPIDefaultContentType = Nothing,+      _asyncAPIChannels = Nothing,+      _asyncAPIOperations = Nothing,+      _asyncAPIComponents = Nothing,+      _asyncAPIExtensions = InsOrd.empty+    }++instance ToJSON AsyncAPI where+  toJSON = jsonViaEncoding+  toEncoding AsyncAPI {..} =+    recordEncoding+      _asyncAPIExtensions+      [ "asyncapi" .=? Just _asyncAPIAsyncAPI,+        "id" .=? _asyncAPIId,+        "info" .=? Just _asyncAPIInfo,+        "servers" .=? fmap SortedObject _asyncAPIServers,+        "defaultContentType" .=? _asyncAPIDefaultContentType,+        "channels" .=? fmap SortedObject _asyncAPIChannels,+        "operations" .=? fmap SortedObject _asyncAPIOperations,+        "components" .=? _asyncAPIComponents+      ]++instance FromJSON AsyncAPI where+  parseJSON = withObject "AsyncAPI" $ \o -> do+    _asyncAPIAsyncAPI <- o .: "asyncapi"+    _asyncAPIId <- o .:? "id"+    _asyncAPIInfo <- o .: "info"+    _asyncAPIServers <- sortedMapField "servers" o+    _asyncAPIDefaultContentType <- o .:? "defaultContentType"+    _asyncAPIChannels <- sortedMapField "channels" o+    _asyncAPIOperations <- sortedMapField "operations" o+    _asyncAPIComponents <- o .:? "components"+    let _asyncAPIExtensions = parseExtensions o+    pure AsyncAPI {..}++-- $ info+--+-- [AsyncAPI 3.1.0 — Info Object](https://www.asyncapi.com/docs/reference/specification/v3.1.0#infoObject)++-- | Metadata about the API.+--+-- [AsyncAPI 3.1.0 — Info Object](https://www.asyncapi.com/docs/reference/specification/v3.1.0#infoObject)+data Info = Info+  { -- | **REQUIRED.** The title of the application.+    _infoTitle :: Title,+    -- | **REQUIRED.** The version of the application API.+    _infoVersion :: Version,+    -- | A short description of the application.+    _infoDescription :: Maybe Description,+    -- | A URL to the Terms of Service.+    _infoTermsOfService :: Maybe Url,+    -- | Contact information.+    -- [Contact Object](https://www.asyncapi.com/docs/reference/specification/v3.1.0#contactObject)+    _infoContact :: Maybe Contact,+    -- | License information.+    -- [License Object](https://www.asyncapi.com/docs/reference/specification/v3.1.0#licenseObject)+    _infoLicense :: Maybe License,+    -- | A list of tags.+    -- [Tags Object](https://www.asyncapi.com/docs/reference/specification/v3.1.0#tagsObject)+    _infoTags :: Maybe Tags,+    -- | Additional external documentation.+    -- [External Documentation Object](https://www.asyncapi.com/docs/reference/specification/v3.1.0#externalDocumentationObject)+    _infoExternalDocs :: Maybe (Referenced ExternalDocumentation),+    -- | Specification extensions (@x-@).+    _infoExtensions :: InsOrdHashMap Text Value+  }+  deriving (Eq, Show, Generic)++instance ToJSON Info where+  toJSON = jsonViaEncoding+  toEncoding Info {..} =+    recordEncoding+      _infoExtensions+      [ "title" .=? Just _infoTitle,+        "version" .=? Just _infoVersion,+        "description" .=? _infoDescription,+        "termsOfService" .=? _infoTermsOfService,+        "contact" .=? _infoContact,+        "license" .=? _infoLicense,+        "tags" .=? _infoTags,+        "externalDocs" .=? _infoExternalDocs+      ]++instance FromJSON Info where+  parseJSON = withObject "Info" $ \o -> do+    _infoTitle <- o .: "title"+    _infoVersion <- o .: "version"+    _infoDescription <- o .:? "description"+    _infoTermsOfService <- o .:? "termsOfService"+    _infoContact <- o .:? "contact"+    _infoLicense <- o .:? "license"+    _infoTags <- o .:? "tags"+    _infoExternalDocs <- o .:? "externalDocs"+    let _infoExtensions = parseExtensions o+    pure Info {..}++-- | An 'Info' with only the required fields set.+emptyInfo :: Title -> Version -> Info+emptyInfo t v =+  Info+    { _infoTitle = t,+      _infoVersion = v,+      _infoDescription = Nothing,+      _infoTermsOfService = Nothing,+      _infoContact = Nothing,+      _infoLicense = Nothing,+      _infoTags = Nothing,+      _infoExternalDocs = Nothing,+      _infoExtensions = InsOrd.empty+    }++-- | Contact information for the exposed API.+--+-- [AsyncAPI 3.1.0 — Contact Object](https://www.asyncapi.com/docs/reference/specification/v3.1.0#contactObject)+data Contact = Contact+  { -- | The identifying name of the contact person\/organization.+    _contactName :: Maybe Name,+    -- | The URL pointing to the contact information.+    _contactUrl :: Maybe Url,+    -- | The email address of the contact person\/organization.+    _contactEmail :: Maybe Text,+    -- | Specification extensions (@x-@).+    _contactExtensions :: InsOrdHashMap Text Value+  }+  deriving (Eq, Show, Generic)++instance ToJSON Contact where+  toJSON = jsonViaEncoding+  toEncoding Contact {..} =+    recordEncoding+      _contactExtensions+      [ "name" .=? _contactName,+        "url" .=? _contactUrl,+        "email" .=? _contactEmail+      ]++instance FromJSON Contact where+  parseJSON = withObject "Contact" $ \o -> do+    _contactName <- o .:? "name"+    _contactUrl <- o .:? "url"+    _contactEmail <- o .:? "email"+    let _contactExtensions = parseExtensions o+    pure Contact {..}++-- | A 'Contact' with only the required fields set.+emptyContact :: Contact+emptyContact =+  Contact+    { _contactName = Nothing,+      _contactUrl = Nothing,+      _contactEmail = Nothing,+      _contactExtensions = InsOrd.empty+    }++-- | License information for the exposed API.+--+-- [AsyncAPI 3.1.0 — License Object](https://www.asyncapi.com/docs/reference/specification/v3.1.0#licenseObject)+data License = License+  { -- | **REQUIRED.** The license name used for the API.+    _licenseName :: Name,+    -- | A URL to the license used for the API.+    _licenseUrl :: Maybe Url,+    -- | Specification extensions (@x-@).+    _licenseExtensions :: InsOrdHashMap Text Value+  }+  deriving (Eq, Show, Generic)++instance ToJSON License where+  toJSON = jsonViaEncoding+  toEncoding License {..} =+    recordEncoding+      _licenseExtensions+      [ "name" .=? Just _licenseName,+        "url" .=? _licenseUrl+      ]++instance FromJSON License where+  parseJSON = withObject "License" $ \o -> do+    _licenseName <- o .: "name"+    _licenseUrl <- o .:? "url"+    let _licenseExtensions = parseExtensions o+    pure License {..}++-- | A 'License' with only the required fields set.+emptyLicense :: Name -> License+emptyLicense n =+  License+    { _licenseName = n,+      _licenseUrl = Nothing,+      _licenseExtensions = InsOrd.empty+    }++-- $ servers+--+-- [AsyncAPI 3.1.0 — Servers Object](https://www.asyncapi.com/docs/reference/specification/v3.1.0#serversObject)++-- | A map of server names to (possibly referenced) servers.+--+-- [AsyncAPI 3.1.0 — Servers Object](https://www.asyncapi.com/docs/reference/specification/v3.1.0#serversObject)+type Servers = InsOrdHashMap Text (Referenced Server)++-- | A message broker, server, or other program capable of sending and\/or+-- receiving data.+--+-- [AsyncAPI 3.1.0 — Server Object](https://www.asyncapi.com/docs/reference/specification/v3.1.0#serverObject)+data Server = Server+  { -- | **REQUIRED.** The server host name; MAY include the port.+    _serverHost :: Text,+    -- | **REQUIRED.** The protocol this server supports for connection.+    _serverProtocol :: Text,+    -- | The version of the protocol used for connection.+    _serverProtocolVersion :: Maybe Version,+    -- | The path to a resource in the host.+    _serverPathname :: Maybe Text,+    -- | An optional string describing the server.+    _serverDescription :: Maybe Description,+    -- | A human-friendly title for the server.+    _serverTitle :: Maybe Title,+    -- | A short summary of the server.+    _serverSummary :: Maybe Summary,+    -- | A map between a variable name and its value.+    -- [Server Variable Object](https://www.asyncapi.com/docs/reference/specification/v3.1.0#serverVariableObject)+    _serverVariables :: Maybe (InsOrdHashMap Text (Referenced ServerVariable)),+    -- | A declaration of which security schemes can be used with this server.+    -- [Security Scheme Object](https://www.asyncapi.com/docs/reference/specification/v3.1.0#securitySchemeObject)+    _serverSecurity :: Maybe [Referenced SecurityScheme],+    -- | A list of tags for logical grouping of servers.+    -- [Tags Object](https://www.asyncapi.com/docs/reference/specification/v3.1.0#tagsObject)+    _serverTags :: Maybe Tags,+    -- | Additional external documentation for this server.+    _serverExternalDocs :: Maybe (Referenced ExternalDocumentation),+    -- | Protocol-specific definitions for the server.+    -- [Server Bindings Object](https://www.asyncapi.com/docs/reference/specification/v3.1.0#serverBindingsObject)+    _serverBindings :: Maybe (Referenced ServerBindings),+    -- | Specification extensions (@x-@).+    _serverExtensions :: InsOrdHashMap Text Value+  }+  deriving (Eq, Show, Generic)++instance ToJSON Server where+  toJSON = jsonViaEncoding+  toEncoding Server {..} =+    recordEncoding+      _serverExtensions+      [ "host" .=? Just _serverHost,+        "protocol" .=? Just _serverProtocol,+        "protocolVersion" .=? _serverProtocolVersion,+        "pathname" .=? _serverPathname,+        "description" .=? _serverDescription,+        "title" .=? _serverTitle,+        "summary" .=? _serverSummary,+        "variables" .=? fmap SortedObject _serverVariables,+        "security" .=? _serverSecurity,+        "tags" .=? _serverTags,+        "externalDocs" .=? _serverExternalDocs,+        "bindings" .=? _serverBindings+      ]++instance FromJSON Server where+  parseJSON = withObject "Server" $ \o -> do+    _serverHost <- o .: "host"+    _serverProtocol <- o .: "protocol"+    _serverProtocolVersion <- o .:? "protocolVersion"+    _serverPathname <- o .:? "pathname"+    _serverDescription <- o .:? "description"+    _serverTitle <- o .:? "title"+    _serverSummary <- o .:? "summary"+    _serverVariables <- sortedMapField "variables" o+    _serverSecurity <- o .:? "security"+    _serverTags <- o .:? "tags"+    _serverExternalDocs <- o .:? "externalDocs"+    _serverBindings <- o .:? "bindings"+    let _serverExtensions = parseExtensions o+    pure Server {..}++-- | A 'Server' with only the required fields set.+emptyServer :: Text -> Text -> Server+emptyServer h p =+  Server+    { _serverHost = h,+      _serverProtocol = p,+      _serverProtocolVersion = Nothing,+      _serverPathname = Nothing,+      _serverDescription = Nothing,+      _serverTitle = Nothing,+      _serverSummary = Nothing,+      _serverVariables = Nothing,+      _serverSecurity = Nothing,+      _serverTags = Nothing,+      _serverExternalDocs = Nothing,+      _serverBindings = Nothing,+      _serverExtensions = InsOrd.empty+    }++-- | A server variable for URL template substitution.+--+-- [AsyncAPI 3.1.0 — Server Variable Object](https://www.asyncapi.com/docs/reference/specification/v3.1.0#serverVariableObject)+data ServerVariable = ServerVariable+  { -- | An enumeration of string values for substitution.+    _serverVariableEnum :: Maybe [Text],+    -- | The default value to use for substitution.+    _serverVariableDefault :: Maybe Text,+    -- | An optional description for the server variable.+    _serverVariableDescription :: Maybe Description,+    -- | An array of examples of the server variable.+    _serverVariableExamples :: Maybe [Text],+    -- | Specification extensions (@x-@).+    _serverVariableExtensions :: InsOrdHashMap Text Value+  }+  deriving (Eq, Show, Generic)++instance ToJSON ServerVariable where+  toJSON = jsonViaEncoding+  toEncoding ServerVariable {..} =+    recordEncoding+      _serverVariableExtensions+      [ "enum" .=? _serverVariableEnum,+        "default" .=? _serverVariableDefault,+        "description" .=? _serverVariableDescription,+        "examples" .=? _serverVariableExamples+      ]++instance FromJSON ServerVariable where+  parseJSON = withObject "ServerVariable" $ \o -> do+    _serverVariableEnum <- o .:? "enum"+    _serverVariableDefault <- o .:? "default"+    _serverVariableDescription <- o .:? "description"+    _serverVariableExamples <- o .:? "examples"+    let _serverVariableExtensions = parseExtensions o+    pure ServerVariable {..}++-- | A 'ServerVariable' with only the required fields set.+emptyServerVariable :: ServerVariable+emptyServerVariable =+  ServerVariable+    { _serverVariableEnum = Nothing,+      _serverVariableDefault = Nothing,+      _serverVariableDescription = Nothing,+      _serverVariableExamples = Nothing,+      _serverVariableExtensions = InsOrd.empty+    }++-- $ channels+--+-- [AsyncAPI 3.1.0 — Channels Object](https://www.asyncapi.com/docs/reference/specification/v3.1.0#channelsObject)++-- | A map of channel identifiers to (possibly referenced) channels.+--+-- [AsyncAPI 3.1.0 — Channels Object](https://www.asyncapi.com/docs/reference/specification/v3.1.0#channelsObject)+type Channels = InsOrdHashMap Text (Referenced Channel)++-- | A shared communication channel.+--+-- [AsyncAPI 3.1.0 — Channel Object](https://www.asyncapi.com/docs/reference/specification/v3.1.0#channelObject)+data Channel = Channel+  { -- | This channel's address (@null@ or absent = unknown).+    _channelAddress :: Maybe (Maybe Text),+    -- | Messages that will be sent to this channel.+    -- [Messages Object](https://www.asyncapi.com/docs/reference/specification/v3.1.0#messagesObject)+    _channelMessages :: Maybe Messages,+    -- | A human-friendly title for the channel.+    _channelTitle :: Maybe Title,+    -- | A short summary of the channel.+    _channelSummary :: Maybe Summary,+    -- | An optional description of this channel.+    _channelDescription :: Maybe Description,+    -- | @$ref@ pointers to the servers in which this channel is available.+    _channelServers :: Maybe [Reference],+    -- | Parameters included in the channel address.+    -- [Parameters Object](https://www.asyncapi.com/docs/reference/specification/v3.1.0#parametersObject)+    _channelParameters :: Maybe Parameters,+    -- | A list of tags for logical grouping of channels.+    _channelTags :: Maybe Tags,+    -- | Additional external documentation for this channel.+    _channelExternalDocs :: Maybe (Referenced ExternalDocumentation),+    -- | Protocol-specific definitions for the channel.+    -- [Channel Bindings Object](https://www.asyncapi.com/docs/reference/specification/v3.1.0#channelBindingsObject)+    _channelBindings :: Maybe (Referenced ChannelBindings),+    -- | Specification extensions (@x-@).+    _channelExtensions :: InsOrdHashMap Text Value+  }+  deriving (Eq, Show, Generic)++instance ToJSON Channel where+  toJSON = jsonViaEncoding+  toEncoding Channel {..} =+    recordEncoding+      _channelExtensions+      [ "address" .=? _channelAddress,+        "messages" .=? fmap SortedObject _channelMessages,+        "title" .=? _channelTitle,+        "summary" .=? _channelSummary,+        "description" .=? _channelDescription,+        "servers" .=? _channelServers,+        "parameters" .=? fmap SortedObject _channelParameters,+        "tags" .=? _channelTags,+        "externalDocs" .=? _channelExternalDocs,+        "bindings" .=? _channelBindings+      ]++instance FromJSON Channel where+  parseJSON = withObject "Channel" $ \o -> do+    _channelAddress <- o .:? "address"+    _channelMessages <- sortedMapField "messages" o+    _channelTitle <- o .:? "title"+    _channelSummary <- o .:? "summary"+    _channelDescription <- o .:? "description"+    _channelServers <- o .:? "servers"+    _channelParameters <- sortedMapField "parameters" o+    _channelTags <- o .:? "tags"+    _channelExternalDocs <- o .:? "externalDocs"+    _channelBindings <- o .:? "bindings"+    let _channelExtensions = parseExtensions o+    pure Channel {..}++-- | A 'Channel' with only the required fields set.+emptyChannel :: Channel+emptyChannel =+  Channel+    { _channelAddress = Nothing,+      _channelMessages = Nothing,+      _channelTitle = Nothing,+      _channelSummary = Nothing,+      _channelDescription = Nothing,+      _channelServers = Nothing,+      _channelParameters = Nothing,+      _channelTags = Nothing,+      _channelExternalDocs = Nothing,+      _channelBindings = Nothing,+      _channelExtensions = InsOrd.empty+    }++-- | A map of parameter names to (possibly referenced) parameters.+--+-- [AsyncAPI 3.1.0 — Parameters Object](https://www.asyncapi.com/docs/reference/specification/v3.1.0#parametersObject)+type Parameters = InsOrdHashMap Text (Referenced Parameter)++-- | A parameter included in a channel address.+--+-- [AsyncAPI 3.1.0 — Parameter Object](https://www.asyncapi.com/docs/reference/specification/v3.1.0#parameterObject)+data Parameter = Parameter+  { -- | An enumeration of string values for substitution.+    _parameterEnum :: Maybe [Text],+    -- | The default value to use for substitution.+    _parameterDefault :: Maybe Text,+    -- | An optional description for the parameter.+    _parameterDescription :: Maybe Description,+    -- | An array of examples of the parameter value.+    _parameterExamples :: Maybe [Text],+    -- | A runtime expression specifying the location of the parameter value.+    -- [Runtime Expression](https://www.asyncapi.com/docs/reference/specification/v3.1.0#runtimeExpression)+    _parameterLocation :: Maybe RuntimeExpression,+    -- | Specification extensions (@x-@).+    _parameterExtensions :: InsOrdHashMap Text Value+  }+  deriving (Eq, Show, Generic)++instance ToJSON Parameter where+  toJSON = jsonViaEncoding+  toEncoding Parameter {..} =+    recordEncoding+      _parameterExtensions+      [ "enum" .=? _parameterEnum,+        "default" .=? _parameterDefault,+        "description" .=? _parameterDescription,+        "examples" .=? _parameterExamples,+        "location" .=? _parameterLocation+      ]++instance FromJSON Parameter where+  parseJSON = withObject "Parameter" $ \o -> do+    _parameterEnum <- o .:? "enum"+    _parameterDefault <- o .:? "default"+    _parameterDescription <- o .:? "description"+    _parameterExamples <- o .:? "examples"+    _parameterLocation <- o .:? "location"+    let _parameterExtensions = parseExtensions o+    pure Parameter {..}++-- | A 'Parameter' with only the required fields set.+emptyParameter :: Parameter+emptyParameter =+  Parameter+    { _parameterEnum = Nothing,+      _parameterDefault = Nothing,+      _parameterDescription = Nothing,+      _parameterExamples = Nothing,+      _parameterLocation = Nothing,+      _parameterExtensions = InsOrd.empty+    }++-- $ security+--+-- [AsyncAPI 3.1.0 — Security Scheme Object](https://www.asyncapi.com/docs/reference/specification/v3.1.0#securitySchemeObject)++-- | The type of a security scheme; the valid values are exactly the ones+-- listed in the Security Scheme Object section.+--+-- [Security Scheme Object](https://www.asyncapi.com/docs/reference/specification/v3.1.0#securitySchemeObjectType)+data SecuritySchemeType+  = UserPassword+  | ApiKey+  | X509+  | SymmetricEncryption+  | AsymmetricEncryption+  | HttpApiKey+  | Http+  | OAuth2+  | OpenIdConnect+  | Plain+  | ScramSha256+  | ScramSha512+  | Gssapi+  deriving (Eq, Show, Generic)++instance ToJSON SecuritySchemeType where+  toJSON = jsonViaEncoding+  toEncoding t = toEncoding (securitySchemeTypeText t)++instance FromJSON SecuritySchemeType where+  parseJSON = withText "SecuritySchemeType" $ \t ->+    case securitySchemeTypeFromText t of+      Just st -> pure st+      Nothing -> fail ("unknown security scheme type: " <> show t)++securitySchemeTypeText :: SecuritySchemeType -> Text+securitySchemeTypeText = \case+  UserPassword -> "userPassword"+  ApiKey -> "apiKey"+  X509 -> "X509"+  SymmetricEncryption -> "symmetricEncryption"+  AsymmetricEncryption -> "asymmetricEncryption"+  HttpApiKey -> "httpApiKey"+  Http -> "http"+  OAuth2 -> "oauth2"+  OpenIdConnect -> "openIdConnect"+  Plain -> "plain"+  ScramSha256 -> "scramSha256"+  ScramSha512 -> "scramSha512"+  Gssapi -> "gssapi"++securitySchemeTypeFromText :: Text -> Maybe SecuritySchemeType+securitySchemeTypeFromText = \case+  "userPassword" -> Just UserPassword+  "apiKey" -> Just ApiKey+  "X509" -> Just X509+  "symmetricEncryption" -> Just SymmetricEncryption+  "asymmetricEncryption" -> Just AsymmetricEncryption+  "httpApiKey" -> Just HttpApiKey+  "http" -> Just Http+  "oauth2" -> Just OAuth2+  "openIdConnect" -> Just OpenIdConnect+  "plain" -> Just Plain+  "scramSha256" -> Just ScramSha256+  "scramSha512" -> Just ScramSha512+  "gssapi" -> Just Gssapi+  _ -> Nothing++-- | The location of an API key.+--+-- [Security Scheme Object](https://www.asyncapi.com/docs/reference/specification/v3.1.0#securitySchemeObjectIn)+data ApiKeyLocation+  = -- | @user@ (only for @apiKey@).+    InUser+  | -- | @password@ (only for @apiKey@).+    InPassword+  | -- | @query@ (only for @httpApiKey@).+    InQuery+  | -- | @header@ (only for @httpApiKey@).+    InHeader+  | -- | @cookie@ (only for @httpApiKey@).+    InCookie+  deriving (Eq, Show, Generic)++instance ToJSON ApiKeyLocation where+  toJSON = jsonViaEncoding+  toEncoding l = toEncoding $ case l of+    InUser -> "user" :: Text+    InPassword -> "password"+    InQuery -> "query"+    InHeader -> "header"+    InCookie -> "cookie"++instance FromJSON ApiKeyLocation where+  parseJSON = withText "ApiKeyLocation" $ \case+    "user" -> pure InUser+    "password" -> pure InPassword+    "query" -> pure InQuery+    "header" -> pure InHeader+    "cookie" -> pure InCookie+    t -> fail ("unknown API key location: " <> show t)++-- | Defines a security scheme that can be used by the operations.+--+-- [AsyncAPI 3.1.0 — Security Scheme Object](https://www.asyncapi.com/docs/reference/specification/v3.1.0#securitySchemeObject)+data SecurityScheme = SecurityScheme+  { -- | **REQUIRED.** The type of the security scheme.+    -- [Security Scheme Object](https://www.asyncapi.com/docs/reference/specification/v3.1.0#securitySchemeObjectType)+    _securitySchemeType :: SecuritySchemeType,+    -- | A short description for the security scheme.+    _securitySchemeDescription :: Maybe Description,+    -- | **REQUIRED** for @httpApiKey@: the name of the header, query or+    -- cookie parameter to be used.+    _securitySchemeName :: Maybe Name,+    -- | **REQUIRED** for @apiKey@ and @httpApiKey@: the location of the API key.+    _securitySchemeIn :: Maybe ApiKeyLocation,+    -- | **REQUIRED** for @http@: the HTTP Authorization scheme name.+    _securitySchemeScheme :: Maybe Text,+    -- | A hint to the client on the bearer token format.+    _securitySchemeBearerFormat :: Maybe Text,+    -- | **REQUIRED** for @oauth2@: configuration of the supported flows.+    -- [OAuth Flows Object](https://www.asyncapi.com/docs/reference/specification/v3.1.0#oauthFlowsObject)+    _securitySchemeFlows :: Maybe OAuthFlows,+    -- | **REQUIRED** for @openIdConnect@: the OpenId Connect URL.+    _securitySchemeOpenIdConnectUrl :: Maybe Url,+    -- | The needed scope names; an empty list means no scopes are needed.+    _securitySchemeScopes :: Maybe [Text],+    -- | Specification extensions (@x-@).+    _securitySchemeExtensions :: InsOrdHashMap Text Value+  }+  deriving (Eq, Show, Generic)++instance ToJSON SecurityScheme where+  toJSON = jsonViaEncoding+  toEncoding SecurityScheme {..} =+    recordEncoding+      _securitySchemeExtensions+      [ "type" .=? Just _securitySchemeType,+        "description" .=? _securitySchemeDescription,+        "name" .=? _securitySchemeName,+        "in" .=? _securitySchemeIn,+        "scheme" .=? _securitySchemeScheme,+        "bearerFormat" .=? _securitySchemeBearerFormat,+        "flows" .=? _securitySchemeFlows,+        "openIdConnectUrl" .=? _securitySchemeOpenIdConnectUrl,+        "scopes" .=? _securitySchemeScopes+      ]++instance FromJSON SecurityScheme where+  parseJSON = withObject "SecurityScheme" $ \o -> do+    _securitySchemeType <- o .: "type"+    _securitySchemeDescription <- o .:? "description"+    _securitySchemeName <- o .:? "name"+    _securitySchemeIn <- o .:? "in"+    _securitySchemeScheme <- o .:? "scheme"+    _securitySchemeBearerFormat <- o .:? "bearerFormat"+    _securitySchemeFlows <- o .:? "flows"+    _securitySchemeOpenIdConnectUrl <- o .:? "openIdConnectUrl"+    _securitySchemeScopes <- o .:? "scopes"+    let _securitySchemeExtensions = parseExtensions o+    pure SecurityScheme {..}++-- | A 'SecurityScheme' with only the required fields set.+emptySecurityScheme :: SecuritySchemeType -> SecurityScheme+emptySecurityScheme t =+  SecurityScheme+    { _securitySchemeType = t,+      _securitySchemeDescription = Nothing,+      _securitySchemeName = Nothing,+      _securitySchemeIn = Nothing,+      _securitySchemeScheme = Nothing,+      _securitySchemeBearerFormat = Nothing,+      _securitySchemeFlows = Nothing,+      _securitySchemeOpenIdConnectUrl = Nothing,+      _securitySchemeScopes = Nothing,+      _securitySchemeExtensions = InsOrd.empty+    }++-- | Configuration of the supported OAuth flows.+--+-- [AsyncAPI 3.1.0 — OAuth Flows Object](https://www.asyncapi.com/docs/reference/specification/v3.1.0#oauthFlowsObject)+data OAuthFlows = OAuthFlows+  { -- | Configuration for the OAuth Implicit flow.+    _oAuthFlowsImplicit :: Maybe OAuthFlow,+    -- | Configuration for the OAuth Resource Owner Protected Credentials flow.+    _oAuthFlowsPassword :: Maybe OAuthFlow,+    -- | Configuration for the OAuth Client Credentials flow.+    _oAuthFlowsClientCredentials :: Maybe OAuthFlow,+    -- | Configuration for the OAuth Authorization Code flow.+    _oAuthFlowsAuthorizationCode :: Maybe OAuthFlow,+    -- | Specification extensions (@x-@).+    _oAuthFlowsExtensions :: InsOrdHashMap Text Value+  }+  deriving (Eq, Show, Generic)++instance ToJSON OAuthFlows where+  toJSON = jsonViaEncoding+  toEncoding OAuthFlows {..} =+    recordEncoding+      _oAuthFlowsExtensions+      [ "implicit" .=? _oAuthFlowsImplicit,+        "password" .=? _oAuthFlowsPassword,+        "clientCredentials" .=? _oAuthFlowsClientCredentials,+        "authorizationCode" .=? _oAuthFlowsAuthorizationCode+      ]++instance FromJSON OAuthFlows where+  parseJSON = withObject "OAuthFlows" $ \o -> do+    _oAuthFlowsImplicit <- o .:? "implicit"+    _oAuthFlowsPassword <- o .:? "password"+    _oAuthFlowsClientCredentials <- o .:? "clientCredentials"+    _oAuthFlowsAuthorizationCode <- o .:? "authorizationCode"+    let _oAuthFlowsExtensions = parseExtensions o+    pure OAuthFlows {..}++-- | An 'OAuthFlows' with only the required fields set.+emptyOAuthFlows :: OAuthFlows+emptyOAuthFlows =+  OAuthFlows+    { _oAuthFlowsImplicit = Nothing,+      _oAuthFlowsPassword = Nothing,+      _oAuthFlowsClientCredentials = Nothing,+      _oAuthFlowsAuthorizationCode = Nothing,+      _oAuthFlowsExtensions = InsOrd.empty+    }++-- | Configuration details for a supported OAuth flow.+--+-- [AsyncAPI 3.1.0 — OAuth Flow Object](https://www.asyncapi.com/docs/reference/specification/v3.1.0#oauthFlowObject)+data OAuthFlow = OAuthFlow+  { -- | **REQUIRED** for @implicit@ and @authorizationCode@: the+    -- authorization URL.+    _oAuthFlowAuthorizationUrl :: Maybe Url,+    -- | **REQUIRED** for @password@, @clientCredentials@ and+    -- @authorizationCode@: the token URL.+    _oAuthFlowTokenUrl :: Maybe Url,+    -- | The URL for obtaining refresh tokens.+    _oAuthFlowRefreshUrl :: Maybe Url,+    -- | **REQUIRED.** The available scopes with a short description each+    -- (JSON key @availableScopes@).+    _oAuthFlowAvailableScopes :: InsOrdHashMap Text Text,+    -- | Specification extensions (@x-@).+    _oAuthFlowExtensions :: InsOrdHashMap Text Value+  }+  deriving (Eq, Show, Generic)++instance ToJSON OAuthFlow where+  toJSON = jsonViaEncoding+  toEncoding OAuthFlow {..} =+    recordEncoding+      _oAuthFlowExtensions+      [ "authorizationUrl" .=? _oAuthFlowAuthorizationUrl,+        "tokenUrl" .=? _oAuthFlowTokenUrl,+        "refreshUrl" .=? _oAuthFlowRefreshUrl,+        "availableScopes" .=? Just (SortedObject _oAuthFlowAvailableScopes)+      ]++instance FromJSON OAuthFlow where+  parseJSON = withObject "OAuthFlow" $ \o -> do+    _oAuthFlowAuthorizationUrl <- o .:? "authorizationUrl"+    _oAuthFlowTokenUrl <- o .:? "tokenUrl"+    _oAuthFlowRefreshUrl <- o .:? "refreshUrl"+    _oAuthFlowAvailableScopes <-+      sortInsOrd . unSortedObject <$> (o .: "availableScopes" .!= SortedObject InsOrd.empty)+    let _oAuthFlowExtensions = parseExtensions o+    pure OAuthFlow {..}++-- | An 'OAuthFlow' with only the required fields set.+emptyOAuthFlow :: InsOrdHashMap Text Text -> OAuthFlow+emptyOAuthFlow scopes =+  OAuthFlow+    { _oAuthFlowAuthorizationUrl = Nothing,+      _oAuthFlowTokenUrl = Nothing,+      _oAuthFlowRefreshUrl = Nothing,+      _oAuthFlowAvailableScopes = scopes,+      _oAuthFlowExtensions = InsOrd.empty+    }++-- $ bindings+--+-- Protocol binding internals are defined by the external+-- [asyncapi\/bindings](https://github.com/asyncapi/bindings) repository, so+-- each protocol's value is kept opaque as a JSON 'Value'.++-- | Protocol-specific definitions for a server.+--+-- [AsyncAPI 3.1.0 — Server Bindings Object](https://www.asyncapi.com/docs/reference/specification/v3.1.0#serverBindingsObject)+data ServerBindings = ServerBindings+  { _serverBindingsHttp :: Maybe Value,+    _serverBindingsWs :: Maybe Value,+    _serverBindingsKafka :: Maybe Value,+    _serverBindingsAnypointmq :: Maybe Value,+    _serverBindingsAmqp :: Maybe Value,+    _serverBindingsAmqp1 :: Maybe Value,+    _serverBindingsMqtt :: Maybe Value,+    _serverBindingsMqtt5 :: Maybe Value,+    _serverBindingsNats :: Maybe Value,+    _serverBindingsJms :: Maybe Value,+    _serverBindingsSns :: Maybe Value,+    _serverBindingsSolace :: Maybe Value,+    _serverBindingsSqs :: Maybe Value,+    _serverBindingsStomp :: Maybe Value,+    _serverBindingsRedis :: Maybe Value,+    _serverBindingsMercure :: Maybe Value,+    _serverBindingsIbmmq :: Maybe Value,+    _serverBindingsGooglepubsub :: Maybe Value,+    _serverBindingsPulsar :: Maybe Value,+    _serverBindingsRos2 :: Maybe Value,+    _serverBindingsExtensions :: InsOrdHashMap Text Value+  }+  deriving (Eq, Show, Generic)++instance ToJSON ServerBindings where+  toJSON = jsonViaEncoding+  toEncoding ServerBindings {..} =+    recordEncoding+      _serverBindingsExtensions+      [ "http" .=? _serverBindingsHttp,+        "ws" .=? _serverBindingsWs,+        "kafka" .=? _serverBindingsKafka,+        "anypointmq" .=? _serverBindingsAnypointmq,+        "amqp" .=? _serverBindingsAmqp,+        "amqp1" .=? _serverBindingsAmqp1,+        "mqtt" .=? _serverBindingsMqtt,+        "mqtt5" .=? _serverBindingsMqtt5,+        "nats" .=? _serverBindingsNats,+        "jms" .=? _serverBindingsJms,+        "sns" .=? _serverBindingsSns,+        "solace" .=? _serverBindingsSolace,+        "sqs" .=? _serverBindingsSqs,+        "stomp" .=? _serverBindingsStomp,+        "redis" .=? _serverBindingsRedis,+        "mercure" .=? _serverBindingsMercure,+        "ibmmq" .=? _serverBindingsIbmmq,+        "googlepubsub" .=? _serverBindingsGooglepubsub,+        "pulsar" .=? _serverBindingsPulsar,+        "ros2" .=? _serverBindingsRos2+      ]++instance FromJSON ServerBindings where+  parseJSON = withObject "ServerBindings" $ \o -> do+    _serverBindingsHttp <- o .:? "http"+    _serverBindingsWs <- o .:? "ws"+    _serverBindingsKafka <- o .:? "kafka"+    _serverBindingsAnypointmq <- o .:? "anypointmq"+    _serverBindingsAmqp <- o .:? "amqp"+    _serverBindingsAmqp1 <- o .:? "amqp1"+    _serverBindingsMqtt <- o .:? "mqtt"+    _serverBindingsMqtt5 <- o .:? "mqtt5"+    _serverBindingsNats <- o .:? "nats"+    _serverBindingsJms <- o .:? "jms"+    _serverBindingsSns <- o .:? "sns"+    _serverBindingsSolace <- o .:? "solace"+    _serverBindingsSqs <- o .:? "sqs"+    _serverBindingsStomp <- o .:? "stomp"+    _serverBindingsRedis <- o .:? "redis"+    _serverBindingsMercure <- o .:? "mercure"+    _serverBindingsIbmmq <- o .:? "ibmmq"+    _serverBindingsGooglepubsub <- o .:? "googlepubsub"+    _serverBindingsPulsar <- o .:? "pulsar"+    _serverBindingsRos2 <- o .:? "ros2"+    let _serverBindingsExtensions = parseExtensions o+    pure ServerBindings {..}++-- | A 'ServerBindings' with only the required fields set.+emptyServerBindings :: ServerBindings+emptyServerBindings =+  ServerBindings+    { _serverBindingsHttp = Nothing,+      _serverBindingsWs = Nothing,+      _serverBindingsKafka = Nothing,+      _serverBindingsAnypointmq = Nothing,+      _serverBindingsAmqp = Nothing,+      _serverBindingsAmqp1 = Nothing,+      _serverBindingsMqtt = Nothing,+      _serverBindingsMqtt5 = Nothing,+      _serverBindingsNats = Nothing,+      _serverBindingsJms = Nothing,+      _serverBindingsSns = Nothing,+      _serverBindingsSolace = Nothing,+      _serverBindingsSqs = Nothing,+      _serverBindingsStomp = Nothing,+      _serverBindingsRedis = Nothing,+      _serverBindingsMercure = Nothing,+      _serverBindingsIbmmq = Nothing,+      _serverBindingsGooglepubsub = Nothing,+      _serverBindingsPulsar = Nothing,+      _serverBindingsRos2 = Nothing,+      _serverBindingsExtensions = InsOrd.empty+    }++-- | Protocol-specific definitions for a channel.+--+-- [AsyncAPI 3.1.0 — Channel Bindings Object](https://www.asyncapi.com/docs/reference/specification/v3.1.0#channelBindingsObject)+data ChannelBindings = ChannelBindings+  { _channelBindingsHttp :: Maybe Value,+    _channelBindingsWs :: Maybe Value,+    _channelBindingsKafka :: Maybe Value,+    _channelBindingsAnypointmq :: Maybe Value,+    _channelBindingsAmqp :: Maybe Value,+    _channelBindingsAmqp1 :: Maybe Value,+    _channelBindingsMqtt :: Maybe Value,+    _channelBindingsMqtt5 :: Maybe Value,+    _channelBindingsNats :: Maybe Value,+    _channelBindingsJms :: Maybe Value,+    _channelBindingsSns :: Maybe Value,+    _channelBindingsSolace :: Maybe Value,+    _channelBindingsSqs :: Maybe Value,+    _channelBindingsStomp :: Maybe Value,+    _channelBindingsRedis :: Maybe Value,+    _channelBindingsMercure :: Maybe Value,+    _channelBindingsIbmmq :: Maybe Value,+    _channelBindingsGooglepubsub :: Maybe Value,+    _channelBindingsPulsar :: Maybe Value,+    _channelBindingsRos2 :: Maybe Value,+    _channelBindingsExtensions :: InsOrdHashMap Text Value+  }+  deriving (Eq, Show, Generic)++instance ToJSON ChannelBindings where+  toJSON = jsonViaEncoding+  toEncoding ChannelBindings {..} =+    recordEncoding+      _channelBindingsExtensions+      [ "http" .=? _channelBindingsHttp,+        "ws" .=? _channelBindingsWs,+        "kafka" .=? _channelBindingsKafka,+        "anypointmq" .=? _channelBindingsAnypointmq,+        "amqp" .=? _channelBindingsAmqp,+        "amqp1" .=? _channelBindingsAmqp1,+        "mqtt" .=? _channelBindingsMqtt,+        "mqtt5" .=? _channelBindingsMqtt5,+        "nats" .=? _channelBindingsNats,+        "jms" .=? _channelBindingsJms,+        "sns" .=? _channelBindingsSns,+        "solace" .=? _channelBindingsSolace,+        "sqs" .=? _channelBindingsSqs,+        "stomp" .=? _channelBindingsStomp,+        "redis" .=? _channelBindingsRedis,+        "mercure" .=? _channelBindingsMercure,+        "ibmmq" .=? _channelBindingsIbmmq,+        "googlepubsub" .=? _channelBindingsGooglepubsub,+        "pulsar" .=? _channelBindingsPulsar,+        "ros2" .=? _channelBindingsRos2+      ]++instance FromJSON ChannelBindings where+  parseJSON = withObject "ChannelBindings" $ \o -> do+    _channelBindingsHttp <- o .:? "http"+    _channelBindingsWs <- o .:? "ws"+    _channelBindingsKafka <- o .:? "kafka"+    _channelBindingsAnypointmq <- o .:? "anypointmq"+    _channelBindingsAmqp <- o .:? "amqp"+    _channelBindingsAmqp1 <- o .:? "amqp1"+    _channelBindingsMqtt <- o .:? "mqtt"+    _channelBindingsMqtt5 <- o .:? "mqtt5"+    _channelBindingsNats <- o .:? "nats"+    _channelBindingsJms <- o .:? "jms"+    _channelBindingsSns <- o .:? "sns"+    _channelBindingsSolace <- o .:? "solace"+    _channelBindingsSqs <- o .:? "sqs"+    _channelBindingsStomp <- o .:? "stomp"+    _channelBindingsRedis <- o .:? "redis"+    _channelBindingsMercure <- o .:? "mercure"+    _channelBindingsIbmmq <- o .:? "ibmmq"+    _channelBindingsGooglepubsub <- o .:? "googlepubsub"+    _channelBindingsPulsar <- o .:? "pulsar"+    _channelBindingsRos2 <- o .:? "ros2"+    let _channelBindingsExtensions = parseExtensions o+    pure ChannelBindings {..}++-- | A 'ChannelBindings' with only the required fields set.+emptyChannelBindings :: ChannelBindings+emptyChannelBindings =+  ChannelBindings+    { _channelBindingsHttp = Nothing,+      _channelBindingsWs = Nothing,+      _channelBindingsKafka = Nothing,+      _channelBindingsAnypointmq = Nothing,+      _channelBindingsAmqp = Nothing,+      _channelBindingsAmqp1 = Nothing,+      _channelBindingsMqtt = Nothing,+      _channelBindingsMqtt5 = Nothing,+      _channelBindingsNats = Nothing,+      _channelBindingsJms = Nothing,+      _channelBindingsSns = Nothing,+      _channelBindingsSolace = Nothing,+      _channelBindingsSqs = Nothing,+      _channelBindingsStomp = Nothing,+      _channelBindingsRedis = Nothing,+      _channelBindingsMercure = Nothing,+      _channelBindingsIbmmq = Nothing,+      _channelBindingsGooglepubsub = Nothing,+      _channelBindingsPulsar = Nothing,+      _channelBindingsRos2 = Nothing,+      _channelBindingsExtensions = InsOrd.empty+    }++-- | Protocol-specific definitions for an operation.+--+-- [AsyncAPI 3.1.0 — Operation Bindings Object](https://www.asyncapi.com/docs/reference/specification/v3.1.0#operationBindingsObject)+data OperationBindings = OperationBindings+  { _operationBindingsHttp :: Maybe Value,+    _operationBindingsWs :: Maybe Value,+    _operationBindingsKafka :: Maybe Value,+    _operationBindingsAnypointmq :: Maybe Value,+    _operationBindingsAmqp :: Maybe Value,+    _operationBindingsAmqp1 :: Maybe Value,+    _operationBindingsMqtt :: Maybe Value,+    _operationBindingsMqtt5 :: Maybe Value,+    _operationBindingsNats :: Maybe Value,+    _operationBindingsJms :: Maybe Value,+    _operationBindingsSns :: Maybe Value,+    _operationBindingsSolace :: Maybe Value,+    _operationBindingsSqs :: Maybe Value,+    _operationBindingsStomp :: Maybe Value,+    _operationBindingsRedis :: Maybe Value,+    _operationBindingsMercure :: Maybe Value,+    _operationBindingsGooglepubsub :: Maybe Value,+    _operationBindingsIbmmq :: Maybe Value,+    _operationBindingsPulsar :: Maybe Value,+    _operationBindingsRos2 :: Maybe Value,+    _operationBindingsExtensions :: InsOrdHashMap Text Value+  }+  deriving (Eq, Show, Generic)++instance ToJSON OperationBindings where+  toJSON = jsonViaEncoding+  toEncoding OperationBindings {..} =+    recordEncoding+      _operationBindingsExtensions+      [ "http" .=? _operationBindingsHttp,+        "ws" .=? _operationBindingsWs,+        "kafka" .=? _operationBindingsKafka,+        "anypointmq" .=? _operationBindingsAnypointmq,+        "amqp" .=? _operationBindingsAmqp,+        "amqp1" .=? _operationBindingsAmqp1,+        "mqtt" .=? _operationBindingsMqtt,+        "mqtt5" .=? _operationBindingsMqtt5,+        "nats" .=? _operationBindingsNats,+        "jms" .=? _operationBindingsJms,+        "sns" .=? _operationBindingsSns,+        "solace" .=? _operationBindingsSolace,+        "sqs" .=? _operationBindingsSqs,+        "stomp" .=? _operationBindingsStomp,+        "redis" .=? _operationBindingsRedis,+        "mercure" .=? _operationBindingsMercure,+        "googlepubsub" .=? _operationBindingsGooglepubsub,+        "ibmmq" .=? _operationBindingsIbmmq,+        "pulsar" .=? _operationBindingsPulsar,+        "ros2" .=? _operationBindingsRos2+      ]++instance FromJSON OperationBindings where+  parseJSON = withObject "OperationBindings" $ \o -> do+    _operationBindingsHttp <- o .:? "http"+    _operationBindingsWs <- o .:? "ws"+    _operationBindingsKafka <- o .:? "kafka"+    _operationBindingsAnypointmq <- o .:? "anypointmq"+    _operationBindingsAmqp <- o .:? "amqp"+    _operationBindingsAmqp1 <- o .:? "amqp1"+    _operationBindingsMqtt <- o .:? "mqtt"+    _operationBindingsMqtt5 <- o .:? "mqtt5"+    _operationBindingsNats <- o .:? "nats"+    _operationBindingsJms <- o .:? "jms"+    _operationBindingsSns <- o .:? "sns"+    _operationBindingsSolace <- o .:? "solace"+    _operationBindingsSqs <- o .:? "sqs"+    _operationBindingsStomp <- o .:? "stomp"+    _operationBindingsRedis <- o .:? "redis"+    _operationBindingsMercure <- o .:? "mercure"+    _operationBindingsGooglepubsub <- o .:? "googlepubsub"+    _operationBindingsIbmmq <- o .:? "ibmmq"+    _operationBindingsPulsar <- o .:? "pulsar"+    _operationBindingsRos2 <- o .:? "ros2"+    let _operationBindingsExtensions = parseExtensions o+    pure OperationBindings {..}++-- | An 'OperationBindings' with only the required fields set.+emptyOperationBindings :: OperationBindings+emptyOperationBindings =+  OperationBindings+    { _operationBindingsHttp = Nothing,+      _operationBindingsWs = Nothing,+      _operationBindingsKafka = Nothing,+      _operationBindingsAnypointmq = Nothing,+      _operationBindingsAmqp = Nothing,+      _operationBindingsAmqp1 = Nothing,+      _operationBindingsMqtt = Nothing,+      _operationBindingsMqtt5 = Nothing,+      _operationBindingsNats = Nothing,+      _operationBindingsJms = Nothing,+      _operationBindingsSns = Nothing,+      _operationBindingsSolace = Nothing,+      _operationBindingsSqs = Nothing,+      _operationBindingsStomp = Nothing,+      _operationBindingsRedis = Nothing,+      _operationBindingsMercure = Nothing,+      _operationBindingsGooglepubsub = Nothing,+      _operationBindingsIbmmq = Nothing,+      _operationBindingsPulsar = Nothing,+      _operationBindingsRos2 = Nothing,+      _operationBindingsExtensions = InsOrd.empty+    }++-- | Protocol-specific definitions for a message.+--+-- [AsyncAPI 3.1.0 — Message Bindings Object](https://www.asyncapi.com/docs/reference/specification/v3.1.0#messageBindingsObject)+data MessageBindings = MessageBindings+  { _messageBindingsHttp :: Maybe Value,+    _messageBindingsWs :: Maybe Value,+    _messageBindingsKafka :: Maybe Value,+    _messageBindingsAnypointmq :: Maybe Value,+    _messageBindingsAmqp :: Maybe Value,+    _messageBindingsAmqp1 :: Maybe Value,+    _messageBindingsMqtt :: Maybe Value,+    _messageBindingsMqtt5 :: Maybe Value,+    _messageBindingsNats :: Maybe Value,+    _messageBindingsJms :: Maybe Value,+    _messageBindingsSns :: Maybe Value,+    _messageBindingsSolace :: Maybe Value,+    _messageBindingsSqs :: Maybe Value,+    _messageBindingsStomp :: Maybe Value,+    _messageBindingsRedis :: Maybe Value,+    _messageBindingsMercure :: Maybe Value,+    _messageBindingsIbmmq :: Maybe Value,+    _messageBindingsGooglepubsub :: Maybe Value,+    _messageBindingsPulsar :: Maybe Value,+    _messageBindingsRos2 :: Maybe Value,+    _messageBindingsExtensions :: InsOrdHashMap Text Value+  }+  deriving (Eq, Show, Generic)++instance ToJSON MessageBindings where+  toJSON = jsonViaEncoding+  toEncoding MessageBindings {..} =+    recordEncoding+      _messageBindingsExtensions+      [ "http" .=? _messageBindingsHttp,+        "ws" .=? _messageBindingsWs,+        "kafka" .=? _messageBindingsKafka,+        "anypointmq" .=? _messageBindingsAnypointmq,+        "amqp" .=? _messageBindingsAmqp,+        "amqp1" .=? _messageBindingsAmqp1,+        "mqtt" .=? _messageBindingsMqtt,+        "mqtt5" .=? _messageBindingsMqtt5,+        "nats" .=? _messageBindingsNats,+        "jms" .=? _messageBindingsJms,+        "sns" .=? _messageBindingsSns,+        "solace" .=? _messageBindingsSolace,+        "sqs" .=? _messageBindingsSqs,+        "stomp" .=? _messageBindingsStomp,+        "redis" .=? _messageBindingsRedis,+        "mercure" .=? _messageBindingsMercure,+        "ibmmq" .=? _messageBindingsIbmmq,+        "googlepubsub" .=? _messageBindingsGooglepubsub,+        "pulsar" .=? _messageBindingsPulsar,+        "ros2" .=? _messageBindingsRos2+      ]++instance FromJSON MessageBindings where+  parseJSON = withObject "MessageBindings" $ \o -> do+    _messageBindingsHttp <- o .:? "http"+    _messageBindingsWs <- o .:? "ws"+    _messageBindingsKafka <- o .:? "kafka"+    _messageBindingsAnypointmq <- o .:? "anypointmq"+    _messageBindingsAmqp <- o .:? "amqp"+    _messageBindingsAmqp1 <- o .:? "amqp1"+    _messageBindingsMqtt <- o .:? "mqtt"+    _messageBindingsMqtt5 <- o .:? "mqtt5"+    _messageBindingsNats <- o .:? "nats"+    _messageBindingsJms <- o .:? "jms"+    _messageBindingsSns <- o .:? "sns"+    _messageBindingsSolace <- o .:? "solace"+    _messageBindingsSqs <- o .:? "sqs"+    _messageBindingsStomp <- o .:? "stomp"+    _messageBindingsRedis <- o .:? "redis"+    _messageBindingsMercure <- o .:? "mercure"+    _messageBindingsIbmmq <- o .:? "ibmmq"+    _messageBindingsGooglepubsub <- o .:? "googlepubsub"+    _messageBindingsPulsar <- o .:? "pulsar"+    _messageBindingsRos2 <- o .:? "ros2"+    let _messageBindingsExtensions = parseExtensions o+    pure MessageBindings {..}++-- | A 'MessageBindings' with only the required fields set.+emptyMessageBindings :: MessageBindings+emptyMessageBindings =+  MessageBindings+    { _messageBindingsHttp = Nothing,+      _messageBindingsWs = Nothing,+      _messageBindingsKafka = Nothing,+      _messageBindingsAnypointmq = Nothing,+      _messageBindingsAmqp = Nothing,+      _messageBindingsAmqp1 = Nothing,+      _messageBindingsMqtt = Nothing,+      _messageBindingsMqtt5 = Nothing,+      _messageBindingsNats = Nothing,+      _messageBindingsJms = Nothing,+      _messageBindingsSns = Nothing,+      _messageBindingsSolace = Nothing,+      _messageBindingsSqs = Nothing,+      _messageBindingsStomp = Nothing,+      _messageBindingsRedis = Nothing,+      _messageBindingsMercure = Nothing,+      _messageBindingsIbmmq = Nothing,+      _messageBindingsGooglepubsub = Nothing,+      _messageBindingsPulsar = Nothing,+      _messageBindingsRos2 = Nothing,+      _messageBindingsExtensions = InsOrd.empty+    }++-- $ mfs+--+-- [AsyncAPI 3.1.0 — Multi Format Schema Object](https://www.asyncapi.com/docs/reference/specification/v3.1.0#multiFormatSchemaObject)++-- | A schema definition supporting multiple schema formats or languages.+--+-- [AsyncAPI 3.1.0 — Multi Format Schema Object](https://www.asyncapi.com/docs/reference/specification/v3.1.0#multiFormatSchemaObject)+data MultiFormatSchema = MultiFormatSchema+  { -- | **REQUIRED.** Name of the schema format used to define the schema.+    -- [Schema formats table](https://www.asyncapi.com/docs/reference/specification/v3.1.0#multiFormatSchemaFormatTable)+    _multiFormatSchemaSchemaFormat :: Text,+    -- | **REQUIRED.** The schema definition, in the given format.+    _multiFormatSchemaSchema :: Value,+    -- | Specification extensions (@x-@).+    _multiFormatSchemaExtensions :: InsOrdHashMap Text Value+  }+  deriving (Eq, Show, Generic)++instance ToJSON MultiFormatSchema where+  toJSON = jsonViaEncoding+  toEncoding MultiFormatSchema {..} =+    recordEncoding+      _multiFormatSchemaExtensions+      [ "schemaFormat" .=? Just _multiFormatSchemaSchemaFormat,+        "schema" .=? Just _multiFormatSchemaSchema+      ]++instance FromJSON MultiFormatSchema where+  parseJSON = withObject "MultiFormatSchema" $ \o -> do+    _multiFormatSchemaSchemaFormat <- o .: "schemaFormat"+    _multiFormatSchemaSchema <- o .: "schema"+    let _multiFormatSchemaExtensions = parseExtensions o+    pure MultiFormatSchema {..}++-- | A 'MultiFormatSchema' with only the required fields set.+emptyMultiFormatSchema :: Text -> Value -> MultiFormatSchema+emptyMultiFormatSchema fmt schema =+  MultiFormatSchema+    { _multiFormatSchemaSchemaFormat = fmt,+      _multiFormatSchemaSchema = schema,+      _multiFormatSchemaExtensions = InsOrd.empty+    }++-- $ components+--+-- [AsyncAPI 3.1.0 — Components Object](https://www.asyncapi.com/docs/reference/specification/v3.1.0#componentsObject)++-- | Reusable objects for different aspects of the specification.+--+-- [AsyncAPI 3.1.0 — Components Object](https://www.asyncapi.com/docs/reference/specification/v3.1.0#componentsObject)+data Components = Components+  { -- | Reusable schemas (Schema Objects, references, or other formats).+    -- [Components Object, schemas](https://www.asyncapi.com/docs/reference/specification/v3.1.0#componentsSchemas)+    _componentsSchemas :: Maybe (InsOrdHashMap Text SchemaDefinition),+    -- | Reusable servers.+    -- [Components Object, servers](https://www.asyncapi.com/docs/reference/specification/v3.1.0#componentsServers)+    _componentsServers :: Maybe Servers,+    -- | Reusable channels.+    -- [Components Object, channels](https://www.asyncapi.com/docs/reference/specification/v3.1.0#componentsChannels)+    _componentsChannels :: Maybe Channels,+    -- | Reusable operations.+    -- [Components Object, operations](https://www.asyncapi.com/docs/reference/specification/v3.1.0#componentsOperations)+    _componentsOperations :: Maybe Operations,+    -- | Reusable messages.+    -- [Components Object, messages](https://www.asyncapi.com/docs/reference/specification/v3.1.0#componentsMessages)+    _componentsMessages :: Maybe Messages,+    -- | Reusable security schemes.+    -- [Components Object, securitySchemes](https://www.asyncapi.com/docs/reference/specification/v3.1.0#componentsSecuritySchemes)+    _componentsSecuritySchemes :: Maybe (InsOrdHashMap Text (Referenced SecurityScheme)),+    -- | Reusable server variables.+    -- [Components Object, serverVariables](https://www.asyncapi.com/docs/reference/specification/v3.1.0#componentsServerVariables)+    _componentsServerVariables :: Maybe (InsOrdHashMap Text (Referenced ServerVariable)),+    -- | Reusable parameters.+    -- [Components Object, parameters](https://www.asyncapi.com/docs/reference/specification/v3.1.0#componentsParameters)+    _componentsParameters :: Maybe Parameters,+    -- | Reusable correlation IDs.+    -- [Components Object, correlationIds](https://www.asyncapi.com/docs/reference/specification/v3.1.0#componentsCorrelationIDs)+    _componentsCorrelationIds :: Maybe (InsOrdHashMap Text (Referenced CorrelationId)),+    -- | Reusable operation replies.+    -- [Components Object, replies](https://www.asyncapi.com/docs/reference/specification/v3.1.0#componentsReplies)+    _componentsReplies :: Maybe (InsOrdHashMap Text (Referenced OperationReply)),+    -- | Reusable operation reply addresses.+    -- [Components Object, replyAddresses](https://www.asyncapi.com/docs/reference/specification/v3.1.0#componentsReplyAddresses)+    _componentsReplyAddresses :: Maybe (InsOrdHashMap Text (Referenced OperationReplyAddress)),+    -- | Reusable external documentation objects.+    -- [Components Object, externalDocs](https://www.asyncapi.com/docs/reference/specification/v3.1.0#componentsExternalDocs)+    _componentsExternalDocs :: Maybe (InsOrdHashMap Text (Referenced ExternalDocumentation)),+    -- | Reusable tags.+    -- [Components Object, tags](https://www.asyncapi.com/docs/reference/specification/v3.1.0#componentsTags)+    _componentsTags :: Maybe (InsOrdHashMap Text (Referenced Tag)),+    -- | Reusable operation traits.+    -- [Components Object, operationTraits](https://www.asyncapi.com/docs/reference/specification/v3.1.0#componentsOperationTraits)+    _componentsOperationTraits :: Maybe (InsOrdHashMap Text (Referenced OperationTrait)),+    -- | Reusable message traits.+    -- [Components Object, messageTraits](https://www.asyncapi.com/docs/reference/specification/v3.1.0#componentsMessageTraits)+    _componentsMessageTraits :: Maybe (InsOrdHashMap Text (Referenced MessageTrait)),+    -- | Reusable server bindings.+    -- [Components Object, serverBindings](https://www.asyncapi.com/docs/reference/specification/v3.1.0#componentsServerBindings)+    _componentsServerBindings :: Maybe (InsOrdHashMap Text (Referenced ServerBindings)),+    -- | Reusable channel bindings.+    -- [Components Object, channelBindings](https://www.asyncapi.com/docs/reference/specification/v3.1.0#componentsChannelBindings)+    _componentsChannelBindings :: Maybe (InsOrdHashMap Text (Referenced ChannelBindings)),+    -- | Reusable operation bindings.+    -- [Components Object, operationBindings](https://www.asyncapi.com/docs/reference/specification/v3.1.0#componentsOperationBindings)+    _componentsOperationBindings :: Maybe (InsOrdHashMap Text (Referenced OperationBindings)),+    -- | Reusable message bindings.+    -- [Components Object, messageBindings](https://www.asyncapi.com/docs/reference/specification/v3.1.0#componentsMessageBindings)+    _componentsMessageBindings :: Maybe (InsOrdHashMap Text (Referenced MessageBindings)),+    -- | Specification extensions (@x-@).+    _componentsExtensions :: InsOrdHashMap Text Value+  }+  deriving (Eq, Show, Generic)++-- | A 'Components' object with no reusable objects.+emptyComponents :: Components+emptyComponents =+  Components+    { _componentsSchemas = Nothing,+      _componentsServers = Nothing,+      _componentsChannels = Nothing,+      _componentsOperations = Nothing,+      _componentsMessages = Nothing,+      _componentsSecuritySchemes = Nothing,+      _componentsServerVariables = Nothing,+      _componentsParameters = Nothing,+      _componentsCorrelationIds = Nothing,+      _componentsReplies = Nothing,+      _componentsReplyAddresses = Nothing,+      _componentsExternalDocs = Nothing,+      _componentsTags = Nothing,+      _componentsOperationTraits = Nothing,+      _componentsMessageTraits = Nothing,+      _componentsServerBindings = Nothing,+      _componentsChannelBindings = Nothing,+      _componentsOperationBindings = Nothing,+      _componentsMessageBindings = Nothing,+      _componentsExtensions = InsOrd.empty+    }++instance ToJSON Components where+  toJSON = jsonViaEncoding+  toEncoding Components {..} =+    recordEncoding+      _componentsExtensions+      [ "schemas" .=? fmap SortedObject _componentsSchemas,+        "servers" .=? fmap SortedObject _componentsServers,+        "channels" .=? fmap SortedObject _componentsChannels,+        "operations" .=? fmap SortedObject _componentsOperations,+        "messages" .=? fmap SortedObject _componentsMessages,+        "securitySchemes" .=? fmap SortedObject _componentsSecuritySchemes,+        "serverVariables" .=? fmap SortedObject _componentsServerVariables,+        "parameters" .=? fmap SortedObject _componentsParameters,+        "correlationIds" .=? fmap SortedObject _componentsCorrelationIds,+        "replies" .=? fmap SortedObject _componentsReplies,+        "replyAddresses" .=? fmap SortedObject _componentsReplyAddresses,+        "externalDocs" .=? fmap SortedObject _componentsExternalDocs,+        "tags" .=? fmap SortedObject _componentsTags,+        "operationTraits" .=? fmap SortedObject _componentsOperationTraits,+        "messageTraits" .=? fmap SortedObject _componentsMessageTraits,+        "serverBindings" .=? fmap SortedObject _componentsServerBindings,+        "channelBindings" .=? fmap SortedObject _componentsChannelBindings,+        "operationBindings" .=? fmap SortedObject _componentsOperationBindings,+        "messageBindings" .=? fmap SortedObject _componentsMessageBindings+      ]++instance FromJSON Components where+  parseJSON = withObject "Components" $ \o -> do+    _componentsSchemas <- sortedMapField "schemas" o+    _componentsServers <- sortedMapField "servers" o+    _componentsChannels <- sortedMapField "channels" o+    _componentsOperations <- sortedMapField "operations" o+    _componentsMessages <- sortedMapField "messages" o+    _componentsSecuritySchemes <- sortedMapField "securitySchemes" o+    _componentsServerVariables <- sortedMapField "serverVariables" o+    _componentsParameters <- sortedMapField "parameters" o+    _componentsCorrelationIds <- sortedMapField "correlationIds" o+    _componentsReplies <- sortedMapField "replies" o+    _componentsReplyAddresses <- sortedMapField "replyAddresses" o+    _componentsExternalDocs <- sortedMapField "externalDocs" o+    _componentsTags <- sortedMapField "tags" o+    _componentsOperationTraits <- sortedMapField "operationTraits" o+    _componentsMessageTraits <- sortedMapField "messageTraits" o+    _componentsServerBindings <- sortedMapField "serverBindings" o+    _componentsChannelBindings <- sortedMapField "channelBindings" o+    _componentsOperationBindings <- sortedMapField "operationBindings" o+    _componentsMessageBindings <- sortedMapField "messageBindings" o+    let _componentsExtensions = parseExtensions o+    pure Components {..}++-- $ messages+--+-- [AsyncAPI 3.1.0 — Messages Object](https://www.asyncapi.com/docs/reference/specification/v3.1.0#messagesObject)++-- | A map of message identifiers to (possibly referenced) messages.+--+-- [AsyncAPI 3.1.0 — Messages Object](https://www.asyncapi.com/docs/reference/specification/v3.1.0#messagesObject)+type Messages = InsOrdHashMap Text (Referenced Message)++-- | A schema definition in any supported form: a (possibly referenced)+-- Schema Object, or a Multi Format Schema Object for other formats.+--+-- [Multi Format Schema Object](https://www.asyncapi.com/docs/reference/specification/v3.1.0#multiFormatSchemaObject)+data SchemaDefinition+  = -- | A Schema Object or a Reference to one.+    SchemaDefSchema (Referenced Schema)+  | -- | A schema in another format (e.g. Avro).+    SchemaDefMultiFormat MultiFormatSchema+  deriving (Eq, Show, Generic)++instance ToJSON SchemaDefinition where+  toJSON = jsonViaEncoding+  toEncoding (SchemaDefMultiFormat m) = toEncoding m+  toEncoding (SchemaDefSchema s) = toEncoding s++instance FromJSON SchemaDefinition where+  parseJSON v@(Object o)+    -- `schemaFormat` is REQUIRED in the Multi Format Schema Object and is not+    -- a draft-07 keyword, so its presence alone is an unambiguous+    -- discriminator; a missing `schema` then fails inside MultiFormatSchema+    -- (naming the real problem) instead of decoding as an empty schema.+    | KM.member "schemaFormat" o = SchemaDefMultiFormat <$> parseJSON v+  parseJSON v = SchemaDefSchema <$> parseJSON v++-- | A message received on a given channel and operation.+--+-- [AsyncAPI 3.1.0 — Message Object](https://www.asyncapi.com/docs/reference/specification/v3.1.0#messageObject)+data Message = Message+  { -- | Schema definition of the application headers.+    _messageHeaders :: Maybe SchemaDefinition,+    -- | Definition of the message payload.+    _messagePayload :: Maybe SchemaDefinition,+    -- | Definition of the correlation ID used for message tracing or matching.+    -- [Correlation ID Object](https://www.asyncapi.com/docs/reference/specification/v3.1.0#correlationIdObject)+    _messageCorrelationId :: Maybe (Referenced CorrelationId),+    -- | The content type to use when encoding\/decoding the payload.+    -- [Message Object, contentType](https://www.asyncapi.com/docs/reference/specification/v3.1.0#messageObjectContentType)+    _messageContentType :: Maybe ContentType,+    -- | A machine-friendly name for the message.+    _messageName :: Maybe Name,+    -- | A human-friendly title for the message.+    _messageTitle :: Maybe Title,+    -- | A short summary of what the message is about.+    _messageSummary :: Maybe Summary,+    -- | A verbose explanation of the message.+    _messageDescription :: Maybe Description,+    -- | A list of tags for logical grouping of messages.+    _messageTags :: Maybe Tags,+    -- | Additional external documentation for this message.+    _messageExternalDocs :: Maybe (Referenced ExternalDocumentation),+    -- | Protocol-specific definitions for the message.+    -- [Message Bindings Object](https://www.asyncapi.com/docs/reference/specification/v3.1.0#messageBindingsObject)+    _messageBindings :: Maybe (Referenced MessageBindings),+    -- | List of examples.+    -- [Message Example Object](https://www.asyncapi.com/docs/reference/specification/v3.1.0#messageExampleObject)+    _messageExamples :: Maybe [MessageExample],+    -- | A list of traits to apply to the message object.+    -- [Message Trait Object](https://www.asyncapi.com/docs/reference/specification/v3.1.0#messageTraitObject)+    _messageTraits :: Maybe [Referenced MessageTrait],+    -- | Specification extensions (@x-@).+    _messageExtensions :: InsOrdHashMap Text Value+  }+  deriving (Eq, Show, Generic)++instance ToJSON Message where+  toJSON = jsonViaEncoding+  toEncoding Message {..} =+    recordEncoding+      _messageExtensions+      [ "headers" .=? _messageHeaders,+        "payload" .=? _messagePayload,+        "correlationId" .=? _messageCorrelationId,+        "contentType" .=? _messageContentType,+        "name" .=? _messageName,+        "title" .=? _messageTitle,+        "summary" .=? _messageSummary,+        "description" .=? _messageDescription,+        "tags" .=? _messageTags,+        "externalDocs" .=? _messageExternalDocs,+        "bindings" .=? _messageBindings,+        "examples" .=? _messageExamples,+        "traits" .=? _messageTraits+      ]++instance FromJSON Message where+  parseJSON = withObject "Message" $ \o -> do+    _messageHeaders <- o .:? "headers"+    _messagePayload <- o .:? "payload"+    _messageCorrelationId <- o .:? "correlationId"+    _messageContentType <- o .:? "contentType"+    _messageName <- o .:? "name"+    _messageTitle <- o .:? "title"+    _messageSummary <- o .:? "summary"+    _messageDescription <- o .:? "description"+    _messageTags <- o .:? "tags"+    _messageExternalDocs <- o .:? "externalDocs"+    _messageBindings <- o .:? "bindings"+    _messageExamples <- o .:? "examples"+    _messageTraits <- o .:? "traits"+    let _messageExtensions = parseExtensions o+    pure Message {..}++-- | A 'Message' with only the required fields set.+emptyMessage :: Message+emptyMessage =+  Message+    { _messageHeaders = Nothing,+      _messagePayload = Nothing,+      _messageCorrelationId = Nothing,+      _messageContentType = Nothing,+      _messageName = Nothing,+      _messageTitle = Nothing,+      _messageSummary = Nothing,+      _messageDescription = Nothing,+      _messageTags = Nothing,+      _messageExternalDocs = Nothing,+      _messageBindings = Nothing,+      _messageExamples = Nothing,+      _messageTraits = Nothing,+      _messageExtensions = InsOrd.empty+    }++-- | A trait that MAY be applied to a message; any Message Object property+-- except @payload@ and @traits@.+--+-- [AsyncAPI 3.1.0 — Message Trait Object](https://www.asyncapi.com/docs/reference/specification/v3.1.0#messageTraitObject)+data MessageTrait = MessageTrait+  { -- | Schema definition of the application headers.+    _messageTraitHeaders :: Maybe SchemaDefinition,+    -- | Definition of the correlation ID.+    _messageTraitCorrelationId :: Maybe (Referenced CorrelationId),+    -- | The content type to use when encoding\/decoding the payload.+    _messageTraitContentType :: Maybe ContentType,+    -- | A machine-friendly name for the message.+    _messageTraitName :: Maybe Name,+    -- | A human-friendly title for the message.+    _messageTraitTitle :: Maybe Title,+    -- | A short summary of what the message is about.+    _messageTraitSummary :: Maybe Summary,+    -- | A verbose explanation of the message.+    _messageTraitDescription :: Maybe Description,+    -- | A list of tags for logical grouping of messages.+    _messageTraitTags :: Maybe Tags,+    -- | Additional external documentation for this message.+    _messageTraitExternalDocs :: Maybe (Referenced ExternalDocumentation),+    -- | Protocol-specific definitions for the message.+    _messageTraitBindings :: Maybe (Referenced MessageBindings),+    -- | List of examples.+    _messageTraitExamples :: Maybe [MessageExample],+    -- | Specification extensions (@x-@).+    _messageTraitExtensions :: InsOrdHashMap Text Value+  }+  deriving (Eq, Show, Generic)++instance ToJSON MessageTrait where+  toJSON = jsonViaEncoding+  toEncoding MessageTrait {..} =+    recordEncoding+      _messageTraitExtensions+      [ "headers" .=? _messageTraitHeaders,+        "correlationId" .=? _messageTraitCorrelationId,+        "contentType" .=? _messageTraitContentType,+        "name" .=? _messageTraitName,+        "title" .=? _messageTraitTitle,+        "summary" .=? _messageTraitSummary,+        "description" .=? _messageTraitDescription,+        "tags" .=? _messageTraitTags,+        "externalDocs" .=? _messageTraitExternalDocs,+        "bindings" .=? _messageTraitBindings,+        "examples" .=? _messageTraitExamples+      ]++instance FromJSON MessageTrait where+  parseJSON = withObject "MessageTrait" $ \o -> do+    _messageTraitHeaders <- o .:? "headers"+    _messageTraitCorrelationId <- o .:? "correlationId"+    _messageTraitContentType <- o .:? "contentType"+    _messageTraitName <- o .:? "name"+    _messageTraitTitle <- o .:? "title"+    _messageTraitSummary <- o .:? "summary"+    _messageTraitDescription <- o .:? "description"+    _messageTraitTags <- o .:? "tags"+    _messageTraitExternalDocs <- o .:? "externalDocs"+    _messageTraitBindings <- o .:? "bindings"+    _messageTraitExamples <- o .:? "examples"+    let _messageTraitExtensions = parseExtensions o+    pure MessageTrait {..}++-- | A 'MessageTrait' with only the required fields set.+emptyMessageTrait :: MessageTrait+emptyMessageTrait =+  MessageTrait+    { _messageTraitHeaders = Nothing,+      _messageTraitCorrelationId = Nothing,+      _messageTraitContentType = Nothing,+      _messageTraitName = Nothing,+      _messageTraitTitle = Nothing,+      _messageTraitSummary = Nothing,+      _messageTraitDescription = Nothing,+      _messageTraitTags = Nothing,+      _messageTraitExternalDocs = Nothing,+      _messageTraitBindings = Nothing,+      _messageTraitExamples = Nothing,+      _messageTraitExtensions = InsOrd.empty+    }++-- | An example of a message; MUST contain headers and\/or payload.+--+-- [AsyncAPI 3.1.0 — Message Example Object](https://www.asyncapi.com/docs/reference/specification/v3.1.0#messageExampleObject)+data MessageExample = MessageExample+  { -- | Example headers, validating against the message's @headers@.+    _messageExampleHeaders :: Maybe (InsOrdHashMap Text Value),+    -- | Example payload, validating against the message's @payload@.+    _messageExamplePayload :: Maybe Value,+    -- | A machine-friendly name.+    _messageExampleName :: Maybe Name,+    -- | A short summary of what the example is about.+    _messageExampleSummary :: Maybe Summary,+    -- | Specification extensions (@x-@).+    _messageExampleExtensions :: InsOrdHashMap Text Value+  }+  deriving (Eq, Show, Generic)++instance ToJSON MessageExample where+  toJSON = jsonViaEncoding+  toEncoding MessageExample {..} =+    recordEncoding+      _messageExampleExtensions+      [ "headers" .=? fmap SortedObject _messageExampleHeaders,+        "payload" .=? _messageExamplePayload,+        "name" .=? _messageExampleName,+        "summary" .=? _messageExampleSummary+      ]++instance FromJSON MessageExample where+  parseJSON = withObject "MessageExample" $ \o -> do+    _messageExampleHeaders <- sortedMapField "headers" o+    _messageExamplePayload <- o .:? "payload"+    _messageExampleName <- o .:? "name"+    _messageExampleSummary <- o .:? "summary"+    let _messageExampleExtensions = parseExtensions o+    pure MessageExample {..}++-- | A 'MessageExample' with only the required fields set.+emptyMessageExample :: MessageExample+emptyMessageExample =+  MessageExample+    { _messageExampleHeaders = Nothing,+      _messageExamplePayload = Nothing,+      _messageExampleName = Nothing,+      _messageExampleSummary = Nothing,+      _messageExampleExtensions = InsOrd.empty+    }++-- | An identifier used for message tracing and correlation.+--+-- [AsyncAPI 3.1.0 — Correlation ID Object](https://www.asyncapi.com/docs/reference/specification/v3.1.0#correlationIdObject)+data CorrelationId = CorrelationId+  { -- | An optional description of the identifier.+    _correlationIdDescription :: Maybe Description,+    -- | **REQUIRED.** A runtime expression locating the correlation ID.+    -- [Runtime Expression](https://www.asyncapi.com/docs/reference/specification/v3.1.0#runtimeExpression)+    _correlationIdLocation :: RuntimeExpression,+    -- | Specification extensions (@x-@).+    _correlationIdExtensions :: InsOrdHashMap Text Value+  }+  deriving (Eq, Show, Generic)++instance ToJSON CorrelationId where+  toJSON = jsonViaEncoding+  toEncoding CorrelationId {..} =+    recordEncoding+      _correlationIdExtensions+      [ "description" .=? _correlationIdDescription,+        "location" .=? Just _correlationIdLocation+      ]++instance FromJSON CorrelationId where+  parseJSON = withObject "CorrelationId" $ \o -> do+    _correlationIdDescription <- o .:? "description"+    _correlationIdLocation <- o .: "location"+    let _correlationIdExtensions = parseExtensions o+    pure CorrelationId {..}++-- | A 'CorrelationId' with only the required fields set.+emptyCorrelationId :: RuntimeExpression -> CorrelationId+emptyCorrelationId loc =+  CorrelationId+    { _correlationIdDescription = Nothing,+      _correlationIdLocation = loc,+      _correlationIdExtensions = InsOrd.empty+    }++-- $ operations+--+-- [AsyncAPI 3.1.0 — Operations Object](https://www.asyncapi.com/docs/reference/specification/v3.1.0#operationsObject)++-- | A map of operation identifiers to (possibly referenced) operations.+--+-- [AsyncAPI 3.1.0 — Operations Object](https://www.asyncapi.com/docs/reference/specification/v3.1.0#operationsObject)+type Operations = InsOrdHashMap Text (Referenced Operation)++-- | The direction of an operation.+--+-- [Operation Object, action](https://www.asyncapi.com/docs/reference/specification/v3.1.0#operationObjectAction)+data OperationAction+  = -- | The application sends a message to the channel.+    Send+  | -- | The application receives messages from the channel.+    Receive+  deriving (Eq, Show, Generic)++instance ToJSON OperationAction where+  toJSON = jsonViaEncoding+  toEncoding a = toEncoding (case a of Send -> "send" :: Text; Receive -> "receive")++instance FromJSON OperationAction where+  parseJSON = withText "OperationAction" $ \case+    "send" -> pure Send+    "receive" -> pure Receive+    t -> fail ("unknown operation action: " <> show t)++-- | A specific operation.+--+-- [AsyncAPI 3.1.0 — Operation Object](https://www.asyncapi.com/docs/reference/specification/v3.1.0#operationObject)+data Operation = Operation+  { -- | **REQUIRED.** @send@ or @receive@.+    -- [Operation Object, action](https://www.asyncapi.com/docs/reference/specification/v3.1.0#operationObjectAction)+    _operationAction :: OperationAction,+    -- | **REQUIRED.** A @$ref@ pointer to the channel of this operation; MUST+    -- be a Reference Object.+    -- [Operation Object, channel](https://www.asyncapi.com/docs/reference/specification/v3.1.0#operationObjectChannel)+    _operationChannel :: Reference,+    -- | A human-friendly title for the operation.+    _operationTitle :: Maybe Title,+    -- | A short summary of what the operation is about.+    _operationSummary :: Maybe Summary,+    -- | A verbose explanation of the operation.+    _operationDescription :: Maybe Description,+    -- | A declaration of which security schemes are associated with this+    -- operation.+    -- [Security Scheme Object](https://www.asyncapi.com/docs/reference/specification/v3.1.0#securitySchemeObject)+    _operationSecurity :: Maybe [Referenced SecurityScheme],+    -- | A list of tags for logical grouping of operations.+    _operationTags :: Maybe Tags,+    -- | Additional external documentation for this operation.+    _operationExternalDocs :: Maybe (Referenced ExternalDocumentation),+    -- | Protocol-specific definitions for the operation.+    -- [Operation Bindings Object](https://www.asyncapi.com/docs/reference/specification/v3.1.0#operationBindingsObject)+    _operationBindings :: Maybe (Referenced OperationBindings),+    -- | A list of traits to apply to the operation object.+    -- [Operation Trait Object](https://www.asyncapi.com/docs/reference/specification/v3.1.0#operationTraitObject)+    _operationTraits :: Maybe [Referenced OperationTrait],+    -- | References to the supported messages of this operation; MUST be a+    -- list of Reference Objects.+    -- [Operation Object, messages](https://www.asyncapi.com/docs/reference/specification/v3.1.0#operationObjectMessages)+    _operationMessages :: Maybe [Reference],+    -- | The definition of the reply in a request-reply operation.+    -- [Operation Reply Object](https://www.asyncapi.com/docs/reference/specification/v3.1.0#operationReplyObject)+    _operationReply :: Maybe (Referenced OperationReply),+    -- | Specification extensions (@x-@).+    _operationExtensions :: InsOrdHashMap Text Value+  }+  deriving (Eq, Show, Generic)++instance ToJSON Operation where+  toJSON = jsonViaEncoding+  toEncoding Operation {..} =+    recordEncoding+      _operationExtensions+      [ "action" .=? Just _operationAction,+        "channel" .=? Just _operationChannel,+        "title" .=? _operationTitle,+        "summary" .=? _operationSummary,+        "description" .=? _operationDescription,+        "security" .=? _operationSecurity,+        "tags" .=? _operationTags,+        "externalDocs" .=? _operationExternalDocs,+        "bindings" .=? _operationBindings,+        "traits" .=? _operationTraits,+        "messages" .=? _operationMessages,+        "reply" .=? _operationReply+      ]++instance FromJSON Operation where+  parseJSON = withObject "Operation" $ \o -> do+    _operationAction <- o .: "action"+    _operationChannel <- o .: "channel"+    _operationTitle <- o .:? "title"+    _operationSummary <- o .:? "summary"+    _operationDescription <- o .:? "description"+    _operationSecurity <- o .:? "security"+    _operationTags <- o .:? "tags"+    _operationExternalDocs <- o .:? "externalDocs"+    _operationBindings <- o .:? "bindings"+    _operationTraits <- o .:? "traits"+    _operationMessages <- o .:? "messages"+    _operationReply <- o .:? "reply"+    let _operationExtensions = parseExtensions o+    pure Operation {..}++-- | An 'Operation' with only the required fields set.+emptyOperation :: OperationAction -> Reference -> Operation+emptyOperation action channel =+  Operation+    { _operationAction = action,+      _operationChannel = channel,+      _operationTitle = Nothing,+      _operationSummary = Nothing,+      _operationDescription = Nothing,+      _operationSecurity = Nothing,+      _operationTags = Nothing,+      _operationExternalDocs = Nothing,+      _operationBindings = Nothing,+      _operationTraits = Nothing,+      _operationMessages = Nothing,+      _operationReply = Nothing,+      _operationExtensions = InsOrd.empty+    }++-- | A trait that MAY be applied to an operation; any Operation Object+-- property except @action@, @channel@, @messages@ and @traits@.+--+-- [AsyncAPI 3.1.0 — Operation Trait Object](https://www.asyncapi.com/docs/reference/specification/v3.1.0#operationTraitObject)+data OperationTrait = OperationTrait+  { -- | A human-friendly title for the operation.+    _operationTraitTitle :: Maybe Title,+    -- | A short summary of what the operation is about.+    _operationTraitSummary :: Maybe Summary,+    -- | A verbose explanation of the operation.+    _operationTraitDescription :: Maybe Description,+    -- | A declaration of which security schemes are associated with this+    -- operation.+    _operationTraitSecurity :: Maybe [Referenced SecurityScheme],+    -- | A list of tags for logical grouping of operations.+    _operationTraitTags :: Maybe Tags,+    -- | Additional external documentation for this operation.+    _operationTraitExternalDocs :: Maybe (Referenced ExternalDocumentation),+    -- | Protocol-specific definitions for the operation.+    _operationTraitBindings :: Maybe (Referenced OperationBindings),+    -- | Specification extensions (@x-@).+    _operationTraitExtensions :: InsOrdHashMap Text Value+  }+  deriving (Eq, Show, Generic)++instance ToJSON OperationTrait where+  toJSON = jsonViaEncoding+  toEncoding OperationTrait {..} =+    recordEncoding+      _operationTraitExtensions+      [ "title" .=? _operationTraitTitle,+        "summary" .=? _operationTraitSummary,+        "description" .=? _operationTraitDescription,+        "security" .=? _operationTraitSecurity,+        "tags" .=? _operationTraitTags,+        "externalDocs" .=? _operationTraitExternalDocs,+        "bindings" .=? _operationTraitBindings+      ]++instance FromJSON OperationTrait where+  parseJSON = withObject "OperationTrait" $ \o -> do+    _operationTraitTitle <- o .:? "title"+    _operationTraitSummary <- o .:? "summary"+    _operationTraitDescription <- o .:? "description"+    _operationTraitSecurity <- o .:? "security"+    _operationTraitTags <- o .:? "tags"+    _operationTraitExternalDocs <- o .:? "externalDocs"+    _operationTraitBindings <- o .:? "bindings"+    let _operationTraitExtensions = parseExtensions o+    pure OperationTrait {..}++-- | An 'OperationTrait' with only the required fields set.+emptyOperationTrait :: OperationTrait+emptyOperationTrait =+  OperationTrait+    { _operationTraitTitle = Nothing,+      _operationTraitSummary = Nothing,+      _operationTraitDescription = Nothing,+      _operationTraitSecurity = Nothing,+      _operationTraitTags = Nothing,+      _operationTraitExternalDocs = Nothing,+      _operationTraitBindings = Nothing,+      _operationTraitExtensions = InsOrd.empty+    }++-- | The reply part of a request-reply operation.+--+-- [AsyncAPI 3.1.0 — Operation Reply Object](https://www.asyncapi.com/docs/reference/specification/v3.1.0#operationReplyObject)+data OperationReply = OperationReply+  { -- | The address implementations MUST use for the reply.+    -- [Operation Reply Address Object](https://www.asyncapi.com/docs/reference/specification/v3.1.0#operationReplyAddressObject)+    _operationReplyAddress :: Maybe (Referenced OperationReplyAddress),+    -- | A @$ref@ pointer to the reply channel; MUST be a Reference Object.+    _operationReplyChannel :: Maybe Reference,+    -- | References to the supported reply messages; MUST be a list of+    -- Reference Objects.+    _operationReplyMessages :: Maybe [Reference],+    -- | Specification extensions (@x-@).+    _operationReplyExtensions :: InsOrdHashMap Text Value+  }+  deriving (Eq, Show, Generic)++instance ToJSON OperationReply where+  toJSON = jsonViaEncoding+  toEncoding OperationReply {..} =+    recordEncoding+      _operationReplyExtensions+      [ "address" .=? _operationReplyAddress,+        "channel" .=? _operationReplyChannel,+        "messages" .=? _operationReplyMessages+      ]++instance FromJSON OperationReply where+  parseJSON = withObject "OperationReply" $ \o -> do+    _operationReplyAddress <- o .:? "address"+    _operationReplyChannel <- o .:? "channel"+    _operationReplyMessages <- o .:? "messages"+    let _operationReplyExtensions = parseExtensions o+    pure OperationReply {..}++-- | An 'OperationReply' with only the required fields set.+emptyOperationReply :: OperationReply+emptyOperationReply =+  OperationReply+    { _operationReplyAddress = Nothing,+      _operationReplyChannel = Nothing,+      _operationReplyMessages = Nothing,+      _operationReplyExtensions = InsOrd.empty+    }++-- | Where an operation has to send the reply, as a runtime expression.+--+-- [AsyncAPI 3.1.0 — Operation Reply Address Object](https://www.asyncapi.com/docs/reference/specification/v3.1.0#operationReplyAddressObject)+data OperationReplyAddress = OperationReplyAddress+  { -- | An optional description of the address.+    _operationReplyAddressDescription :: Maybe Description,+    -- | **REQUIRED.** A runtime expression specifying the reply location.+    -- [Runtime Expression](https://www.asyncapi.com/docs/reference/specification/v3.1.0#runtimeExpression)+    _operationReplyAddressLocation :: RuntimeExpression,+    -- | Specification extensions (@x-@).+    _operationReplyAddressExtensions :: InsOrdHashMap Text Value+  }+  deriving (Eq, Show, Generic)++instance ToJSON OperationReplyAddress where+  toJSON = jsonViaEncoding+  toEncoding OperationReplyAddress {..} =+    recordEncoding+      _operationReplyAddressExtensions+      [ "description" .=? _operationReplyAddressDescription,+        "location" .=? Just _operationReplyAddressLocation+      ]++instance FromJSON OperationReplyAddress where+  parseJSON = withObject "OperationReplyAddress" $ \o -> do+    _operationReplyAddressDescription <- o .:? "description"+    _operationReplyAddressLocation <- o .: "location"+    let _operationReplyAddressExtensions = parseExtensions o+    pure OperationReplyAddress {..}++-- | An 'OperationReplyAddress' with only the required fields set.+emptyOperationReplyAddress :: RuntimeExpression -> OperationReplyAddress+emptyOperationReplyAddress loc =+  OperationReplyAddress+    { _operationReplyAddressDescription = Nothing,+      _operationReplyAddressLocation = loc,+      _operationReplyAddressExtensions = InsOrd.empty+    }
+ src/Data/AsyncAPI/Internal/Encoding.hs view
@@ -0,0 +1,113 @@+-- | Ordered, omitting encoders shared by every AsyncAPI object.+--+-- Aeson's 'Data.Aeson.KeyMap.Object' is unordered, so every @ToJSON@ instance+-- in this library defines 'Data.Aeson.toEncoding' explicitly: fields are+-- emitted in the order of the specification's field tables, 'Nothing' fields+-- are omitted, and extension (@x-@) pairs follow the fixed fields in+-- 'InsOrdHashMap' order. This is what makes golden tests byte-stable.+module Data.AsyncAPI.Internal.Encoding+  ( recordEncoding,+    (.=?),+    SortedObject (..),+    extensionsSeries,+    parseExtensions,+    jsonViaEncoding,+    sortInsOrd,+    sortedMapField,+    escapeToken,+    unescapeToken,+  )+where++import Data.Aeson (FromJSON (..), ToJSON (..), Value, (.=))+import Data.Aeson qualified as Aeson+import Data.Aeson.Encoding (Encoding, dict, encodingToLazyByteString, pairs, text)+import Data.Aeson.Key (Key)+import Data.Aeson.Key qualified as Key+import Data.Aeson.KeyMap qualified as KM+import Data.Aeson.Types (Object, Parser, Series, withObject, (.:?))+import Data.Bifunctor (first)+import Data.HashMap.Strict qualified as HMS+import Data.HashMap.Strict.InsOrd (InsOrdHashMap)+import Data.HashMap.Strict.InsOrd qualified as InsOrd+import Data.List (sortOn)+import Data.Maybe (catMaybes)+import Data.Text (Text)+import Data.Text qualified as T++-- | Build an object 'Encoding': fixed-field series in the given (spec table)+-- order, omitting 'Nothing', followed by the @x-@ extension pairs.+recordEncoding :: InsOrdHashMap Text Value -> [Maybe Series] -> Encoding+recordEncoding exts fixed = pairs (mconcat (catMaybes (fixed ++ map Just (extensionsSeries exts))))++-- | Encode an optional field: 'Nothing' produces no series at all, so the+-- key is omitted from the object.+infixr 8 .=?++(.=?) :: (ToJSON a) => Key -> Maybe a -> Maybe Series+k .=? Just v = Just (k .= v)+_ .=? Nothing = Nothing++-- | Extension (@x-@) pairs in 'InsOrdHashMap' order.+extensionsSeries :: InsOrdHashMap Text Value -> [Series]+extensionsSeries = map (\(k, v) -> Key.fromText k .= v) . InsOrd.toList++-- | Collect the @x-@ extension keys from a parsed object, sorted by key+-- (aeson's 'Data.Aeson.KeyMap' loses source order; see the umbrella module).+parseExtensions :: Object -> InsOrdHashMap Text Value+parseExtensions =+  InsOrd.fromList+    . sortOn fst+    . map (first Key.toText)+    . filter (T.isPrefixOf "x-" . Key.toText . fst)+    . KM.toList++-- | Apply RFC 6901 token escaping (@~@ -> @~0@, @/@ -> @~1@).+escapeToken :: Text -> Text+escapeToken = T.replace "~" "~0" . T.replace "/" "~1"++-- | Undo RFC 6901 token escaping (~1 first, then ~0).+unescapeToken :: Text -> Text+unescapeToken = T.replace "~0" "~" . T.replace "~1" "/"++-- | Derive 'toJSON' from a type's ordered 'toEncoding'. Aeson's default+-- 'toJSON' goes through 'GHC.Generics' and loses the fixed-field order (and+-- mis-tags manual sum encodings), so every model instance defines+-- @toJSON = jsonViaEncoding@.+jsonViaEncoding :: (ToJSON a) => a -> Value+jsonViaEncoding a = case Aeson.eitherDecode' (encodingToLazyByteString (toEncoding a)) of+  Right v -> v+  Left e -> error ("jsonViaEncoding: impossible decode failure: " <> e)++-- | JSON-boundary newtype: encodes/decodes an 'InsOrdHashMap Text v' as a JSON+-- object (encode order = insertion order), independent of+-- insert-ordered-containers' own aeson instances (0.3.x emits pair arrays).+--+-- Decode deliberately does NOT sort: it reproduces 0.2.7's behavior+-- (insertion order = hash order of the key set) so fragment goldens stay+-- byte-identical; document-level sorting lives in 'sortedMapField'.+newtype SortedObject v = SortedObject {unSortedObject :: InsOrdHashMap Text v}+  deriving newtype (Eq, Show)++instance (ToJSON v) => ToJSON (SortedObject v) where+  toJSON = jsonViaEncoding+  toEncoding (SortedObject m) =+    dict text toEncoding InsOrd.foldrWithKey m++instance (FromJSON v) => FromJSON (SortedObject v) where+  -- 0.2.7's FromJSON1 decodes through a plain 'HashMap' and converts with+  -- 'fromList . HashMap.toList', so the insertion order (and hence the+  -- reencoded order) is the hash order of the key set, not the JSON source+  -- order and not aeson's KeyMap iteration order. Reproduce exactly.+  parseJSON = withObject "map" $ \o ->+    SortedObject . InsOrd.fromList . HMS.toList . HMS.fromList+      <$> traverse (\(k, v) -> (,) (Key.toText k) <$> parseJSON v) (KM.toList o)++-- | Sort a decoded map by key (aeson's key-map loses source order; see the+-- umbrella module for the roundtrip contract).+sortInsOrd :: InsOrdHashMap Text a -> InsOrdHashMap Text a+sortInsOrd = InsOrd.fromList . sortOn fst . InsOrd.toList++-- | Decode an optional object-valued field as a key-sorted 'InsOrdHashMap'.+sortedMapField :: (FromJSON a) => Key -> Object -> Parser (Maybe (InsOrdHashMap Text a))+sortedMapField k o = fmap (sortInsOrd . unSortedObject) <$> o .:? k
+ src/Data/AsyncAPI/Internal/FieldNames.hs view
@@ -0,0 +1,75 @@+-- | Explicit field-name mappings for records whose JSON keys are Haskell+-- keywords; used with @makeFieldLabelsFor@ by the optics interface.+module Data.AsyncAPI.Internal.FieldNames+  ( parameterFields,+    serverVariableFields,+    schemaObjFields,+  )+where++-- | Parameter Object fields, mapped to label names (@default@ is a Haskell+-- keyword).+parameterFields :: [(String, String)]+parameterFields =+  [ ("_parameterEnum", "enum"),+    ("_parameterDefault", "default_"),+    ("_parameterDescription", "description"),+    ("_parameterExamples", "examples"),+    ("_parameterLocation", "location")+  ]++-- | Server Variable Object fields (@default@ is a Haskell keyword).+serverVariableFields :: [(String, String)]+serverVariableFields =+  [ ("_serverVariableEnum", "enum"),+    ("_serverVariableDefault", "default_"),+    ("_serverVariableDescription", "description"),+    ("_serverVariableExamples", "examples")+  ]++-- | Schema Object fields (@type@, @if@, @then@, @else@ and @default@ are+-- Haskell keywords).+schemaObjFields :: [(String, String)]+schemaObjFields =+  [ ("_schemaTitle", "title"),+    ("_schemaType", "type_"),+    ("_schemaRequired", "required"),+    ("_schemaMultipleOf", "multipleOf"),+    ("_schemaMaximum", "maximum"),+    ("_schemaExclusiveMaximum", "exclusiveMaximum"),+    ("_schemaMinimum", "minimum"),+    ("_schemaExclusiveMinimum", "exclusiveMinimum"),+    ("_schemaMaxLength", "maxLength"),+    ("_schemaMinLength", "minLength"),+    ("_schemaPattern", "pattern"),+    ("_schemaMaxItems", "maxItems"),+    ("_schemaMinItems", "minItems"),+    ("_schemaUniqueItems", "uniqueItems"),+    ("_schemaMaxProperties", "maxProperties"),+    ("_schemaMinProperties", "minProperties"),+    ("_schemaEnum", "enum"),+    ("_schemaConst", "const"),+    ("_schemaExamples", "examples"),+    ("_schemaIf", "if_"),+    ("_schemaThen", "then_"),+    ("_schemaElse", "else_"),+    ("_schemaReadOnly", "readOnly"),+    ("_schemaWriteOnly", "writeOnly"),+    ("_schemaProperties", "properties"),+    ("_schemaPatternProperties", "patternProperties"),+    ("_schemaAdditionalProperties", "additionalProperties"),+    ("_schemaAdditionalItems", "additionalItems"),+    ("_schemaItems", "items"),+    ("_schemaPropertyNames", "propertyNames"),+    ("_schemaContains", "contains"),+    ("_schemaAllOf", "allOf"),+    ("_schemaOneOf", "oneOf"),+    ("_schemaAnyOf", "anyOf"),+    ("_schemaNot", "not"),+    ("_schemaDescription", "description"),+    ("_schemaFormat", "format"),+    ("_schemaDefault", "default_"),+    ("_schemaDiscriminator", "discriminator"),+    ("_schemaExternalDocs", "externalDocs"),+    ("_schemaDeprecated", "deprecated")+  ]
+ src/Data/AsyncAPI/Internal/Referenced.hs view
@@ -0,0 +1,177 @@+-- | Reference and simple shared metadata objects used across the model.+module Data.AsyncAPI.Internal.Referenced+  ( Reference (..),+    emptyReference,+    Referenced (..),+    ExternalDocumentation (..),+    emptyExternalDocumentation,+    Tags,+    Tag (..),+    emptyTag,+  )+where++import Data.Aeson (FromJSON (..), ToJSON (..), Value (..), withObject, (.:), (.:?))+import Data.Aeson.KeyMap qualified as KM+import Data.AsyncAPI.Internal.Encoding+import Data.AsyncAPI.Internal.Types+import Data.HashMap.Strict.InsOrd (InsOrdHashMap)+import Data.HashMap.Strict.InsOrd qualified as InsOrd+import Data.Text (Text)+import GHC.Generics (Generic)++-- | A reference to an external resource for extended documentation.+--+-- [AsyncAPI 3.1.0 — External Documentation Object](https://www.asyncapi.com/docs/reference/specification/v3.1.0#externalDocumentationObject)+data ExternalDocumentation = ExternalDocumentation+  { -- | A short description of the target documentation.+    _externalDocumentationDescription :: Maybe Description,+    -- | **REQUIRED.** The URL for the target documentation.+    _externalDocumentationUrl :: Url,+    -- | Specification extensions (@x-@).+    _externalDocumentationExtensions :: InsOrdHashMap Text Value+  }+  deriving (Eq, Show, Generic)++instance ToJSON ExternalDocumentation where+  toJSON = jsonViaEncoding+  toEncoding ExternalDocumentation {..} =+    recordEncoding+      _externalDocumentationExtensions+      [ "description" .=? _externalDocumentationDescription,+        "url" .=? Just _externalDocumentationUrl+      ]++instance FromJSON ExternalDocumentation where+  parseJSON = withObject "ExternalDocumentation" $ \o -> do+    _externalDocumentationDescription <- o .:? "description"+    _externalDocumentationUrl <- o .: "url"+    let _externalDocumentationExtensions = parseExtensions o+    pure ExternalDocumentation {..}++-- | An 'ExternalDocumentation' with only the required fields set.+emptyExternalDocumentation :: Url -> ExternalDocumentation+emptyExternalDocumentation u =+  ExternalDocumentation+    { _externalDocumentationDescription = Nothing,+      _externalDocumentationUrl = u,+      _externalDocumentationExtensions = InsOrd.empty+    }++-- | A simple object allowing referencing other components, internally and+-- externally. The 3.1 Reference Object defines exactly one field (@$ref@);+-- per the specification it cannot be extended and additional properties are+-- ignored.+--+-- [AsyncAPI 3.1.0 — Reference Object](https://www.asyncapi.com/docs/reference/specification/v3.1.0#referenceObject)+data Reference = Reference+  { -- | **REQUIRED.** The reference string.+    _reference :: Text+  }+  deriving (Eq, Show, Generic)++instance ToJSON Reference where+  toJSON = jsonViaEncoding+  toEncoding Reference {..} = recordEncoding InsOrd.empty ["$ref" .=? Just _reference]++instance FromJSON Reference where+  parseJSON = withObject "Reference" $ \o -> do+    _reference <- o .: "$ref"+    pure Reference {..}++-- | A 'Reference' with only the required fields set.+emptyReference :: Text -> Reference+emptyReference r =+  Reference+    { _reference = r+    }++-- | An inline definition or a 'Reference'.+--+-- Note: decoding peeks for a @$ref@ key, so an object carrying @$ref@ plus+-- sibling keywords (draft-07 allows @"$ref"@ next to @description@ etc.+-- inside Schema Objects) is silently narrowed to 'Ref' and the siblings are+-- dropped; sibling-keyword refs are not representable in this model.+--+-- [AsyncAPI 3.1.0 — Reference Object](https://www.asyncapi.com/docs/reference/specification/v3.1.0#referenceObject)+data Referenced a+  = -- | A definition written inline.+    Inline a+  | -- | A reference to a definition elsewhere.+    Ref Reference+  deriving (Eq, Show, Generic)++instance Functor Referenced where+  fmap f (Inline a) = Inline (f a)+  fmap _ (Ref r) = Ref r++instance Foldable Referenced where+  foldMap f (Inline a) = f a+  foldMap _ (Ref _) = mempty++instance Traversable Referenced where+  traverse f (Inline a) = Inline <$> f a+  traverse _ (Ref r) = pure (Ref r)++instance (ToJSON a) => ToJSON (Referenced a) where+  toJSON = jsonViaEncoding+  toEncoding (Inline a) = toEncoding a+  toEncoding (Ref r) = toEncoding r++instance (FromJSON a) => FromJSON (Referenced a) where+  parseJSON v@(Object o)+    | KM.member "$ref" o = Ref <$> parseJSON v+    | otherwise = Inline <$> parseJSON v+  parseJSON v = Inline <$> parseJSON v++-- $ metadata+--+-- [AsyncAPI 3.1.0 — Tags Object](https://www.asyncapi.com/docs/reference/specification/v3.1.0#tagsObject)++-- | A list of (possibly referenced) tags.+--+-- [AsyncAPI 3.1.0 — Tags Object](https://www.asyncapi.com/docs/reference/specification/v3.1.0#tagsObject)+type Tags = [Referenced Tag]++-- | Metadata attached to a single tag.+--+-- [AsyncAPI 3.1.0 — Tag Object](https://www.asyncapi.com/docs/reference/specification/v3.1.0#tagObject)+data Tag = Tag+  { -- | **REQUIRED.** The name of the tag.+    _tagName :: Name,+    -- | A short description for the tag.+    _tagDescription :: Maybe Description,+    -- | Additional external documentation for this tag.+    _tagExternalDocs :: Maybe (Referenced ExternalDocumentation),+    -- | Specification extensions (@x-@).+    _tagExtensions :: InsOrdHashMap Text Value+  }+  deriving (Eq, Show, Generic)++instance ToJSON Tag where+  toJSON = jsonViaEncoding+  toEncoding Tag {..} =+    recordEncoding+      _tagExtensions+      [ "name" .=? Just _tagName,+        "description" .=? _tagDescription,+        "externalDocs" .=? _tagExternalDocs+      ]++instance FromJSON Tag where+  parseJSON = withObject "Tag" $ \o -> do+    _tagName <- o .: "name"+    _tagDescription <- o .:? "description"+    _tagExternalDocs <- o .:? "externalDocs"+    let _tagExtensions = parseExtensions o+    pure Tag {..}++-- | A 'Tag' with only the required fields set.+emptyTag :: Name -> Tag+emptyTag n =+  Tag+    { _tagName = n,+      _tagDescription = Nothing,+      _tagExternalDocs = Nothing,+      _tagExtensions = InsOrd.empty+    }
+ src/Data/AsyncAPI/Internal/Schema.hs view
@@ -0,0 +1,399 @@+-- | The AsyncAPI 3.1.0 Schema Object: a superset of JSON Schema Draft 07+-- plus @discriminator@, @externalDocs@ and @deprecated@.+module Data.AsyncAPI.Internal.Schema+  ( Schema (..),+    SchemaObj (..),+    emptySchemaObj,+    JsonType (..),+    SchemaType (..),+    ItemsSchema (..),+    AdditionalProperties (..),+  )+where++import Control.Applicative ((<|>))+import Data.Aeson+  ( FromJSON (..),+    ToJSON (..),+    Value (..),+    withObject,+    withText,+    (.:?),+  )+import Data.AsyncAPI.Internal.Encoding+import Data.AsyncAPI.Internal.Referenced+import Data.AsyncAPI.Internal.Types+import Data.HashMap.Strict.InsOrd (InsOrdHashMap)+import Data.HashMap.Strict.InsOrd qualified as InsOrd+import Data.List.NonEmpty (NonEmpty)+import Data.Scientific (Scientific)+import Data.Text (Text)+import GHC.Generics (Generic)++-- | A JSON Schema type name.+--+-- [Schema Object](https://www.asyncapi.com/docs/reference/specification/v3.1.0#schemaObject)+data JsonType+  = JsonNull+  | JsonBoolean+  | JsonObject+  | JsonArray+  | JsonNumber+  | -- | Draft-07 @integer@ (subset of @number@).+    JsonInteger+  | JsonString+  deriving (Eq, Show, Generic)++instance ToJSON JsonType where+  toJSON = jsonViaEncoding+  toEncoding t = toEncoding (jsonTypeText t)++instance FromJSON JsonType where+  parseJSON = withText "JsonType" $ \t ->+    maybe (fail ("unknown JSON type: " <> show t)) pure (jsonTypeFromText t)++jsonTypeText :: JsonType -> Text+jsonTypeText = \case+  JsonNull -> "null"+  JsonBoolean -> "boolean"+  JsonObject -> "object"+  JsonArray -> "array"+  JsonNumber -> "number"+  JsonInteger -> "integer"+  JsonString -> "string"++jsonTypeFromText :: Text -> Maybe JsonType+jsonTypeFromText = \case+  "null" -> Just JsonNull+  "boolean" -> Just JsonBoolean+  "object" -> Just JsonObject+  "array" -> Just JsonArray+  "number" -> Just JsonNumber+  "integer" -> Just JsonInteger+  "string" -> Just JsonString+  _ -> Nothing++-- | The @type@ keyword: a single type or a union of types.+--+-- [Schema Object](https://www.asyncapi.com/docs/reference/specification/v3.1.0#schemaObject)+data SchemaType+  = -- | @type: string@ style.+    SingleType JsonType+  | -- | @type: [string, "null"]@ style.+    MultiType (NonEmpty JsonType)+  deriving (Eq, Show, Generic)++instance ToJSON SchemaType where+  toJSON = jsonViaEncoding+  toEncoding (SingleType t) = toEncoding t+  toEncoding (MultiType ts) = toEncoding ts++instance FromJSON SchemaType where+  parseJSON v = single <|> multi+    where+      single = SingleType <$> parseJSON v+      multi = MultiType <$> parseJSON v++-- | The @items@ keyword: one schema for all items, or per-position schemas.+--+-- [Schema Object](https://www.asyncapi.com/docs/reference/specification/v3.1.0#schemaObject)+data ItemsSchema+  = -- | A single schema applied to every item.+    SingleItem (Referenced Schema)+  | -- | A schema per tuple position.+    ItemList [Referenced Schema]+  deriving (Eq, Show, Generic)++instance ToJSON ItemsSchema where+  toJSON = jsonViaEncoding+  toEncoding (SingleItem s) = toEncoding s+  toEncoding (ItemList ss) = toEncoding ss++instance FromJSON ItemsSchema where+  parseJSON v = single <|> list+    where+      single = SingleItem <$> parseJSON v+      list = ItemList <$> parseJSON v++-- | @additionalProperties@ (and @additionalItems@): an on\/off flag or a+-- schema.+--+-- [Schema Object](https://www.asyncapi.com/docs/reference/specification/v3.1.0#schemaObject)+data AdditionalProperties+  = -- | @additionalProperties: false@ (or @true@).+    AllowAdditional Bool+  | -- | @additionalProperties: {schema}@.+    AdditionalSchema (Referenced Schema)+  deriving (Eq, Show, Generic)++instance ToJSON AdditionalProperties where+  toJSON = jsonViaEncoding+  toEncoding (AllowAdditional b) = toEncoding b+  toEncoding (AdditionalSchema s) = toEncoding s++instance FromJSON AdditionalProperties where+  parseJSON v = bool <|> schema+    where+      bool = AllowAdditional <$> parseJSON v+      schema = AdditionalSchema <$> parseJSON v++-- | A schema: either a JSON Schema boolean or a Schema Object. The empty+-- schema (allowing everything) is @BooleanSchema True@; a schema allowing+-- nothing is @BooleanSchema False@.+--+-- [AsyncAPI 3.1.0 — Schema Object](https://www.asyncapi.com/docs/reference/specification/v3.1.0#schemaObject)+data Schema+  = BooleanSchema Bool+  | SchemaObject SchemaObj+  deriving (Eq, Show, Generic)++instance ToJSON Schema where+  toJSON = jsonViaEncoding+  toEncoding (BooleanSchema b) = toEncoding b+  toEncoding (SchemaObject o) = toEncoding o++instance FromJSON Schema where+  parseJSON (Bool b) = pure (BooleanSchema b)+  parseJSON v = SchemaObject <$> parseJSON v++-- | A Schema Object with no keywords set.+emptySchemaObj :: SchemaObj+emptySchemaObj =+  SchemaObj+    { _schemaTitle = Nothing,+      _schemaType = Nothing,+      _schemaRequired = Nothing,+      _schemaMultipleOf = Nothing,+      _schemaMaximum = Nothing,+      _schemaExclusiveMaximum = Nothing,+      _schemaMinimum = Nothing,+      _schemaExclusiveMinimum = Nothing,+      _schemaMaxLength = Nothing,+      _schemaMinLength = Nothing,+      _schemaPattern = Nothing,+      _schemaMaxItems = Nothing,+      _schemaMinItems = Nothing,+      _schemaUniqueItems = Nothing,+      _schemaMaxProperties = Nothing,+      _schemaMinProperties = Nothing,+      _schemaEnum = Nothing,+      _schemaConst = Nothing,+      _schemaExamples = Nothing,+      _schemaIf = Nothing,+      _schemaThen = Nothing,+      _schemaElse = Nothing,+      _schemaReadOnly = Nothing,+      _schemaWriteOnly = Nothing,+      _schemaProperties = Nothing,+      _schemaPatternProperties = Nothing,+      _schemaAdditionalProperties = Nothing,+      _schemaAdditionalItems = Nothing,+      _schemaItems = Nothing,+      _schemaPropertyNames = Nothing,+      _schemaContains = Nothing,+      _schemaAllOf = Nothing,+      _schemaOneOf = Nothing,+      _schemaAnyOf = Nothing,+      _schemaNot = Nothing,+      _schemaDescription = Nothing,+      _schemaFormat = Nothing,+      _schemaDefault = Nothing,+      _schemaDiscriminator = Nothing,+      _schemaExternalDocs = Nothing,+      _schemaDeprecated = Nothing,+      _schemaExtensions = InsOrd.empty+    }++-- | The Schema Object record. Field order in 'ToJSON' follows the order the+-- keywords are listed in the specification's Properties section, with the+-- AsyncAPI-specific Fixed Fields (@discriminator@, @externalDocs@,+-- @deprecated@) at the end.+--+-- [AsyncAPI 3.1.0 — Schema Object](https://www.asyncapi.com/docs/reference/specification/v3.1.0#schemaObject)+data SchemaObj = SchemaObj+  { -- | @title@.+    -- [Schema Object](https://www.asyncapi.com/docs/reference/specification/v3.1.0#schemaObject)+    _schemaTitle :: Maybe Title,+    -- | @type@.+    _schemaType :: Maybe SchemaType,+    -- | @required@.+    _schemaRequired :: Maybe [Text],+    -- | @multipleOf@.+    _schemaMultipleOf :: Maybe Scientific,+    -- | @maximum@.+    _schemaMaximum :: Maybe Scientific,+    -- | @exclusiveMaximum@ (draft-07 numeric form).+    _schemaExclusiveMaximum :: Maybe Scientific,+    -- | @minimum@.+    _schemaMinimum :: Maybe Scientific,+    -- | @exclusiveMinimum@ (draft-07 numeric form).+    _schemaExclusiveMinimum :: Maybe Scientific,+    -- | @maxLength@.+    _schemaMaxLength :: Maybe Int,+    -- | @minLength@.+    _schemaMinLength :: Maybe Int,+    -- | @pattern@.+    _schemaPattern :: Maybe Text,+    -- | @maxItems@.+    _schemaMaxItems :: Maybe Int,+    -- | @minItems@.+    _schemaMinItems :: Maybe Int,+    -- | @uniqueItems@.+    _schemaUniqueItems :: Maybe Bool,+    -- | @maxProperties@.+    _schemaMaxProperties :: Maybe Int,+    -- | @minProperties@.+    _schemaMinProperties :: Maybe Int,+    -- | @enum@.+    _schemaEnum :: Maybe [Value],+    -- | @const@.+    _schemaConst :: Maybe Value,+    -- | @examples@.+    _schemaExamples :: Maybe [Value],+    -- | @if@.+    _schemaIf :: Maybe (Referenced Schema),+    -- | @then@.+    _schemaThen :: Maybe (Referenced Schema),+    -- | @else@.+    _schemaElse :: Maybe (Referenced Schema),+    -- | @readOnly@.+    _schemaReadOnly :: Maybe Bool,+    -- | @writeOnly@.+    _schemaWriteOnly :: Maybe Bool,+    -- | @properties@.+    _schemaProperties :: Maybe (InsOrdHashMap Text (Referenced Schema)),+    -- | @patternProperties@.+    _schemaPatternProperties :: Maybe (InsOrdHashMap Text (Referenced Schema)),+    -- | @additionalProperties@.+    _schemaAdditionalProperties :: Maybe AdditionalProperties,+    -- | @additionalItems@.+    _schemaAdditionalItems :: Maybe AdditionalProperties,+    -- | @items@.+    _schemaItems :: Maybe ItemsSchema,+    -- | @propertyNames@.+    _schemaPropertyNames :: Maybe (Referenced Schema),+    -- | @contains@.+    _schemaContains :: Maybe (Referenced Schema),+    -- | @allOf@.+    -- [Composition and Inheritance](https://www.asyncapi.com/docs/reference/specification/v3.1.0#schemaComposition)+    _schemaAllOf :: Maybe [Referenced Schema],+    -- | @oneOf@.+    _schemaOneOf :: Maybe [Referenced Schema],+    -- | @anyOf@.+    _schemaAnyOf :: Maybe [Referenced Schema],+    -- | @not@.+    _schemaNot :: Maybe (Referenced Schema),+    -- | @description@ (adjusted: CommonMark allowed).+    _schemaDescription :: Maybe Description,+    -- | @format@ (adjusted: see Data Type Formats).+    -- [Data Type Formats](https://www.asyncapi.com/docs/reference/specification/v3.1.0#dataTypeFormat)+    _schemaFormat :: Maybe Text,+    -- | @default@ (adjusted: MUST conform to the schema's type).+    _schemaDefault :: Maybe Value,+    -- | @discriminator@.+    -- [Schema Object, discriminator](https://www.asyncapi.com/docs/reference/specification/v3.1.0#schemaObjectDiscriminator)+    _schemaDiscriminator :: Maybe Text,+    -- | @externalDocs@.+    -- [Schema Object, externalDocs](https://www.asyncapi.com/docs/reference/specification/v3.1.0#schemaObjectExternalDocs)+    _schemaExternalDocs :: Maybe (Referenced ExternalDocumentation),+    -- | @deprecated@ (default @false@).+    -- [Schema Object, deprecated](https://www.asyncapi.com/docs/reference/specification/v3.1.0#schemaObjectDeprecated)+    _schemaDeprecated :: Maybe Bool,+    -- | Specification extensions (@x-@).+    _schemaExtensions :: InsOrdHashMap Text Value+  }+  deriving (Eq, Show, Generic)++instance ToJSON SchemaObj where+  toJSON = jsonViaEncoding+  toEncoding SchemaObj {..} =+    recordEncoding+      _schemaExtensions+      [ "title" .=? _schemaTitle,+        "type" .=? _schemaType,+        "required" .=? _schemaRequired,+        "multipleOf" .=? _schemaMultipleOf,+        "maximum" .=? _schemaMaximum,+        "exclusiveMaximum" .=? _schemaExclusiveMaximum,+        "minimum" .=? _schemaMinimum,+        "exclusiveMinimum" .=? _schemaExclusiveMinimum,+        "maxLength" .=? _schemaMaxLength,+        "minLength" .=? _schemaMinLength,+        "pattern" .=? _schemaPattern,+        "maxItems" .=? _schemaMaxItems,+        "minItems" .=? _schemaMinItems,+        "uniqueItems" .=? _schemaUniqueItems,+        "maxProperties" .=? _schemaMaxProperties,+        "minProperties" .=? _schemaMinProperties,+        "enum" .=? _schemaEnum,+        "const" .=? _schemaConst,+        "examples" .=? _schemaExamples,+        "if" .=? _schemaIf,+        "then" .=? _schemaThen,+        "else" .=? _schemaElse,+        "readOnly" .=? _schemaReadOnly,+        "writeOnly" .=? _schemaWriteOnly,+        "properties" .=? fmap SortedObject _schemaProperties,+        "patternProperties" .=? fmap SortedObject _schemaPatternProperties,+        "additionalProperties" .=? _schemaAdditionalProperties,+        "additionalItems" .=? _schemaAdditionalItems,+        "items" .=? _schemaItems,+        "propertyNames" .=? _schemaPropertyNames,+        "contains" .=? _schemaContains,+        "allOf" .=? _schemaAllOf,+        "oneOf" .=? _schemaOneOf,+        "anyOf" .=? _schemaAnyOf,+        "not" .=? _schemaNot,+        "description" .=? _schemaDescription,+        "format" .=? _schemaFormat,+        "default" .=? _schemaDefault,+        "discriminator" .=? _schemaDiscriminator,+        "externalDocs" .=? _schemaExternalDocs,+        "deprecated" .=? _schemaDeprecated+      ]++instance FromJSON SchemaObj where+  parseJSON = withObject "SchemaObj" $ \o -> do+    _schemaTitle <- o .:? "title"+    _schemaType <- o .:? "type"+    _schemaRequired <- o .:? "required"+    _schemaMultipleOf <- o .:? "multipleOf"+    _schemaMaximum <- o .:? "maximum"+    _schemaExclusiveMaximum <- o .:? "exclusiveMaximum"+    _schemaMinimum <- o .:? "minimum"+    _schemaExclusiveMinimum <- o .:? "exclusiveMinimum"+    _schemaMaxLength <- o .:? "maxLength"+    _schemaMinLength <- o .:? "minLength"+    _schemaPattern <- o .:? "pattern"+    _schemaMaxItems <- o .:? "maxItems"+    _schemaMinItems <- o .:? "minItems"+    _schemaUniqueItems <- o .:? "uniqueItems"+    _schemaMaxProperties <- o .:? "maxProperties"+    _schemaMinProperties <- o .:? "minProperties"+    _schemaEnum <- o .:? "enum"+    _schemaConst <- o .:? "const"+    _schemaExamples <- o .:? "examples"+    _schemaIf <- o .:? "if"+    _schemaThen <- o .:? "then"+    _schemaElse <- o .:? "else"+    _schemaReadOnly <- o .:? "readOnly"+    _schemaWriteOnly <- o .:? "writeOnly"+    _schemaProperties <- sortedMapField "properties" o+    _schemaPatternProperties <- sortedMapField "patternProperties" o+    _schemaAdditionalProperties <- o .:? "additionalProperties"+    _schemaAdditionalItems <- o .:? "additionalItems"+    _schemaItems <- o .:? "items"+    _schemaPropertyNames <- o .:? "propertyNames"+    _schemaContains <- o .:? "contains"+    _schemaAllOf <- o .:? "allOf"+    _schemaOneOf <- o .:? "oneOf"+    _schemaAnyOf <- o .:? "anyOf"+    _schemaNot <- o .:? "not"+    _schemaDescription <- o .:? "description"+    _schemaFormat <- o .:? "format"+    _schemaDefault <- o .:? "default"+    _schemaDiscriminator <- o .:? "discriminator"+    _schemaExternalDocs <- o .:? "externalDocs"+    _schemaDeprecated <- o .:? "deprecated"+    let _schemaExtensions = parseExtensions o+    pure SchemaObj {..}
+ src/Data/AsyncAPI/Internal/Types.hs view
@@ -0,0 +1,65 @@+-- | Shared newtype wrappers for repeated text fields of the AsyncAPI 3.1.0+-- model. Every wrapper derives 'IsString' (string literals work under+-- 'OverloadedStrings') and newtype-derives JSON instances, so encoding and+-- decoding are byte-identical to bare 'Text'.+module Data.AsyncAPI.Internal.Types+  ( Title (..),+    Name (..),+    Version (..),+    Id (..),+    Summary (..),+    Description (..),+    Url (..),+    ContentType (..),+    RuntimeExpression (..),+  )+where++import Data.Aeson (FromJSON, ToJSON)+import Data.String (IsString)+import Data.Text (Text)++-- | The title of an API, server, channel, message, operation, or schema.+newtype Title = Title {getTitle :: Text}+  deriving stock (Eq, Ord, Show)+  deriving newtype (IsString, ToJSON, FromJSON)++-- | A machine- or human-assigned name (contact, license, tag, message, ...).+newtype Name = Name {getName :: Text}+  deriving stock (Eq, Ord, Show)+  deriving newtype (IsString, ToJSON, FromJSON)++-- | A version string (API version, spec version, protocol version).+newtype Version = Version {getVersion :: Text}+  deriving stock (Eq, Ord, Show)+  deriving newtype (IsString, ToJSON, FromJSON)++-- | The application identifier of an AsyncAPI document.+newtype Id = Id {getId :: Text}+  deriving stock (Eq, Ord, Show)+  deriving newtype (IsString, ToJSON, FromJSON)++-- | A short summary of a server, channel, message, or operation.+newtype Summary = Summary {getSummary :: Text}+  deriving stock (Eq, Ord, Show)+  deriving newtype (IsString, ToJSON, FromJSON)++-- | A prose description (CommonMark allowed).+newtype Description = Description {getDescription :: Text}+  deriving stock (Eq, Ord, Show)+  deriving newtype (IsString, ToJSON, FromJSON)++-- | A URL (terms of service, contact, license, documentation, OAuth, ...).+newtype Url = Url {getUrl :: Text}+  deriving stock (Eq, Ord, Show)+  deriving newtype (IsString, ToJSON, FromJSON)++-- | A media type for message payloads.+newtype ContentType = ContentType {getContentType :: Text}+  deriving stock (Eq, Ord, Show)+  deriving newtype (IsString, ToJSON, FromJSON)++-- | An AsyncAPI runtime expression (e.g. @$message.header#\/cid@).+newtype RuntimeExpression = RuntimeExpression {getRuntimeExpression :: Text}+  deriving stock (Eq, Ord, Show)+  deriving newtype (IsString, ToJSON, FromJSON)
+ src/Data/AsyncAPI/Lens.hs view
@@ -0,0 +1,260 @@+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE FunctionalDependencies #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE UndecidableInstances #-}++-- | Field lenses and prisms for the AsyncAPI 3.1.0 model, built with+-- @lens@. Generated field lenses are named after the JSON keys (e.g.+-- @title@ on both 'Info' and 'Message').+--+-- Four records contain fields whose JSON keys are Haskell keywords+-- (@type@, @if@, @then@, @else@, @default@, @in@); they cannot use+-- 'makeFields' (the method name would be a keyword), so their fields get+-- explicit type-prefixed lenses instead: @schemaObj*@, @serverVariable*@,+-- @parameter*@, @securityScheme*@ (no underscores).+module Data.AsyncAPI.Lens+  ( module Data.AsyncAPI.Lens,+    module Data.AsyncAPI.Internal,+    module Data.AsyncAPI.Internal.Schema,+  )+where++import Control.Lens (Lens', lens)+import Control.Lens.TH (makeFields, makePrisms)+import Data.Aeson (Value)+import Data.AsyncAPI.Internal+import Data.AsyncAPI.Internal.Schema+import Data.HashMap.Strict.InsOrd (InsOrdHashMap)+import Data.Scientific (Scientific)+import Data.Text (Text)++-- Root+makeFields ''AsyncAPI+makeFields ''Info+makeFields ''Contact+makeFields ''License+makeFields ''Server+makeFields ''Channel+makeFields ''Tag+makeFields ''ExternalDocumentation+makeFields ''Reference+makeFields ''Components++-- Security (type/in are keywords; explicit lenses below)+makeFields ''OAuthFlows+makeFields ''OAuthFlow++-- Bindings+makeFields ''ServerBindings+makeFields ''ChannelBindings+makeFields ''OperationBindings+makeFields ''MessageBindings++-- Schemas (type/if/then/else/default are keywords; explicit lenses below)+makeFields ''MultiFormatSchema++-- Messages+makeFields ''Message+makeFields ''MessageTrait+makeFields ''MessageExample+makeFields ''CorrelationId++-- Operations+makeFields ''Operation+makeFields ''OperationTrait+makeFields ''OperationReply+makeFields ''OperationReplyAddress++-- Prisms for sum types+makePrisms ''Referenced+makePrisms ''Schema+makePrisms ''SchemaType+makePrisms ''ItemsSchema+makePrisms ''AdditionalProperties+makePrisms ''SchemaDefinition+makePrisms ''SecuritySchemeType+makePrisms ''ApiKeyLocation+makePrisms ''OperationAction+makePrisms ''JsonType++-- Schema Object lenses+schemaObjTitle :: Lens' SchemaObj (Maybe Title)+schemaObjTitle = lens _schemaTitle (\s a -> s {_schemaTitle = a})++schemaObjType :: Lens' SchemaObj (Maybe SchemaType)+schemaObjType = lens _schemaType (\s a -> s {_schemaType = a})++schemaObjRequired :: Lens' SchemaObj (Maybe [Text])+schemaObjRequired = lens _schemaRequired (\s a -> s {_schemaRequired = a})++schemaObjMultipleOf :: Lens' SchemaObj (Maybe Scientific)+schemaObjMultipleOf = lens _schemaMultipleOf (\s a -> s {_schemaMultipleOf = a})++schemaObjMaximum :: Lens' SchemaObj (Maybe Scientific)+schemaObjMaximum = lens _schemaMaximum (\s a -> s {_schemaMaximum = a})++schemaObjExclusiveMaximum :: Lens' SchemaObj (Maybe Scientific)+schemaObjExclusiveMaximum = lens _schemaExclusiveMaximum (\s a -> s {_schemaExclusiveMaximum = a})++schemaObjMinimum :: Lens' SchemaObj (Maybe Scientific)+schemaObjMinimum = lens _schemaMinimum (\s a -> s {_schemaMinimum = a})++schemaObjExclusiveMinimum :: Lens' SchemaObj (Maybe Scientific)+schemaObjExclusiveMinimum = lens _schemaExclusiveMinimum (\s a -> s {_schemaExclusiveMinimum = a})++schemaObjMaxLength :: Lens' SchemaObj (Maybe Int)+schemaObjMaxLength = lens _schemaMaxLength (\s a -> s {_schemaMaxLength = a})++schemaObjMinLength :: Lens' SchemaObj (Maybe Int)+schemaObjMinLength = lens _schemaMinLength (\s a -> s {_schemaMinLength = a})++schemaObjPattern :: Lens' SchemaObj (Maybe Text)+schemaObjPattern = lens _schemaPattern (\s a -> s {_schemaPattern = a})++schemaObjMaxItems :: Lens' SchemaObj (Maybe Int)+schemaObjMaxItems = lens _schemaMaxItems (\s a -> s {_schemaMaxItems = a})++schemaObjMinItems :: Lens' SchemaObj (Maybe Int)+schemaObjMinItems = lens _schemaMinItems (\s a -> s {_schemaMinItems = a})++schemaObjUniqueItems :: Lens' SchemaObj (Maybe Bool)+schemaObjUniqueItems = lens _schemaUniqueItems (\s a -> s {_schemaUniqueItems = a})++schemaObjMaxProperties :: Lens' SchemaObj (Maybe Int)+schemaObjMaxProperties = lens _schemaMaxProperties (\s a -> s {_schemaMaxProperties = a})++schemaObjMinProperties :: Lens' SchemaObj (Maybe Int)+schemaObjMinProperties = lens _schemaMinProperties (\s a -> s {_schemaMinProperties = a})++schemaObjEnum :: Lens' SchemaObj (Maybe [Value])+schemaObjEnum = lens _schemaEnum (\s a -> s {_schemaEnum = a})++schemaObjConst :: Lens' SchemaObj (Maybe Value)+schemaObjConst = lens _schemaConst (\s a -> s {_schemaConst = a})++schemaObjExamples :: Lens' SchemaObj (Maybe [Value])+schemaObjExamples = lens _schemaExamples (\s a -> s {_schemaExamples = a})++schemaObjIf :: Lens' SchemaObj (Maybe (Referenced Schema))+schemaObjIf = lens _schemaIf (\s a -> s {_schemaIf = a})++schemaObjThen :: Lens' SchemaObj (Maybe (Referenced Schema))+schemaObjThen = lens _schemaThen (\s a -> s {_schemaThen = a})++schemaObjElse :: Lens' SchemaObj (Maybe (Referenced Schema))+schemaObjElse = lens _schemaElse (\s a -> s {_schemaElse = a})++schemaObjReadOnly :: Lens' SchemaObj (Maybe Bool)+schemaObjReadOnly = lens _schemaReadOnly (\s a -> s {_schemaReadOnly = a})++schemaObjWriteOnly :: Lens' SchemaObj (Maybe Bool)+schemaObjWriteOnly = lens _schemaWriteOnly (\s a -> s {_schemaWriteOnly = a})++schemaObjProperties :: Lens' SchemaObj (Maybe (InsOrdHashMap Text (Referenced Schema)))+schemaObjProperties = lens _schemaProperties (\s a -> s {_schemaProperties = a})++schemaObjPatternProperties :: Lens' SchemaObj (Maybe (InsOrdHashMap Text (Referenced Schema)))+schemaObjPatternProperties = lens _schemaPatternProperties (\s a -> s {_schemaPatternProperties = a})++schemaObjAdditionalProperties :: Lens' SchemaObj (Maybe AdditionalProperties)+schemaObjAdditionalProperties = lens _schemaAdditionalProperties (\s a -> s {_schemaAdditionalProperties = a})++schemaObjAdditionalItems :: Lens' SchemaObj (Maybe AdditionalProperties)+schemaObjAdditionalItems = lens _schemaAdditionalItems (\s a -> s {_schemaAdditionalItems = a})++schemaObjItems :: Lens' SchemaObj (Maybe ItemsSchema)+schemaObjItems = lens _schemaItems (\s a -> s {_schemaItems = a})++schemaObjPropertyNames :: Lens' SchemaObj (Maybe (Referenced Schema))+schemaObjPropertyNames = lens _schemaPropertyNames (\s a -> s {_schemaPropertyNames = a})++schemaObjContains :: Lens' SchemaObj (Maybe (Referenced Schema))+schemaObjContains = lens _schemaContains (\s a -> s {_schemaContains = a})++schemaObjAllOf :: Lens' SchemaObj (Maybe [Referenced Schema])+schemaObjAllOf = lens _schemaAllOf (\s a -> s {_schemaAllOf = a})++schemaObjOneOf :: Lens' SchemaObj (Maybe [Referenced Schema])+schemaObjOneOf = lens _schemaOneOf (\s a -> s {_schemaOneOf = a})++schemaObjAnyOf :: Lens' SchemaObj (Maybe [Referenced Schema])+schemaObjAnyOf = lens _schemaAnyOf (\s a -> s {_schemaAnyOf = a})++schemaObjNot :: Lens' SchemaObj (Maybe (Referenced Schema))+schemaObjNot = lens _schemaNot (\s a -> s {_schemaNot = a})++schemaObjDescription :: Lens' SchemaObj (Maybe Description)+schemaObjDescription = lens _schemaDescription (\s a -> s {_schemaDescription = a})++schemaObjFormat :: Lens' SchemaObj (Maybe Text)+schemaObjFormat = lens _schemaFormat (\s a -> s {_schemaFormat = a})++schemaObjDefault :: Lens' SchemaObj (Maybe Value)+schemaObjDefault = lens _schemaDefault (\s a -> s {_schemaDefault = a})++schemaObjDiscriminator :: Lens' SchemaObj (Maybe Text)+schemaObjDiscriminator = lens _schemaDiscriminator (\s a -> s {_schemaDiscriminator = a})++schemaObjExternalDocs :: Lens' SchemaObj (Maybe (Referenced ExternalDocumentation))+schemaObjExternalDocs = lens _schemaExternalDocs (\s a -> s {_schemaExternalDocs = a})++schemaObjDeprecated :: Lens' SchemaObj (Maybe Bool)+schemaObjDeprecated = lens _schemaDeprecated (\s a -> s {_schemaDeprecated = a})++-- Server Variable Object lenses+serverVariableEnum :: Lens' ServerVariable (Maybe [Text])+serverVariableEnum = lens _serverVariableEnum (\s a -> s {_serverVariableEnum = a})++serverVariableDefault :: Lens' ServerVariable (Maybe Text)+serverVariableDefault = lens _serverVariableDefault (\s a -> s {_serverVariableDefault = a})++serverVariableDescription :: Lens' ServerVariable (Maybe Description)+serverVariableDescription = lens _serverVariableDescription (\s a -> s {_serverVariableDescription = a})++serverVariableExamples :: Lens' ServerVariable (Maybe [Text])+serverVariableExamples = lens _serverVariableExamples (\s a -> s {_serverVariableExamples = a})++-- Parameter Object lenses+parameterEnum :: Lens' Parameter (Maybe [Text])+parameterEnum = lens _parameterEnum (\s a -> s {_parameterEnum = a})++parameterDefault :: Lens' Parameter (Maybe Text)+parameterDefault = lens _parameterDefault (\s a -> s {_parameterDefault = a})++parameterDescription :: Lens' Parameter (Maybe Description)+parameterDescription = lens _parameterDescription (\s a -> s {_parameterDescription = a})++parameterExamples :: Lens' Parameter (Maybe [Text])+parameterExamples = lens _parameterExamples (\s a -> s {_parameterExamples = a})++parameterLocation :: Lens' Parameter (Maybe RuntimeExpression)+parameterLocation = lens _parameterLocation (\s a -> s {_parameterLocation = a})++-- Security Scheme lenses+securitySchemeType :: Lens' SecurityScheme (SecuritySchemeType)+securitySchemeType = lens _securitySchemeType (\s a -> s {_securitySchemeType = a})++securitySchemeDescription :: Lens' SecurityScheme (Maybe Description)+securitySchemeDescription = lens _securitySchemeDescription (\s a -> s {_securitySchemeDescription = a})++securitySchemeName :: Lens' SecurityScheme (Maybe Name)+securitySchemeName = lens _securitySchemeName (\s a -> s {_securitySchemeName = a})++securitySchemeIn :: Lens' SecurityScheme (Maybe ApiKeyLocation)+securitySchemeIn = lens _securitySchemeIn (\s a -> s {_securitySchemeIn = a})++securitySchemeScheme :: Lens' SecurityScheme (Maybe Text)+securitySchemeScheme = lens _securitySchemeScheme (\s a -> s {_securitySchemeScheme = a})++securitySchemeBearerFormat :: Lens' SecurityScheme (Maybe Text)+securitySchemeBearerFormat = lens _securitySchemeBearerFormat (\s a -> s {_securitySchemeBearerFormat = a})++securitySchemeFlows :: Lens' SecurityScheme (Maybe OAuthFlows)+securitySchemeFlows = lens _securitySchemeFlows (\s a -> s {_securitySchemeFlows = a})++securitySchemeOpenIdConnectUrl :: Lens' SecurityScheme (Maybe Url)+securitySchemeOpenIdConnectUrl = lens _securitySchemeOpenIdConnectUrl (\s a -> s {_securitySchemeOpenIdConnectUrl = a})++securitySchemeScopes :: Lens' SecurityScheme (Maybe [Text])+securitySchemeScopes = lens _securitySchemeScopes (\s a -> s {_securitySchemeScopes = a})
+ src/Data/AsyncAPI/Optics.hs view
@@ -0,0 +1,81 @@+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE TemplateHaskell #-}+{-# LANGUAGE UndecidableInstances #-}+{-# OPTIONS_GHC -Wno-orphans #-}++-- | Field optics and prisms for the AsyncAPI 3.1.0 model, built with+-- @optics-th@. Field labels are named after the JSON keys (usable as+-- @#title@ with @OverloadedLabels@); prisms carry the constructor names.+--+-- Fields whose JSON keys are Haskell keywords get underscore-suffixed labels+-- (@type_@, @if_@, @then_@, @else_@, @default_@); for 'SecurityScheme' the+-- keyword label is the bare @in@ (generated by 'makeFieldLabels'). The three+-- keyword-heavy records enumerate their labels explicitly via+-- 'makeFieldLabelsFor'; all other records use 'makeFieldLabels'. The+-- generated 'Optics.Label.LabelOptic' instances are intentionally orphan+-- (label optics must be declared where they are used).+module Data.AsyncAPI.Optics+  ( module Data.AsyncAPI.Optics,+    module Data.AsyncAPI.Internal,+    module Data.AsyncAPI.Internal.Schema,+  )+where++import Data.AsyncAPI.Internal+import Data.AsyncAPI.Internal.FieldNames (parameterFields, schemaObjFields, serverVariableFields)+import Data.AsyncAPI.Internal.Schema+import Optics.TH (makeFieldLabels, makeFieldLabelsFor, makePrisms)++-- Root+makeFieldLabels ''AsyncAPI+makeFieldLabels ''Info+makeFieldLabels ''Contact+makeFieldLabels ''License+makeFieldLabels ''Server+makeFieldLabels ''Channel+makeFieldLabels ''Tag+makeFieldLabels ''ExternalDocumentation+makeFieldLabels ''Reference+makeFieldLabels ''Components++-- Security+makeFieldLabels ''SecurityScheme+makeFieldLabels ''OAuthFlows+makeFieldLabels ''OAuthFlow++-- Bindings+makeFieldLabels ''ServerBindings+makeFieldLabels ''ChannelBindings+makeFieldLabels ''OperationBindings+makeFieldLabels ''MessageBindings++-- Schemas+makeFieldLabels ''MultiFormatSchema+makeFieldLabelsFor schemaObjFields ''SchemaObj+makeFieldLabelsFor serverVariableFields ''ServerVariable+makeFieldLabelsFor parameterFields ''Parameter++-- Messages+makeFieldLabels ''Message+makeFieldLabels ''MessageTrait+makeFieldLabels ''MessageExample+makeFieldLabels ''CorrelationId++-- Operations+makeFieldLabels ''Operation+makeFieldLabels ''OperationTrait+makeFieldLabels ''OperationReply+makeFieldLabels ''OperationReplyAddress++-- Prisms for sum types+makePrisms ''Referenced+makePrisms ''Schema+makePrisms ''SchemaType+makePrisms ''ItemsSchema+makePrisms ''AdditionalProperties+makePrisms ''SchemaDefinition+makePrisms ''SecuritySchemeType+makePrisms ''ApiKeyLocation+makePrisms ''OperationAction+makePrisms ''JsonType
+ src/Data/AsyncAPI/Validation.hs view
@@ -0,0 +1,131 @@+-- | Structural validation of AsyncAPI 3.1.0 documents.+module Data.AsyncAPI.Validation+  ( ValidationError (..),+    ValidationRule (..),+    validateAsyncAPI,+    supportedSchemaFormats,+    validVersion,+    internalRefs,+    resolvesRef,+    multiFormatSchemas,+  )+where++import Data.Aeson (Value (..), toJSON)+import Data.Aeson.Key qualified as Key+import Data.Aeson.KeyMap qualified as KM+import Data.AsyncAPI.Internal+import Data.Text (Text)+import Data.Text qualified as T+import Data.Vector qualified as V++-- | The rule a 'ValidationError' came from.+data ValidationRule+  = -- | The @asyncapi@ version string.+    VersionRule+  | -- | Internal @$ref@ resolution.+    RefResolutionRule+  | -- | Multi Format Schema @schemaFormat@ support (MUST table only).+    SchemaFormatRule+  deriving (Eq, Show)++-- | A single structural validation failure. The pointer is an RFC 6901 JSON+-- pointer into the document (@\"\"@ = root).+data ValidationError = ValidationError+  { -- | Rule that produced the failure.+    validationRule :: ValidationRule,+    -- | Pointer to the offending location.+    validationPointer :: Text,+    -- | Human-readable description of the failure.+    validationMessage :: Text+  }+  deriving (Eq, Show)++-- | Schema formats every implementation MUST support+-- ([Schema formats table](https://www.asyncapi.com/docs/reference/specification/v3.1.0#multiFormatSchemaFormatTable)).+supportedSchemaFormats :: [Text]+supportedSchemaFormats =+  [ "application/vnd.aai.asyncapi;version=3.1.0",+    "application/vnd.aai.asyncapi+json;version=3.1.0",+    "application/vnd.aai.asyncapi+yaml;version=3.1.0",+    "application/schema+json;version=draft-07",+    "application/schema+yaml;version=draft-07"+  ]++-- | Structural rules: version string, internal reference resolution, and+-- Multi Format Schema 'supportedSchemaFormats'. Result order is unspecified.+validateAsyncAPI :: AsyncAPI -> [ValidationError]+validateAsyncAPI doc = versionErrors <> refErrors <> schemaFormatErrors+  where+    json = toJSON doc+    versionErrors =+      [ ValidationError VersionRule "" ("unsupported asyncapi version: " <> v)+      | let v = getVersion (_asyncAPIAsyncAPI doc),+        not (validVersion v)+      ]+    refErrors =+      [ ValidationError RefResolutionRule p ("unresolved internal reference: " <> r)+      | (p, r) <- internalRefs json,+        not (resolvesRef r json)+      ]+    schemaFormatErrors =+      [ ValidationError SchemaFormatRule p ("unsupported schemaFormat: " <> f)+      | (p, f) <- multiFormatSchemas json,+        f `notElem` supportedSchemaFormats+      ]++-- | The @asyncapi@ version string must be @3.<digits>.<digits>(-suffix)?@.+validVersion :: Text -> Bool+validVersion v = case T.splitOn "." v of+  ["3", mi, pa] ->+    digits mi+      && let (pre, post) = T.breakOn "-" pa+          in digits pre && (T.null post || (T.length post > 1))+  _ -> False+  where+    digits t = not (T.null t) && T.all (\c -> c >= '0' && c <= '9') t++-- | All internal @$ref@ values (@#/@-prefixed) with their RFC 6901 pointers.+internalRefs :: Value -> [(Text, Text)]+internalRefs = go ""+  where+    go p (Object o) =+      concatMap+        ( \(k, v) ->+            case (Key.toText k, v) of+              ("$ref", String r)+                | "#/" `T.isPrefixOf` r -> [(p, r)]+              _ -> go (child p k) v+        )+        (KM.toList o)+    go p (Array a) =+      concat+        [go (p <> "/" <> T.pack (show i)) v | (i, v) <- zip [0 :: Int ..] (V.toList a)]+    go _ _ = []+    child p k = p <> "/" <> escapeToken (Key.toText k)++-- | Whether an internal reference (@#\/a\/b@) resolves in the document.+resolvesRef :: Text -> Value -> Bool+resolvesRef r doc = case T.stripPrefix "#/" r of+  Nothing -> False+  Just rest -> go (T.splitOn "/" rest) doc+  where+    go [] _ = True+    go (t : ts) v = case v of+      Object o -> case KM.lookup (Key.fromText (unescapeToken t)) o of+        Just v' -> go ts v'+        Nothing -> False+      _ -> False++-- | All @schemaFormat@ values of embedded Multi Format Schema Objects+-- (objects carrying both @schemaFormat@ and @schema@ keys), with pointers.+multiFormatSchemas :: Value -> [(Text, Text)]+multiFormatSchemas = go ""+  where+    go p (Object o)+      | Just (String f) <- KM.lookup "schemaFormat" o,+        KM.member "schema" o =+          (p, f) : concatMap (go p . snd) (KM.toList o)+      | otherwise = concatMap (go p . snd) (KM.toList o)+    go p (Array a) = concatMap (go p) (V.toList a)+    go _ _ = []
+ test/AsyncAPISpec.hs view
@@ -0,0 +1,102 @@+-- | Golden tests for the examples embedded in the specification. Each+-- tester-annotated block is decoded into the model type named by its+-- @json_pointer@ (see 'pointerType'), encoded with the library's ordered+-- encoder, and byte-compared against a golden file; the encoding is then+-- redecoded and checked for structural equality.+module AsyncAPISpec (spec) where++import Control.Monad (forM_)+import Data.Aeson (Value (..), decode, eitherDecode, encode)+import Data.Aeson.KeyMap qualified as KM+import Data.Aeson.Types (parseEither)+import Data.ByteString (ByteString)+import Data.ByteString.Lazy qualified as BL+import Data.Text (Text)+import Data.Text qualified as T+import Data.Text.Encoding qualified as TE+import Data.Yaml qualified (decodeEither')+import System.FilePath ((<.>), (</>))+import Test.Hspec+import Test.Hspec.Golden (Golden)+import TestSupport++spec :: Spec+spec = describe "spec examples" $ do+  base <- runIO loadBaseDoc+  examples <- runIO (annotatedExamples <$> loadSpecMarkdown)+  mapM_ (exampleCase base) (zip [1 :: Int ..] examples)+  identifierExamples++exampleCase :: Value -> (Int, ExampleBlock) -> Spec+exampleCase base (idx, ex) = it label action+  where+    action :: IO (Golden ByteString)+    action = do+      fragment <- parseFragment ex+      let expectedValue =+            case blockPointer ex of+              Just "" -> mergePatch base fragment+              _ -> fragment+      case pointerType (maybe "" id (blockPointer ex)) of+        Nothing -> pendWith ("pointerType row pending for " <> show (blockPointer ex))+        Just (Target tname tparser) ->+          case parseEither tparser expectedValue of+            Left e ->+              failWith ("decoding as " <> tname <> " failed: " <> e)+            Right v -> do+              let out = BL.toStrict (encode v)+              case decode (BL.fromStrict out) of+                Just v' | v' == v -> pure (byteGolden ("spec-examples" </> goldenName idx ex) out)+                _ -> failWith "decode (encode v) /= v"+    label =+      T.unpack (maybe "" id (blockName ex))+        <> " ["+        <> T.unpack (blockFormat ex)+        <> "] at "+        <> T.unpack (maybe "" id (blockPointer ex))++-- | The four unannotated Identifier Object examples (spec lines 234, 240,+-- 244, 250): literal @id@ URI values, checked as plain JSON.+identifierExamples :: Spec+identifierExamples = do+  md <- runIO loadSpecMarkdown+  let ids =+        [ b+        | b <- allFencedBlocks md,+          blockLine b `elem` [234, 240, 244, 250]+        ]+  describe "identifier examples" $ do+    it "finds the four Identifier Object blocks" $ length ids `shouldBe` 4+    forM_ ids $ \b ->+      it ("line " <> show (blockLine b) <> " parses as an id object") $ do+        v <- parseFragment b+        case v of+          Object o | Just (String _) <- KM.lookup "id" o -> pure ()+          _ -> expectationFailure ("not an id object: " <> show v)++-- | Decode the block body (yaml or json) into an aeson value.+parseFragment :: ExampleBlock -> IO Value+parseFragment ex = do+  let bs = TE.encodeUtf8 (blockBody ex)+  case blockFormat ex of+    "json" -> either (fail . ("json parse: " <>)) pure (eitherDecode (BL.fromStrict bs))+    "yaml" -> either (fail . show) pure (Data.Yaml.decodeEither' bs)+    f -> fail ("unsupported format " <> show f)++-- | Golden file path for an example: @test/golden/spec-examples/<idx>-<name>-<format>.json@.+goldenName :: Int -> ExampleBlock -> String+goldenName idx ex =+  show idx+    <> "-"+    <> slug (maybe "unnamed" id (blockName ex))+    <> "-"+    <> T.unpack (blockFormat ex)+      <.> "json"++slug :: Text -> String+slug = map slugChar . T.unpack . T.toLower+  where+    slugChar ' ' = '-'+    slugChar c+      | c `elem` ("/.:()[]|, '\t" :: String) = '-'+      | otherwise = c
+ test/ExamplesSpec.hs view
@@ -0,0 +1,52 @@+-- | Golden + validation tests over the real-world example documents vendored+-- from the spec repository (reference/examples/).+module ExamplesSpec (spec) where++import Control.Monad (forM, forM_)+import Data.Aeson (Value, decode, eitherDecode, encode, toJSON)+import Data.AsyncAPI (ValidationError (..), ValidationRule (..), validateAsyncAPI)+import Data.ByteString qualified as BS+import Data.ByteString.Lazy qualified as BL+import System.FilePath ((<.>), (</>))+import Test.Hspec+import Test.Hspec.Golden (Golden)+import TestSupport++spec :: Spec+spec = describe "real-world examples" $ do+  files <- runIO exampleFiles+  cases <-+    runIO+      ( forM files $ \f -> do+          v <- parseYamlFile f+          pure (f, v)+      )+  forM_ cases exampleCase++exampleCase :: (FilePath, Value) -> Spec+exampleCase (file, value) = it file $ do+  case eitherDecode (encode (toJSON value)) of+    Left e -> failWith ("decode as AsyncAPI failed: " <> e)+    Right doc ->+      case decode (encode doc) of+        Just doc'+          | doc' == doc ->+              case filter mustLevel (validateAsyncAPI doc) of+                [] -> pure (goldenFor file (BL.toStrict (encode doc)))+                errs ->+                  failWith+                    ( "validation errors: "+                        <> show [(validationPointer e, validationMessage e) | e <- errs]+                    )+        _ -> failWith "decode (encode v) /= v"+  where+    -- RECOMMENDED (non-MUST) schema formats (e.g. Avro) are valid documents;+    -- the validator only enforces the spec's MUST table, so skip its+    -- schemaFormat complaints here.+    mustLevel e = validationRule e /= SchemaFormatRule++goldenFor :: FilePath -> BS.ByteString -> Golden BS.ByteString+goldenFor file = byteGolden ("examples" </> map slash file <.> "json")+  where+    slash '/' = '-'+    slash c = c
+ test/Spec.hs view
@@ -0,0 +1,1 @@+{-# OPTIONS_GHC -F -pgmF hspec-discover #-}
+ test/SpecConformanceSpec.hs view
@@ -0,0 +1,141 @@+-- | Repository-level conformance enforcement:+--+--  1. *Doc anchors* — every Haddock spec link in @src/**@ must reference an+--     anchor that actually exists in the vendored spec.+--  2. *Example coverage* — every yaml/json fenced block in the spec must be+--     either tester-annotated (covered by golden tests), in the manual list+--     below, or on the skip list with a reason. The skip list may only+--     contain blocks that are genuinely non-modelable (prose illustrations).+module SpecConformanceSpec (spec) where++import Data.ByteString qualified as BS+import Data.Char (isSpace)+import Data.List (isPrefixOf, isSuffixOf)+import Data.Set qualified as Set+import Data.Text (Text)+import Data.Text qualified as T+import Data.Text.Encoding qualified as TE+import System.Directory (doesDirectoryExist, listDirectory)+import System.FilePath ((</>))+import Test.Hspec+import TestSupport++spec :: Spec+spec = do+  describe "doc anchors" docAnchorSpec+  describe "example coverage" exampleCoverageSpec++-- | Collect all Haskell sources under @src/@ (project-relative paths).+haskellSources :: IO [FilePath]+haskellSources = do+  root <- projectRoot+  let go d = do+        entries <- listDirectory (root </> d)+        concat+          <$> mapM+            ( \e -> do+                let rel = d </> e+                isDir <- doesDirectoryExist (root </> rel)+                if isDir+                  then go rel+                  else pure [rel | ".hs" `isSuffixOf` e]+            )+            entries+  go "src"+  where++-- | All anchors defined in the vendored spec (@<a name="...">@).+specAnchors :: IO (Set.Set Text)+specAnchors = do+  md <- loadSpecMarkdown+  pure . Set.fromList $ concatMap anchorsInLine (T.lines md)+  where+    anchorsInLine l =+      case T.breakOn ("<a name=\"" :: Text) l of+        (_, rest)+          | T.null rest -> []+          | otherwise ->+              let afterAnchor = T.drop (T.length ("<a name=\"" :: Text)) rest+               in [T.takeWhile (/= '"') afterAnchor]++-- | All anchors referenced from Haskell sources via+-- @docs\/reference\/specification\/v3.1.0#<anchor>@.+referencedAnchors :: IO (Set.Set Text)+referencedAnchors = do+  root <- projectRoot+  sources <- haskellSources+  contents <- mapM (fmap (T.unpack . TE.decodeUtf8) . bsRead . (root </>)) sources+  pure . Set.fromList . concatMap refsIn $ contents+  where+    prefix = "docs/reference/specification/v3.1.0#"+    refsIn s = go s+      where+        go [] = []+        go cs+          | prefix `isPrefixOf` cs =+              let rest = drop (length prefix) cs+                  a = takeWhile (`notElem` ("() \t\r\n\"<" :: String)) rest+                  a' = reverse (dropWhile isSpace (reverse a))+               in (if null a' then [] else [T.pack a']) ++ go rest+          | otherwise = go (drop 1 cs)++docAnchorSpec :: Spec+docAnchorSpec =+  it "every referenced spec anchor exists in the vendored spec" $ do+    anchors <- specAnchors+    refs <- referencedAnchors+    let missing = Set.difference refs anchors+    missing `shouldBe` Set.empty++-- | Unannotated yaml/json blocks modeled by targeted tests outside the+-- golden machinery, as @(line, name, pointer)@ rows. The four Identifier+-- Object examples (lines 234, 240, 244, 250) are checked by+-- AsyncAPISpec.identifierExamples.+manualCoverage :: [(Int, Text, Text)]+manualCoverage =+  [ (234, "Identifier Object json urn", "/id"),+    (240, "Identifier Object yaml urn", "/id"),+    (244, "Identifier Object json https", "/id"),+    (250, "Identifier Object yaml https", "/id")+  ]++-- | Unannotated yaml/json blocks that cannot be modeled as data-model+-- golden tests, with reasons. Must shrink to genuinely non-modelable blocks.+skipCoverage :: [(Int, Text)]+skipCoverage =+  [ (21, "prose illustration of a channels object (redacted/commented)"),+    (38, "prose illustration of an operations object (inline-commented narrative)"),+    (50, "prose illustration of channel referencing a message (inline-commented narrative)"),+    (162, "pseudo-syntax fragment of Schema Object fields"),+    (2713, "traits merge mechanism: before-merge prose illustration"),+    (2724, "traits merge mechanism: after-merge prose illustration")+  ]++exampleCoverageSpec :: Spec+exampleCoverageSpec =+  it "partitions all yaml/json fenced blocks into annotated / manual / skip" $ do+    md <- loadSpecMarkdown+    let blocks = allFencedBlocks md+        modelable b = blockFormat b `elem` ["yaml", "json"]+        annotatedLines = map blockLine (annotatedExamples md)+        unannotated =+          [ (blockLine b, b)+          | b <- blocks,+            modelable b,+            blockLine b `notElem` annotatedLines+          ]+        manualLines = map (\(n, _, _) -> n) manualCoverage+        skipLines = map fst skipCoverage+        uncovered =+          [ (n, T.take 60 (T.unwords (T.words (blockBody b))))+          | (n, b) <- unannotated,+            n `notElem` manualLines,+            n `notElem` skipLines+          ]+    -- sanity: every annotation in the file produced exactly one block+    annotationCount <- pure (length (filter (T.isPrefixOf "<!-- asyncapi-example-tester:" . T.strip) (T.lines md)))+    length annotatedLines `shouldBe` annotationCount+    uncovered `shouldBe` []++bsRead :: FilePath -> IO BS.ByteString+bsRead = BS.readFile
+ test/TestSupport.hs view
@@ -0,0 +1,327 @@+-- | Shared test infrastructure: extraction of examples embedded in the+-- vendored specification, RFC 7386 merge-patch, RFC 6901 JSON pointers, and+-- file loaders.+module TestSupport+  ( ExampleBlock (..),+    annotatedExamples,+    allFencedBlocks,+    specMarkdownPath,+    baseDocPath,+    examplesDir,+    exampleFiles,+    projectRoot,+    loadSpecMarkdown,+    loadBaseDoc,+    parseYamlFile,+    mergePatch,+    pointerGet,+    pointerSet,+    unescapeToken,+    escapeToken,+    splitPointer,+    Target (..),+    pointerType,+    TestSupport.failWith,+    pendWith,+    byteGolden,+  )+where++import Data.Aeson (FromJSON, ToJSON, Value (..), parseJSON)+import Data.Aeson qualified as Aeson+import Data.Aeson.Key qualified as Key+import Data.Aeson.KeyMap qualified as KM+import Data.Aeson.Types (Parser)+import Data.AsyncAPI.Internal+import Data.ByteString (ByteString)+import Data.ByteString qualified as BS+import Data.ByteString.Lazy qualified as BL+import Data.List (isSuffixOf, sort)+import Data.Text (Text)+import Data.Text qualified as T+import Data.Text.Encoding (decodeUtf8, encodeUtf8)+import Data.Vector qualified as V+import Data.Yaml qualified (decodeEither')+import System.Directory+  ( doesDirectoryExist,+    doesFileExist,+    getCurrentDirectory,+    listDirectory,+  )+import System.FilePath (splitDirectories, (</>))+import Test.Hspec (expectationFailure, pendingWith)+import Test.Hspec.Golden (Golden (..))++-- | A fenced code block extracted from the spec markdown.+data ExampleBlock = ExampleBlock+  { -- | 1-based line number of the opening fence.+    blockLine :: Int,+    -- | Fence language (@yaml@, @json@, @text@, ...).+    blockFormat :: Text,+    -- | Block body (between the fences).+    blockBody :: Text,+    -- | For annotated blocks: the tester @name@ field.+    blockName :: Maybe Text,+    -- | For annotated blocks: the tester @json_pointer@ field (@""@ = root).+    blockPointer :: Maybe Text+  }+  deriving (Eq, Show)++-- | Path of the vendored spec markdown, relative to the project root.+specMarkdownPath :: FilePath+specMarkdownPath = "reference/asyncapi.md"++-- | Path of the (patched) base document, relative to the project root.+baseDocPath :: FilePath+baseDocPath = "reference/base-doc.json"++-- | Directory of real-world example documents, relative to the project root.+examplesDir :: FilePath+examplesDir = "reference/examples"++-- | The project root: the nearest ancestor of the current directory that+-- contains the vendored spec. @cabal test@ runs with the package root as cwd,+-- so this normally resolves immediately.+projectRoot :: IO FilePath+projectRoot = do+  cwd <- getCurrentDirectory+  go (splitDirectories cwd)+  where+    go [] = fail ("project root not found (missing " <> specMarkdownPath <> ")")+    go dirs = do+      let cand = if null dirs then "/" else foldr (</>) "" dirs+      ok <- doesFileExist (cand </> specMarkdownPath)+      if ok then pure cand else go (init dirs)++-- | Every example document under 'examplesDir' (sorted), as project-relative+-- paths.+exampleFiles :: IO [FilePath]+exampleFiles = do+  root <- projectRoot+  let go d = do+        entries <- listDirectory (root </> d)+        concat+          <$> mapM+            ( \e -> do+                let rel = d </> e+                isDir <- doesDirectoryExist (root </> rel)+                if isDir+                  then go rel+                  else pure [rel | any (`isSuffixOf` e) [".yml", ".yaml"]]+            )+            entries+  sort <$> go examplesDir++-- | Read the vendored spec markdown.+loadSpecMarkdown :: IO Text+loadSpecMarkdown = do+  root <- projectRoot+  decodeUtf8 <$> readBs (root </> specMarkdownPath)++-- | Read and parse the base document used by the spec's own example tester.+loadBaseDoc :: IO Value+loadBaseDoc = do+  root <- projectRoot+  bs <- readBs (root </> baseDocPath)+  either (fail . ("base-doc.json: " <>)) pure (Aeson.eitherDecode (BL.fromStrict bs))++-- | Parse a YAML file into an aeson 'Value' (mappings become key-maps).+parseYamlFile :: FilePath -> IO Value+parseYamlFile path = do+  bs <- readBs path+  either (fail . ((path <> ": ") <>) . show) pure (Data.Yaml.decodeEither' bs)++readBs :: FilePath -> IO ByteString+readBs p = BL.toStrict <$> BL.readFile p++-- | Extract all fenced blocks. A block is tester-annotated iff the line+-- immediately above its opening fence matches+-- @<!-- asyncapi-example-tester:{...} -->@.+allFencedBlocks :: Text -> [ExampleBlock]+allFencedBlocks md = go (zip [1 ..] (T.lines md)) Nothing+  where+    go [] _ = []+    go ((n, l) : rest) pending+      | Just ann <- annotationOf l = go rest (Just ann)+      | Just lang <- openFence l =+          let (bodyLines, rest') = break (isClose . snd) rest+              (name, pointer) = case pending of+                Just ann -> (strField "name" ann, strField "json_pointer" ann)+                Nothing -> (Nothing, Nothing)+           in ExampleBlock+                n+                lang+                (T.intercalate "\n" (map snd bodyLines))+                name+                pointer+                : go (drop 1 rest') Nothing+      | otherwise = go rest Nothing+    openFence l =+      let t = T.strip l+       in if "```" `T.isPrefixOf` t then Just (T.strip (T.drop 3 t)) else Nothing+    isClose l = T.strip l == "```"++-- | Tester-annotated examples only.+annotatedExamples :: Text -> [ExampleBlock]+annotatedExamples = filter (maybe False (const True) . blockPointer) . allFencedBlocks++annotationOf :: Text -> Maybe Value+annotationOf l = do+  t <- T.stripPrefix "<!-- asyncapi-example-tester:" (T.strip l)+  json <- T.stripSuffix "-->" t+  either (const Nothing) Just (Aeson.eitherDecode (BL.fromStrict (encodeUtf8 json)))++strField :: Text -> Value -> Maybe Text+strField k (Object o) = case KM.lookup (Key.fromText k) o of+  Just (String s) -> Just s+  _ -> Nothing+strField _ _ = Nothing++-- $ pointers+--+-- RFC 6901 JSON Pointer helpers. Tokens are escaped with @~1@ for @/@ and+-- @~0@ for @~@.++-- | Split a pointer like @\/info\/contact@ into unescaped tokens.+-- @""@ is the empty pointer (the whole document).+splitPointer :: Text -> [Text]+splitPointer "" = []+splitPointer p = map unescapeToken (drop 1 (T.splitOn "/" p))++-- | RFC 7386 merge-patch: @target@ patched with @patch@.+mergePatch :: Value -> Value -> Value+mergePatch target patch = case (target, patch) of+  (_, Object po) ->+    Object+      ( foldr+          ( \(k, v) acc -> case v of+              Null -> KM.delete (Key.fromText k) acc+              _ ->+                KM.insert+                  (Key.fromText k)+                  (mergePatch (lookupOr k acc Null) v)+                  acc+          )+          (emptyOrObject target)+          (map (fmap' Key.toText) (KM.toList po))+      )+  (_, p) -> p+  where+    fmap' f (a, b) = (f a, b)+    emptyOrObject (Object o) = o+    emptyOrObject _ = KM.empty+    lookupOr k o d = maybe d id (KM.lookup (Key.fromText k) o)++-- | Look up a pointer in a value ('Nothing' when the path does not exist).+pointerGet :: [Text] -> Value -> Maybe Value+pointerGet [] v = Just v+pointerGet (t : ts) v = case v of+  Object o -> KM.lookup (Key.fromText t) o >>= pointerGet ts+  Array a+    | Just i <- readIndex t,+      i < V.length a ->+        pointerGet ts (a V.! i)+  _ -> Nothing++-- | Set (or remove with 'Nothing') the value at a pointer, creating missing+-- intermediate containers. Numeric segments create\/extend JSON arrays+-- (padded with 'Null'), matching the spec tester's @_.set@ behavior; a+-- non-container at an intermediate position is replaced, like lodash.+pointerSet :: [Text] -> Maybe Value -> Value -> Value+pointerSet [] mv _ = maybe Null id mv+pointerSet (t : ts) mv v+  | Just i <- readIndex t =+      case v of+        Array a+          | i < V.length a -> Array (a V.// [(i, sub)])+          | otherwise -> Array (a V.++ V.replicate (i - V.length a) Null V.++ V.singleton sub)+        _ -> Array (V.replicate i Null V.++ V.singleton sub)+  | otherwise = case v of+      Object o -> Object (KM.insert (Key.fromText t) sub o)+      _ -> Object (KM.singleton (Key.fromText t) sub)+  where+    sub = case existing of+      Just existing' -> pointerSet ts mv existing'+      Nothing -> pointerSet ts mv Null+    existing = case v of+      Object o -> KM.lookup (Key.fromText t) o+      Array a+        | Just i <- readIndex t,+          i < V.length a ->+            Just (a V.! i)+      _ -> Nothing++-- | RFC 6901 array index: digits only, no leading zeros (except "0"),+-- bounded to avoid absurd 'read' results.+readIndex :: Text -> Maybe Int+readIndex t+  | t == "0" = Just 0+  | not (T.null t),+    T.all (\c -> c >= '1' && c <= '9') t,+    T.length t <= 9 =+      Just (read (T.unpack t))+  | otherwise = Nothing++-- | A model type an example fragment can be decoded into, carrying the+-- dictionaries the golden test needs.+data Target+  = forall a.+  (ToJSON a, FromJSON a, Eq a, Show a) =>+  Target+  { -- | Human-readable name of the target type.+    targetName :: String,+    -- | Parser from a JSON 'Value' to the target type.+    targetParser :: Value -> Parser a+  }++-- | Map an example @json_pointer@ to the model type the fragment is decoded+-- into. Every pointer used by an annotated example must have an explicit row;+-- a missing row fails the test, naming the pointer.+pointerType :: Text -> Maybe Target+pointerType ptr = case splitPointer ptr of+  [] -> Just (Target "AsyncAPI" (parseJSON :: Value -> Parser AsyncAPI))+  ["info"] -> Just (Target "Info" (parseJSON :: Value -> Parser Info))+  ["info", "contact"] -> Just (Target "Contact" (parseJSON :: Value -> Parser Contact))+  ["info", "license"] -> Just (Target "License" (parseJSON :: Value -> Parser License))+  ["servers"] -> Just (Target "Servers" (parseJSON :: Value -> Parser (SortedObject (Referenced Server))))+  ["servers", _] -> Just (Target "Server" (parseJSON :: Value -> Parser Server))+  ["channels"] -> Just (Target "Channels" (parseJSON :: Value -> Parser (SortedObject (Referenced Channel))))+  ["channels", _] -> Just (Target "Channel" (parseJSON :: Value -> Parser Channel))+  ["components", "tags", _] -> Just (Target "Tag" (parseJSON :: Value -> Parser Tag))+  ["components", "externalDocs", _] -> Just (Target "ExternalDocumentation" (parseJSON :: Value -> Parser ExternalDocumentation))+  ["components", "securitySchemes", _, "flows", _] -> Just (Target "OAuthFlow" (parseJSON :: Value -> Parser OAuthFlow))+  ["components", "securitySchemes", _] -> Just (Target "SecurityScheme" (parseJSON :: Value -> Parser SecurityScheme))+  ["channels", _, "messages"] -> Just (Target "Messages" (parseJSON :: Value -> Parser (SortedObject (Referenced Message))))+  ["operations"] -> Just (Target "Operations" (parseJSON :: Value -> Parser (SortedObject (Referenced Operation))))+  ["operations", _] -> Just (Target "Operation" (parseJSON :: Value -> Parser Operation))+  ["operations", _, "reply", "address"] -> Just (Target "OperationReplyAddress" (parseJSON :: Value -> Parser OperationReplyAddress))+  ["operations", _, "traits", _] -> Just (Target "OperationTrait" (parseJSON :: Value -> Parser OperationTrait))+  ["components", "schemas", _] -> Just (Target "SchemaDefinition" (parseJSON :: Value -> Parser SchemaDefinition))+  ["components", "messages", _, "examples", _] -> Just (Target "MessageExample" (parseJSON :: Value -> Parser MessageExample))+  ["components", "messages", _, "payload"] -> Just (Target "SchemaDefinition" (parseJSON :: Value -> Parser SchemaDefinition))+  ["components", "messages", _] -> Just (Target "Message" (parseJSON :: Value -> Parser Message))+  ["components", "messageTraits", _] -> Just (Target "MessageTrait" (parseJSON :: Value -> Parser MessageTrait))+  ["components", "correlationIds", _] -> Just (Target "CorrelationId" (parseJSON :: Value -> Parser CorrelationId))+  _ -> Nothing++-- | Fail the enclosing golden example ('expectationFailure' throws, so the+-- unreachable continuation is never evaluated).+failWith :: String -> IO (Golden BS.ByteString)+failWith msg = expectationFailure msg >> pure (error "expectationFailure should have thrown")++-- | Mark the golden example pending ('pendingWith' throws; see 'failWith').+pendWith :: String -> IO (Golden BS.ByteString)+pendWith msg = pendingWith msg >> pure (error "pendingWith should have thrown")++-- | Byte-exact golden comparison against @test/golden/<path>@.+byteGolden :: FilePath -> BS.ByteString -> Golden BS.ByteString+byteGolden path out =+  Golden+    { output = out,+      encodePretty = T.unpack . decodeUtf8,+      writeToFile = BS.writeFile,+      readFromFile = BS.readFile,+      goldenFile = "test/golden" </> path,+      actualFile = Nothing,+      failFirstTime = False+    }
+ test/ValidationSpec.hs view
@@ -0,0 +1,62 @@+-- | Red-case-per-rule tests for the structural validator, plus a+-- clean-document case. Documents are built with lens field optics.+module ValidationSpec (spec) where++import Control.Lens ((&), (.~))+import Data.Aeson (object, (.=))+import Data.AsyncAPI+import Data.AsyncAPI.Lens+import Data.HashMap.Strict.InsOrd qualified as InsOrd+import Test.Hspec++spec :: Spec+spec = describe "validateAsyncAPI" $ do+  it "accepts a clean document" $+    validateAsyncAPI cleanDoc `shouldBe` []++  it "rejects a bad asyncapi version string" $+    validateAsyncAPI (cleanDoc & asyncAPI .~ "2.6.0")+      `shouldContain` [ValidationError VersionRule "" "unsupported asyncapi version: 2.6.0"]++  it "rejects a dangling internal reference" $ do+    let doc =+          cleanDoc+            & components .~ Just (emptyComponents {_componentsMessages = Just (InsOrd.singleton "none" (Ref (Reference "#/components/messages/missing")))})+    validateAsyncAPI doc+      `shouldContain` [ValidationError RefResolutionRule "/components/messages/none" "unresolved internal reference: #/components/messages/missing"]++  it "rejects an unsupported schemaFormat" $ do+    let mfs =+          MultiFormatSchema+            { _multiFormatSchemaSchemaFormat = "application/vnd.apache.avro+json;version=1.9.0",+              _multiFormatSchemaSchema = object ["x" .= (1 :: Int)],+              _multiFormatSchemaExtensions = InsOrd.empty+            }+        doc =+          cleanDoc+            & components .~ Just (emptyComponents {_componentsMessages = Just (InsOrd.singleton "avro" (Inline (messageWithPayload mfs)))})+    validateAsyncAPI doc+      `shouldContain` [ValidationError SchemaFormatRule "" "unsupported schemaFormat: application/vnd.apache.avro+json;version=1.9.0"]++cleanDoc :: AsyncAPI+cleanDoc =+  emptyAsyncAPI "3.1.0" (Info "Test" "1.0.0" Nothing Nothing Nothing Nothing Nothing Nothing InsOrd.empty)++messageWithPayload :: MultiFormatSchema -> Message+messageWithPayload mfs =+  Message+    { _messageHeaders = Nothing,+      _messagePayload = Just (SchemaDefMultiFormat mfs),+      _messageCorrelationId = Nothing,+      _messageContentType = Nothing,+      _messageName = Nothing,+      _messageTitle = Nothing,+      _messageSummary = Nothing,+      _messageDescription = Nothing,+      _messageTags = Nothing,+      _messageExternalDocs = Nothing,+      _messageBindings = Nothing,+      _messageExamples = Nothing,+      _messageTraits = Nothing,+      _messageExtensions = InsOrd.empty+    }
+ test/golden/examples/reference-examples-adeo-kafka-request-reply-asyncapi.yml.json view
@@ -0,0 +1,1 @@+{"asyncapi":"3.1.0","info":{"title":"Adeo AsyncAPI Case Study","version":"%REPLACED_BY_MAVEN%","description":"This Adeo specification illustrates how ADEO uses AsyncAPI to document some of their exchanges.\n","contact":{"name":"AsyncAPI Community","email":"case-study@asyncapi.com"},"tags":[{"name":"costing","description":"Costing channels, used by Costing clients."}]},"servers":{"dev":{"host":"dev.url:9092","protocol":"kafka","description":"Kafka DEV cluster for `dev` and `sit` environments","security":[{"$ref":"#/components/securitySchemes/sasl-ssl"}],"bindings":{"kafka":{"schemaRegistryUrl":"https://schema-registry.prod.url/"}}},"production":{"host":"prod.url:9092","protocol":"kafka","description":"Kafka PRODUCTION cluster","security":[{"$ref":"#/components/securitySchemes/sasl-ssl"}],"bindings":{"kafka":{"schemaRegistryUrl":"https://schema-registry.prod.url/"}}},"staging":{"host":"staging.url:9092","protocol":"kafka","description":"Kafka STAGING cluster for `uat` and `preprod` environments","security":[{"$ref":"#/components/securitySchemes/sasl-ssl"}],"bindings":{"kafka":{"schemaRegistryUrl":"https://schema-registry.prod.url/"}}}},"channels":{"costingRequestChannel":{"address":"adeo-{env}-case-study-COSTING-REQUEST-{version}","messages":{"CostingRequest":{"$ref":"#/components/messages/costingRequestV1"}},"description":"Use this topic to do a Costing Request to Costing product. We use the [**RecordNameStrategy**](https://docs.confluent.io/platform/current/schema-registry/serdes-develop/index.html#subject-name-strategy) to infer the messages schema. You have to define `value.subject.name.strategy` to `io.confluent.kafka.serializers.subject.RecordNameStrategy` in your producer to use the schema we manage. The schema below illustrates how Costing Request messages are handled. ![](https://user-images.githubusercontent.com/5501911/188920831-689cec5f-8dc3-460b-8794-0b54ec8b0ac8.png)\n","parameters":{"env":{"$ref":"#/components/parameters/Env"},"version":{"$ref":"#/components/parameters/Version"}},"bindings":{"kafka":{"partitions":3,"replicas":3,"topicConfiguration":{"cleanup.policy":["delete"],"retention.ms":60000000}}}},"costingResponseChannel":{"messages":{"costingResponse":{"$ref":"#/components/messages/costingResponse"}},"description":"This topic is used to REPLY Costing Requests and is targeted by the `REPLY_TOPIC` header. **You must grant PUBLISH access to our `svc-ccr-app` service account.**. We use the [**RecordNameStrategy**](https://docs.confluent.io/platform/current/schema-registry/serdes-develop/index.html#subject-name-strategy) to infer the messages schema. \nTopic should follow pattern \"adeo-{env}-case-study-COSTING-RESPONSE-{version}\"\nYou have to define `key.subject.name.strategy` and `value.subject.name.strategy` to `io.confluent.kafka.serializers.subject.RecordNameStrategy` in your consumer. The schema below illustrates how Costing Response messages are handled.\n     ![](https://user-images.githubusercontent.com/5501911/188920831-689cec5f-8dc3-460b-8794-0b54ec8b0ac8.png)\n","tags":[{"name":"costing"}],"bindings":{"kafka":{"x-key.subject.name.strategy":{"description":"We use the RecordNameStrategy to infer the messages schema. Use `key.subject.name.strategy=io.confluent.kafka.serializers.subject.RecordNameStrategy` in your consumer configuration.\n","type":"string"},"x-value.subject.name.strategy":{"description":"We use the RecordNameStrategy to infer the messages schema. Use `value.subject.name.strategy=io.confluent.kafka.serializers.subject.RecordNameStrategy` in your consumer configuration.\n","type":"string"}}}}},"operations":{"receiveACostingRequest":{"action":"receive","channel":{"$ref":"#/channels/costingRequestChannel"},"summary":"[COSTING] Request one or more Costing calculation for any product\n","description":"You can try a costing request using our [Conduktor producer template](https://conduktor.url/)\n","tags":[{"name":"costing"}],"bindings":{"kafka":{"groupId":{"description":"The groupId must be prefixed by your `svc` account, deliver by the Adeo Kafka team. This `svc` must have the write access to the topic.\n","type":"string"},"x-value.subject.name.strategy":{"description":"We use the RecordNameStrategy to infer the messages schema. Use `value.subject.name.strategy=io.confluent.kafka.serializers.subject.RecordNameStrategy` in your producer configuration.\n","type":"string"}}},"reply":{"address":{"location":"$message.header#/REPLY_TOPIC"},"channel":{"$ref":"#/channels/costingResponseChannel"}}}},"components":{"schemas":{"BuCode":{"type":"string","examples":[1],"description":"The Business Unit code for which data are applicable."},"CorrelationId":{"type":"string","examples":["1fa6ef40-8f47-40a8-8cf6-f8607d0066ef"],"description":"A unique Correlation ID defined from the `REQUEST_ID` or the `MESSAGE_ID` provided in the Costing Request.","format":"uuid"},"ErrorCode":{"type":"string","examples":["CURRENCY_NOT_FOUND"],"description":"The error code.\n"},"ErrorMessage":{"type":"string","examples":["Error message"],"description":"The error message describing the error.\n"},"ErrorStep":{"type":"string","examples":["EXPOSE_RESULT"],"description":"The woker that has thrown the error.\n"},"MessageId":{"type":"string","examples":["1fa6ef40-8f47-40a8-8cf6-f8607d0066ef"],"description":"A unique Message ID.","format":"uuid"},"ReplyTopic":{"type":"string","examples":["adeo-case-study-COSTING-RESPONSE-V1"],"description":"The Kafka topic where to send the Costing Response. This is required for the [Return Address EIP pattern](https://www.enterpriseintegrationpatterns.com/patterns/messaging/ReturnAddress.html). **You must grant WRITE access to our `svc-ccr-app` service account.**\n"},"RequestId":{"type":"string","examples":["1fa6ef40-8f47-40a8-8cf6-f8607d0066ef"],"description":"A unique Request ID needed to define a `CORRELATION_ID` for exchanges, which will be sent back in the Costing Responses.","format":"uuid"},"RequesterCode":{"type":"string","examples":[1],"description":"The Costing requester code (generally the BU Code). The requester code is useful to get the dedicated context (tenant)."},"RequesterId":{"type":"string","examples":["svc-ecollect-app"],"description":"The Costing requester service account used to produce costing request."}},"messages":{"costingRequestV1":{"headers":{"type":"object","required":["REQUESTER_ID","REQUESTER_CODE","REQUEST_ID","REPLY_TOPIC"],"properties":{"REPLY_TOPIC":{"$ref":"#/components/schemas/ReplyTopic"},"REQUESTER_CODE":{"$ref":"#/components/schemas/RequesterCode"},"REQUESTER_ID":{"$ref":"#/components/schemas/RequesterId"},"REQUEST_ID":{"$ref":"#/components/schemas/RequestId"}}},"payload":{"schemaFormat":"application/vnd.apache.avro;version=1.9.0","schema":{"$ref":"https://www.asyncapi.com/resources/casestudies/adeo/CostingRequestPayload.avsc"}},"correlationId":{"$ref":"#/components/correlationIds/costingCorrelationId"},"name":"CostingRequestV1","title":"Costing Request V1","summary":"Costing Request V1 inputs.","tags":[{"name":"costing"}]},"costingResponse":{"headers":{"type":"object","properties":{"CALCULATION_ID":{"$ref":"#/components/schemas/MessageId"},"CALCULATION_TIMESTAMP":{"type":"string","description":"Technical timestamp for the costing calculation","format":"date-time"},"CORRELATION_ID":{"$ref":"#/components/schemas/CorrelationId"},"REQUEST_TIMESTAMP":{"type":"string","description":"Timestamp of the costing request","format":"date-time"}}},"payload":{"schemaFormat":"application/vnd.apache.avro;version=1.9.0","schema":{"$ref":"https://www.asyncapi.com/resources/casestudies/adeo/CostingResponsePayload.avsc"}},"correlationId":{"$ref":"#/components/correlationIds/costingCorrelationId"},"name":"CostingResponse","title":"Costing Response","summary":"Costing Response ouputs.","description":"Please refer to the `CostingResponseKey.avsc` schema, available on [our github project](https://github.url/).\n","tags":[{"name":"costing"}]}},"securitySchemes":{"sasl-ssl":{"type":"plain","description":"Use [SASL authentication with SSL encryption](https://docs.confluent.io/platform/current/security/security_tutorial.html#configure-clients) to connect to the ADEO Broker.","x-sasl.jaas.config":"org.apache.kafka.common.security.plain.PlainLoginModule required username=\"<CLUSTER_API_KEY>\" password=\"<CLUSTER_API_SECRET>\";","x-sasl.mechanism":"PLAIN","x-security.protocol":"SASL_SSL","x-ssl.endpoint.identification.algorithm":"https"}},"parameters":{"Env":{"enum":["dev","sit","uat1","preprod","prod"],"description":"Adeo Kafka Environement for messages publications."},"Version":{"default":"V1","description":"the topic version you want to use","examples":["V1"]}},"correlationIds":{"costingCorrelationId":{"description":"This correlation ID is used for message tracing and messages correlation. This correlation ID is generated at runtime based on the `REQUEST_ID` and sent to the RESPONSE message.\n","location":"$message.header#/REQUEST_ID"}}}}
+ test/golden/examples/reference-examples-anyof-asyncapi.yml.json view
@@ -0,0 +1,1 @@+{"asyncapi":"3.1.0","info":{"title":"AnyOf example","version":"1.0.0"},"channels":{"test":{"address":"test","messages":{"testMessages":{"$ref":"#/components/messages/testMessages"}}}},"operations":{"test":{"action":"receive","channel":{"$ref":"#/channels/test"},"messages":[{"$ref":"#/channels/test/messages/testMessages"}]}},"components":{"schemas":{"objectWithKey":{"type":"object","properties":{"key":{"type":"string","additionalProperties":false}}},"objectWithKey2":{"type":"object","properties":{"key2":{"type":"string"}}}},"messages":{"testMessages":{"payload":{"anyOf":[{"$ref":"#/components/schemas/objectWithKey"},{"$ref":"#/components/schemas/objectWithKey2"}]}}}}}
+ test/golden/examples/reference-examples-application-headers-asyncapi.yml.json view
@@ -0,0 +1,1 @@+{"asyncapi":"3.1.0","info":{"title":"Application Headers example","version":"1.0.0","description":"A cut of the Streetlights API to test application header changes supporting","license":{"name":"Apache 2.0","url":"https://www.apache.org/licenses/LICENSE-2.0"}},"servers":{"production":{"host":"test.mosquitto.org:{port}","protocol":"mqtt","description":"Test broker","variables":{"port":{"enum":["1883","8883"],"default":"1883","description":"Secure connection (TLS) is available through port 8883."}}}},"defaultContentType":"application/json","channels":{"lightingMeasured":{"address":"smartylighting/streetlights/1/0/event/{streetlightId}/lighting/measured","messages":{"lightMeasured":{"$ref":"#/components/messages/lightMeasured"}},"parameters":{"streetlightId":{"$ref":"#/components/parameters/streetlightId"}}}},"operations":{"receiveLightMeasurement":{"action":"receive","channel":{"$ref":"#/channels/lightingMeasured"},"summary":"Inform about environmental lighting conditions of a particular streetlight.","messages":[{"$ref":"#/channels/lightingMeasured/messages/lightMeasured"}]}},"components":{"schemas":{"applicationInstanceId":{"type":"string","description":"Unique identifier for a given instance of the publishing application"},"lightMeasuredPayload":{"type":"object","properties":{"lumens":{"type":"integer","minimum":0,"description":"Light intensity measured in lumens."},"sentAt":{"$ref":"#/components/schemas/sentAt"}}},"sentAt":{"type":"string","description":"Date and time when the message was sent.","format":"date-time"}},"messages":{"lightMeasured":{"headers":{"type":"object","properties":{"MQMD":{"type":"object","properties":{"CorrelId":{"type":"string","maxLength":24,"minLength":24,"format":"binary"}}},"applicationInstanceId":{"$ref":"#/components/schemas/applicationInstanceId"}}},"payload":{"$ref":"#/components/schemas/lightMeasuredPayload"},"correlationId":{"location":"$message.header#/MQMD/CorrelId"},"contentType":"application/json","name":"lightMeasured","title":"Light measured","summary":"Inform about environmental lighting conditions of a particular streetlight."}},"parameters":{"streetlightId":{"description":"The ID of the streetlight."}}}}
+ test/golden/examples/reference-examples-correlation-id-asyncapi.yml.json view
@@ -0,0 +1,1 @@+{"asyncapi":"3.1.0","info":{"title":"Correlation ID Example","version":"1.0.0","description":"A cut of the Streetlights API to test Correlation ID","license":{"name":"Apache 2.0","url":"https://www.apache.org/licenses/LICENSE-2.0"}},"servers":{"production":{"host":"test.mosquitto.org:{port}","protocol":"mqtt","description":"Test broker","variables":{"port":{"enum":["1883","8883"],"default":"1883","description":"Secure connection (TLS) is available through port 8883."}},"security":[{"$ref":"#/components/securitySchemes/apiKey"},{"type":"oauth2","description":"Flows to support OAuth 2.0","flows":{"implicit":{"authorizationUrl":"https://authserver.example/auth","availableScopes":{"streetlights:dim":"Ability to dim the lights","streetlights:off":"Ability to switch lights off","streetlights:on":"Ability to switch lights on"}},"password":{"tokenUrl":"https://authserver.example/token","availableScopes":{"streetlights:dim":"Ability to dim the lights","streetlights:off":"Ability to switch lights off","streetlights:on":"Ability to switch lights on"}},"clientCredentials":{"tokenUrl":"https://authserver.example/token","availableScopes":{"streetlights:dim":"Ability to dim the lights","streetlights:off":"Ability to switch lights off","streetlights:on":"Ability to switch lights on"}},"authorizationCode":{"authorizationUrl":"https://authserver.example/auth","tokenUrl":"https://authserver.example/token","refreshUrl":"https://authserver.example/refresh","availableScopes":{"streetlights:dim":"Ability to dim the lights","streetlights:off":"Ability to switch lights off","streetlights:on":"Ability to switch lights on"}}},"scopes":["streetlights:on","streetlights:off","streetlights:dim"]},{"$ref":"#/components/securitySchemes/openIdConnectWellKnown"}]}},"defaultContentType":"application/json","channels":{"lightingMeasured":{"address":"smartylighting/streetlights/1/0/event/{streetlightId}/lighting/measured","messages":{"lightMeasured":{"$ref":"#/components/messages/lightMeasured"}},"parameters":{"streetlightId":{"$ref":"#/components/parameters/streetlightId"}}},"lightsDim":{"address":"smartylighting/streetlights/1/0/action/{streetlightId}/dim","messages":{"dimLight":{"$ref":"#/components/messages/dimLight"}},"parameters":{"streetlightId":{"$ref":"#/components/parameters/streetlightId"}}}},"operations":{"dimLight":{"action":"send","channel":{"$ref":"#/channels/lightsDim"},"messages":[{"$ref":"#/channels/lightsDim/messages/dimLight"}]},"receiveLightMeasurement":{"action":"receive","channel":{"$ref":"#/channels/lightingMeasured"},"summary":"Inform about environmental lighting conditions of a particular streetlight.","messages":[{"$ref":"#/channels/lightingMeasured/messages/lightMeasured"}]}},"components":{"schemas":{"dimLightPayload":{"type":"object","properties":{"percentage":{"type":"integer","maximum":100,"minimum":0,"description":"Percentage to which the light should be dimmed to."},"sentAt":{"$ref":"#/components/schemas/sentAt"}}},"lightMeasuredPayload":{"type":"object","properties":{"lumens":{"type":"integer","minimum":0,"description":"Light intensity measured in lumens."},"sentAt":{"$ref":"#/components/schemas/sentAt"}}},"sentAt":{"type":"string","description":"Date and time when the message was sent.","format":"date-time"}},"messages":{"dimLight":{"payload":{"$ref":"#/components/schemas/dimLightPayload"},"correlationId":{"$ref":"#/components/correlationIds/sentAtCorrelator"},"name":"dimLight","title":"Dim light","summary":"Command a particular streetlight to dim the lights."},"lightMeasured":{"payload":{"$ref":"#/components/schemas/lightMeasuredPayload"},"correlationId":{"location":"$message.header#/MQMD/CorrelId"},"contentType":"application/json","name":"lightMeasured","title":"Light measured","summary":"Inform about environmental lighting conditions of a particular streetlight."}},"securitySchemes":{"apiKey":{"type":"apiKey","description":"Provide your API key as the user and leave the password empty.","in":"user"},"openIdConnectWellKnown":{"type":"openIdConnect","openIdConnectUrl":"https://authserver.example/.well-known"},"supportedOauthFlows":{"type":"oauth2","description":"Flows to support OAuth 2.0","flows":{"implicit":{"authorizationUrl":"https://authserver.example/auth","availableScopes":{"streetlights:dim":"Ability to dim the lights","streetlights:off":"Ability to switch lights off","streetlights:on":"Ability to switch lights on"}},"password":{"tokenUrl":"https://authserver.example/token","availableScopes":{"streetlights:dim":"Ability to dim the lights","streetlights:off":"Ability to switch lights off","streetlights:on":"Ability to switch lights on"}},"clientCredentials":{"tokenUrl":"https://authserver.example/token","availableScopes":{"streetlights:dim":"Ability to dim the lights","streetlights:off":"Ability to switch lights off","streetlights:on":"Ability to switch lights on"}},"authorizationCode":{"authorizationUrl":"https://authserver.example/auth","tokenUrl":"https://authserver.example/token","refreshUrl":"https://authserver.example/refresh","availableScopes":{"streetlights:dim":"Ability to dim the lights","streetlights:off":"Ability to switch lights off","streetlights:on":"Ability to switch lights on"}}}}},"parameters":{"streetlightId":{"description":"The ID of the streetlight."}},"correlationIds":{"sentAtCorrelator":{"description":"Data from message payload used as correlation ID","location":"$message.payload#/sentAt"}}}}
+ test/golden/examples/reference-examples-gitter-streaming-asyncapi.yml.json view
@@ -0,0 +1,1 @@+{"asyncapi":"3.1.0","id":"tag:stream.gitter.im,2022:api","info":{"title":"Gitter Streaming API","version":"1.0.0"},"servers":{"production":{"host":"stream.gitter.im","protocol":"https","protocolVersion":"1.1","pathname":"/v1","security":[{"$ref":"#/components/securitySchemes/httpBearerToken"}]}},"channels":{"rooms":{"address":"/rooms/{roomId}/{resource}","messages":{"chatMessage":{"$ref":"#/components/messages/chatMessage"},"heartbeat":{"$ref":"#/components/messages/heartbeat"}},"parameters":{"resource":{"enum":["chatMessages","events"],"description":"The resource to consume."},"roomId":{"description":"Id of the Gitter room.","examples":["53307860c3599d1de448e19d"]}}}},"operations":{"sendRoomInfo":{"action":"send","channel":{"$ref":"#/channels/rooms"},"bindings":{"http":{"method":"POST"}},"messages":[{"$ref":"#/channels/rooms/messages/chatMessage"},{"$ref":"#/channels/rooms/messages/heartbeat"}]}},"components":{"messages":{"chatMessage":{"payload":{"schemaFormat":"application/schema+yaml;version=draft-07","schema":{"properties":{"fromUser":{"description":"User that sent the message.","properties":{"avatarUrl":{"description":"User avatar URI.","format":"uri","type":"string"},"avatarUrlMedium":{"description":"User avatar URI (medium).","format":"uri","type":"string"},"avatarUrlSmall":{"description":"User avatar URI (small).","format":"uri","type":"string"},"displayName":{"description":"Gitter/GitHub user real name.","type":"string"},"gv":{"description":"Stands for \"Gravatar version\" and is used for cache busting.","type":"string"},"id":{"description":"Gitter User ID.","type":"string"},"url":{"description":"Path to the user on Gitter.","type":"string"},"username":{"description":"Gitter/GitHub username.","type":"string"},"v":{"description":"Version.","type":"number"}},"type":"object"},"gv":{"description":"Stands for \"Gravatar version\" and is used for cache busting.","type":"string"},"html":{"description":"HTML formatted message.","type":"string"},"id":{"description":"ID of the message.","type":"string"},"issues":{"description":"List of #Issues referenced in the message.","items":{"properties":{"number":{"type":"string"}},"type":"object"},"type":"array"},"mentions":{"description":"List of @Mentions in the message.","items":{"properties":{"screenName":{"type":"string"},"userId":{"type":"string"},"userIds":{"items":{"type":"string"},"type":"array"}},"type":"object"},"type":"array"},"meta":{"description":"Metadata. This is currently not used for anything.","items":{},"type":"array"},"readBy":{"description":"Number of users that have read the message.","type":"number"},"sent":{"description":"ISO formatted date of the message.","format":"date-time","type":"string"},"text":{"description":"Original message in plain-text/markdown.","type":"string"},"unread":{"description":"Boolean that indicates if the current user has read the message.","type":"boolean"},"urls":{"description":"List of URLs present in the message.","items":{"format":"uri","type":"string"},"type":"array"},"v":{"description":"Version.","type":"number"}},"type":"object"}},"summary":"A message represents an individual chat message sent to a room. They are a sub-resource of a room.","bindings":{"http":{"headers":{"properties":{"Trailer":{"const":"\\r\\n","type":"string"},"Transfer-Encoding":{"const":"chunked","type":"string"}},"type":"object"}}}},"heartbeat":{"payload":{"schemaFormat":"application/schema+yaml;version=draft-07","schema":{"enum":["\r\n"],"type":"string"}},"summary":"Its purpose is to keep the connection alive.","bindings":{"http":{"headers":{"properties":{"Trailer":{"const":"\\r\\n","type":"string"},"Transfer-Encoding":{"const":"chunked","type":"string"}},"type":"object"}}}}},"securitySchemes":{"httpBearerToken":{"type":"http","scheme":"bearer"}}}}
+ test/golden/examples/reference-examples-kraken-websocket-request-reply-message-filter-in-reply-asyncapi.yml.json view
@@ -0,0 +1,1 @@+{"asyncapi":"3.1.0","info":{"title":"Kraken Websockets API","version":"1.8.0","description":"WebSockets API offers real-time market data updates. WebSockets is a bidirectional protocol offering fastest real-time data, helping you build real-time applications. The public message types presented below do not require authentication. Private-data messages can be subscribed on a separate authenticated endpoint. \n\n### General Considerations\n\n- TLS with SNI (Server Name Indication) is required in order to establish a Kraken WebSockets API connection. See Cloudflare's [What is SNI?](https://www.cloudflare.com/learning/ssl/what-is-sni/) guide for more details.\n- All messages sent and received via WebSockets are encoded in JSON format\n- All decimal fields (including timestamps) are quoted to preserve precision.\n- Timestamps should not be considered unique and not be considered as aliases for transaction IDs. Also, the granularity of timestamps is not representative of transaction rates.\n- At least one private message should be subscribed to keep the authenticated client connection open.\n- Please use REST API endpoint [AssetPairs](https://www.kraken.com/features/api#get-tradable-pairs) to fetch the list of pairs which can be subscribed via WebSockets API. For example, field 'wsname' gives the supported pairs name which can be used to subscribe.\n- Cloudflare imposes a connection/re-connection rate limit (per IP address) of approximately 150 attempts per rolling 10 minutes. If this is exceeded, the IP is banned for 10 minutes.\n- Recommended reconnection behaviour is to (1) attempt reconnection instantly up to a handful of times if the websocket is dropped randomly during normal operation but (2) after maintenance or extended downtime, attempt to reconnect no more quickly than once every 5 seconds. There is no advantage to reconnecting more rapidly after maintenance during cancel_only mode.\n"},"channels":{"currencyExchange":{"address":"/","messages":{"dummyCurrencyInfo":{"$ref":"#/components/messages/dummyCurrencyInfo"},"heartbeat":{"$ref":"#/components/messages/heartbeat"},"ping":{"$ref":"#/components/messages/ping"},"pong":{"$ref":"#/components/messages/pong"},"subscribe":{"$ref":"#/components/messages/subscribe"},"subscriptionStatus":{"$ref":"#/components/messages/subscriptionStatus"},"systemStatus":{"$ref":"#/components/messages/systemStatus"},"unsubscribe":{"$ref":"#/components/messages/unsubscribe"}}}},"operations":{"receivePing":{"action":"receive","channel":{"$ref":"#/channels/currencyExchange"},"messages":[{"$ref":"#/channels/currencyExchange/messages/ping"}],"reply":{"channel":{"$ref":"#/channels/currencyExchange"},"messages":[{"$ref":"#/channels/currencyExchange/messages/pong"}]}},"receiveSubscribeRequest":{"action":"receive","channel":{"$ref":"#/channels/currencyExchange"},"messages":[{"$ref":"#/channels/currencyExchange/messages/subscribe"}],"reply":{"channel":{"$ref":"#/channels/currencyExchange"},"messages":[{"$ref":"#/channels/currencyExchange/messages/subscriptionStatus"},{"$ref":"#/channels/currencyExchange/messages/dummyCurrencyInfo"}]}},"receiveUnsubscribeRequest":{"action":"receive","channel":{"$ref":"#/channels/currencyExchange"},"messages":[{"$ref":"#/channels/currencyExchange/messages/unsubscribe"}],"reply":{"channel":{"$ref":"#/channels/currencyExchange"},"messages":[{"$ref":"#/channels/currencyExchange/messages/subscriptionStatus"}]}},"sendHeartbeat":{"action":"send","channel":{"$ref":"#/channels/currencyExchange"},"messages":[{"$ref":"#/channels/currencyExchange/messages/heartbeat"}]},"systemStatus":{"action":"send","channel":{"$ref":"#/channels/currencyExchange"},"messages":[{"$ref":"#/channels/currencyExchange/messages/systemStatus"}]}},"components":{"schemas":{"depth":{"type":"integer","enum":[10,25,100,500,1000],"description":"Depth associated with book subscription in number of levels each side.","default":10},"heartbeat":{"type":"object","properties":{"event":{"type":"string","const":"heartbeat"}}},"interval":{"type":"integer","enum":[1,5,15,30,60,240,1440,10080,21600],"description":"Time interval associated with ohlc subscription in minutes.","default":1},"maxratecount":{"type":"integer","description":"Max rate-limit budget. Compare to the ratecounter field in the openOrders updates to check whether you are approaching the rate limit."},"name":{"type":"string","enum":["book","ohlc","openOrders","ownTrades","spread","ticker","trade"],"description":"The name of the channel you subscribe too."},"pair":{"type":"array","items":{"type":"string","pattern":"[A-Z\\s]+\\/[A-Z\\s]+","description":"Format of each pair is \"A/B\", where A and B are ISO 4217-A3 for standardized assets and popular unique symbol if not standardized."},"description":"Array of currency pairs."},"ping":{"type":"object","required":["event"],"properties":{"event":{"type":"string","const":"ping"},"reqid":{"$ref":"#/components/schemas/reqid"}}},"pong":{"type":"object","properties":{"event":{"type":"string","const":"pong"},"reqid":{"$ref":"#/components/schemas/reqid"}}},"ratecounter":{"type":"boolean","description":"Whether to send rate-limit counter in updates (supported only for openOrders subscriptions)","default":false},"reqid":{"type":"integer","description":"client originated ID reflected in response message."},"snapshot":{"type":"boolean","description":"Whether to send historical feed data snapshot upon subscription (supported only for ownTrades subscriptions)","default":true},"status":{"type":"string","enum":["online","maintenance","cancel_only","limit_only","post_only"]},"subscribe":{"type":"object","required":["event"],"properties":{"event":{"type":"string","const":"subscribe"},"pair":{"$ref":"#/components/schemas/pair"},"reqid":{"$ref":"#/components/schemas/reqid"},"subscription":{"type":"object","required":["name"],"properties":{"depth":{"$ref":"#/components/schemas/depth"},"interval":{"$ref":"#/components/schemas/interval"},"name":{"$ref":"#/components/schemas/name"},"ratecounter":{"$ref":"#/components/schemas/ratecounter"},"snapshot":{"$ref":"#/components/schemas/snapshot"},"token":{"$ref":"#/components/schemas/token"}}}}},"subscriptionStatus":{"type":"object","oneOf":[{"$ref":"#/components/schemas/subscriptionStatusError"},{"$ref":"#/components/schemas/subscriptionStatusSuccess"}]},"subscriptionStatusCommon":{"type":"object","required":["event"],"properties":{"event":{"type":"string","const":"subscriptionStatus"},"pair":{"$ref":"#/components/schemas/pair"},"reqid":{"$ref":"#/components/schemas/reqid"},"status":{"$ref":"#/components/schemas/status"},"subscription":{"type":"object","required":["name"],"properties":{"depth":{"$ref":"#/components/schemas/depth"},"interval":{"$ref":"#/components/schemas/interval"},"maxratecount":{"$ref":"#/components/schemas/maxratecount"},"name":{"$ref":"#/components/schemas/name"},"token":{"$ref":"#/components/schemas/token"}}}}},"subscriptionStatusError":{"allOf":[{"required":["errorMessage"],"properties":{"errorMessage":{"type":"string"}}},{"$ref":"#/components/schemas/subscriptionStatusCommon"}]},"subscriptionStatusSuccess":{"allOf":[{"required":["channelID","channelName"],"properties":{"channelID":{"type":"integer","description":"ChannelID on successful subscription, applicable to public messages only."},"channelName":{"type":"string","description":"Channel Name on successful subscription. For payloads 'ohlc' and 'book', respective interval or depth will be added as suffix."}}},{"$ref":"#/components/schemas/subscriptionStatusCommon"}]},"systemStatus":{"type":"object","properties":{"connectionID":{"type":"integer","description":"The ID of the connection"},"event":{"type":"string","const":"systemStatus"},"status":{"$ref":"#/components/schemas/status"},"version":{"type":"string"}}},"token":{"type":"string","description":"base64-encoded authentication token for private-data endpoints."},"unsubscribe":{"type":"object","required":["event"],"properties":{"event":{"type":"string","const":"unsubscribe"},"pair":{"$ref":"#/components/schemas/pair"},"reqid":{"$ref":"#/components/schemas/reqid"},"subscription":{"type":"object","required":["name"],"properties":{"depth":{"$ref":"#/components/schemas/depth"},"interval":{"$ref":"#/components/schemas/interval"},"name":{"$ref":"#/components/schemas/name"},"token":{"$ref":"#/components/schemas/token"}}}}}},"messages":{"dummyCurrencyInfo":{"payload":{"type":"object","required":["event"],"properties":{"data":{"type":"object"},"event":{"type":"string","const":"currencyInfo"},"reqid":{"$ref":"#/components/schemas/reqid"}}},"correlationId":{"location":"$message.payload#/reqid"},"summary":"Dummy message with no real life details","description":"It is here in this example to showcase that there is an additional message that normally is of a complex structure. It represents actually currency exchange value to show a reply to operation receiveSubscribeRequest with more than one possible message."},"heartbeat":{"payload":{"$ref":"#/components/schemas/heartbeat"},"description":"Server heartbeat sent if no subscription traffic within 1 second (approximately)"},"ping":{"payload":{"$ref":"#/components/schemas/ping"},"correlationId":{"location":"$message.payload#/reqid"},"summary":"Ping server to determine whether connection is alive","description":"Client can ping server to determine whether connection is alive, server responds with pong. This is an application level ping as opposed to default ping in websockets standard which is server initiated"},"pong":{"payload":{"$ref":"#/components/schemas/pong"},"correlationId":{"location":"$message.payload#/reqid"},"summary":"Pong is a response to ping message","description":"Server pong response to a ping to determine whether connection is alive. This is an application level pong as opposed to default pong in websockets standard which is sent by client in response to a ping"},"subscribe":{"payload":{"$ref":"#/components/schemas/subscribe"},"correlationId":{"location":"$message.payload#/reqid"},"description":"Subscribe to a topic on a single or multiple currency pairs."},"subscriptionStatus":{"payload":{"$ref":"#/components/schemas/subscriptionStatus"},"description":"Subscription status response to subscribe, unsubscribe or exchange initiated unsubscribe.","examples":[{"payload":{"channelID":10001,"channelName":"ohlc-5","event":"subscriptionStatus","pair":"XBT/EUR","reqid":42,"status":"unsubscribed","subscription":{"interval":5,"name":"ohlc"}}},{"payload":{"errorMessage":"Subscription depth not supported","event":"subscriptionStatus","pair":"XBT/USD","status":"error","subscription":{"depth":42,"name":"book"}}}]},"systemStatus":{"payload":{"$ref":"#/components/schemas/systemStatus"},"description":"Status sent on connection or system status changes."},"unsubscribe":{"payload":{"$ref":"#/components/schemas/unsubscribe"},"correlationId":{"location":"$message.payload#/reqid"},"description":"Unsubscribe, can specify a channelID or multiple currency pairs."}}}}
+ test/golden/examples/reference-examples-kraken-websocket-request-reply-multiple-channels-asyncapi.yml.json view
@@ -0,0 +1,1 @@+{"asyncapi":"3.1.0","info":{"title":"Kraken Websockets API","version":"1.8.0","description":"WebSockets API offers real-time market data updates. WebSockets is a bidirectional protocol offering fastest real-time data, helping you build real-time applications. The public message types presented below do not require authentication. Private-data messages can be subscribed on a separate authenticated endpoint. \n\n### General Considerations\n\n- TLS with SNI (Server Name Indication) is required in order to establish a Kraken WebSockets API connection. See Cloudflare's [What is SNI?](https://www.cloudflare.com/learning/ssl/what-is-sni/) guide for more details.\n- All messages sent and received via WebSockets are encoded in JSON format\n- All decimal fields (including timestamps) are quoted to preserve precision.\n- Timestamps should not be considered unique and not be considered as aliases for transaction IDs. Also, the granularity of timestamps is not representative of transaction rates.\n- At least one private message should be subscribed to keep the authenticated client connection open.\n- Please use REST API endpoint [AssetPairs](https://www.kraken.com/features/api#get-tradable-pairs) to fetch the list of pairs which can be subscribed via WebSockets API. For example, field 'wsname' gives the supported pairs name which can be used to subscribe.\n- Cloudflare imposes a connection/re-connection rate limit (per IP address) of approximately 150 attempts per rolling 10 minutes. If this is exceeded, the IP is banned for 10 minutes.\n- Recommended reconnection behaviour is to (1) attempt reconnection instantly up to a handful of times if the websocket is dropped randomly during normal operation but (2) after maintenance or extended downtime, attempt to reconnect no more quickly than once every 5 seconds. There is no advantage to reconnecting more rapidly after maintenance during cancel_only mode.\n"},"channels":{"currencyInfo":{"address":"/","messages":{"dummyCurrencyInfo":{"$ref":"#/components/messages/dummyCurrencyInfo"},"subscriptionStatus":{"$ref":"#/components/messages/subscriptionStatus"}}},"heartbeat":{"address":"/","messages":{"heartbeat":{"$ref":"#/components/messages/heartbeat"}}},"ping":{"address":"/","messages":{"ping":{"$ref":"#/components/messages/ping"}}},"pong":{"address":"/","messages":{"pong":{"$ref":"#/components/messages/pong"}}},"subscribe":{"address":"/","messages":{"subscribe":{"$ref":"#/components/messages/subscribe"}}},"systemStatus":{"address":"/","messages":{"systemStatus":{"$ref":"#/components/messages/systemStatus"}}},"unsubscribe":{"address":"/","messages":{"unsubscribe":{"$ref":"#/components/messages/unsubscribe"}}}},"operations":{"heartbeat":{"action":"send","channel":{"$ref":"#/channels/heartbeat"}},"receivePing":{"action":"receive","channel":{"$ref":"#/channels/ping"},"reply":{"channel":{"$ref":"#/channels/pong"}}},"subscribe":{"action":"receive","channel":{"$ref":"#/channels/subscribe"},"reply":{"channel":{"$ref":"#/channels/currencyInfo"}}},"systemStatus":{"action":"send","channel":{"$ref":"#/channels/systemStatus"}},"unsubscribe":{"action":"receive","channel":{"$ref":"#/channels/unsubscribe"},"reply":{"channel":{"$ref":"#/channels/currencyInfo"},"messages":[{"$ref":"#/channels/currencyInfo/messages/subscriptionStatus"}]}}},"components":{"schemas":{"depth":{"type":"integer","enum":[10,25,100,500,1000],"description":"Depth associated with book subscription in number of levels each side.","default":10},"heartbeat":{"type":"object","properties":{"event":{"type":"string","const":"heartbeat"}}},"interval":{"type":"integer","enum":[1,5,15,30,60,240,1440,10080,21600],"description":"Time interval associated with ohlc subscription in minutes.","default":1},"maxratecount":{"type":"integer","description":"Max rate-limit budget. Compare to the ratecounter field in the openOrders updates to check whether you are approaching the rate limit."},"name":{"type":"string","enum":["book","ohlc","openOrders","ownTrades","spread","ticker","trade"],"description":"The name of the channel you subscribe too."},"pair":{"type":"array","items":{"type":"string","pattern":"[A-Z\\s]+\\/[A-Z\\s]+","description":"Format of each pair is \"A/B\", where A and B are ISO 4217-A3 for standardized assets and popular unique symbol if not standardized."},"description":"Array of currency pairs."},"ping":{"type":"object","required":["event"],"properties":{"event":{"type":"string","const":"ping"},"reqid":{"$ref":"#/components/schemas/reqid"}}},"pong":{"type":"object","properties":{"event":{"type":"string","const":"pong"},"reqid":{"$ref":"#/components/schemas/reqid"}}},"ratecounter":{"type":"boolean","description":"Whether to send rate-limit counter in updates (supported only for openOrders subscriptions)","default":false},"reqid":{"type":"integer","description":"client originated ID reflected in response message."},"snapshot":{"type":"boolean","description":"Whether to send historical feed data snapshot upon subscription (supported only for ownTrades subscriptions)","default":true},"status":{"type":"string","enum":["online","maintenance","cancel_only","limit_only","post_only"]},"subscribe":{"type":"object","required":["event"],"properties":{"event":{"type":"string","const":"subscribe"},"pair":{"$ref":"#/components/schemas/pair"},"reqid":{"$ref":"#/components/schemas/reqid"},"subscription":{"type":"object","required":["name"],"properties":{"depth":{"$ref":"#/components/schemas/depth"},"interval":{"$ref":"#/components/schemas/interval"},"name":{"$ref":"#/components/schemas/name"},"ratecounter":{"$ref":"#/components/schemas/ratecounter"},"snapshot":{"$ref":"#/components/schemas/snapshot"},"token":{"$ref":"#/components/schemas/token"}}}}},"subscriptionStatus":{"type":"object","oneOf":[{"$ref":"#/components/schemas/subscriptionStatusError"},{"$ref":"#/components/schemas/subscriptionStatusSuccess"}]},"subscriptionStatusCommon":{"type":"object","required":["event"],"properties":{"event":{"type":"string","const":"subscriptionStatus"},"pair":{"$ref":"#/components/schemas/pair"},"reqid":{"$ref":"#/components/schemas/reqid"},"status":{"$ref":"#/components/schemas/status"},"subscription":{"type":"object","required":["name"],"properties":{"depth":{"$ref":"#/components/schemas/depth"},"interval":{"$ref":"#/components/schemas/interval"},"maxratecount":{"$ref":"#/components/schemas/maxratecount"},"name":{"$ref":"#/components/schemas/name"},"token":{"$ref":"#/components/schemas/token"}}}}},"subscriptionStatusError":{"allOf":[{"required":["errorMessage"],"properties":{"errorMessage":{"type":"string"}}},{"$ref":"#/components/schemas/subscriptionStatusCommon"}]},"subscriptionStatusSuccess":{"allOf":[{"required":["channelID","channelName"],"properties":{"channelID":{"type":"integer","description":"ChannelID on successful subscription, applicable to public messages only."},"channelName":{"type":"string","description":"Channel Name on successful subscription. For payloads 'ohlc' and 'book', respective interval or depth will be added as suffix."}}},{"$ref":"#/components/schemas/subscriptionStatusCommon"}]},"systemStatus":{"type":"object","properties":{"connectionID":{"type":"integer","description":"The ID of the connection"},"event":{"type":"string","const":"systemStatus"},"status":{"$ref":"#/components/schemas/status"},"version":{"type":"string"}}},"token":{"type":"string","description":"base64-encoded authentication token for private-data endpoints."},"unsubscribe":{"type":"object","required":["event"],"properties":{"event":{"type":"string","const":"unsubscribe"},"pair":{"$ref":"#/components/schemas/pair"},"reqid":{"$ref":"#/components/schemas/reqid"},"subscription":{"type":"object","required":["name"],"properties":{"depth":{"$ref":"#/components/schemas/depth"},"interval":{"$ref":"#/components/schemas/interval"},"name":{"$ref":"#/components/schemas/name"},"token":{"$ref":"#/components/schemas/token"}}}}}},"messages":{"dummyCurrencyInfo":{"payload":{"type":"object","required":["event"],"properties":{"data":{"type":"object"},"event":{"type":"string","const":"currencyInfo"},"reqid":{"$ref":"#/components/schemas/reqid"}}},"correlationId":{"location":"$message.payload#/reqid"},"summary":"Dummy message with no real life details","description":"It is here in this example to showcase that there is an additional message that normally is of a complex structure. It represents actually currency exchange value to show a reply to operation receiveSubscribeRequest with more than one possible message."},"heartbeat":{"payload":{"$ref":"#/components/schemas/heartbeat"},"description":"Server heartbeat sent if no subscription traffic within 1 second (approximately)"},"ping":{"payload":{"$ref":"#/components/schemas/ping"},"correlationId":{"location":"$message.payload#/reqid"},"summary":"Ping server to determine whether connection is alive","description":"Client can ping server to determine whether connection is alive, server responds with pong. This is an application level ping as opposed to default ping in websockets standard which is server initiated"},"pong":{"payload":{"$ref":"#/components/schemas/pong"},"correlationId":{"location":"$message.payload#/reqid"},"summary":"Pong is a response to ping message","description":"Server pong response to a ping to determine whether connection is alive. This is an application level pong as opposed to default pong in websockets standard which is sent by client in response to a ping"},"subscribe":{"payload":{"$ref":"#/components/schemas/subscribe"},"correlationId":{"location":"$message.payload#/reqid"},"description":"Subscribe to a topic on a single or multiple currency pairs."},"subscriptionStatus":{"payload":{"$ref":"#/components/schemas/subscriptionStatus"},"description":"Subscription status response to subscribe, unsubscribe or exchange initiated unsubscribe.","examples":[{"payload":{"channelID":10001,"channelName":"ohlc-5","event":"subscriptionStatus","pair":"XBT/EUR","reqid":42,"status":"unsubscribed","subscription":{"interval":5,"name":"ohlc"}}},{"payload":{"errorMessage":"Subscription depth not supported","event":"subscriptionStatus","pair":"XBT/USD","status":"error","subscription":{"depth":42,"name":"book"}}}]},"systemStatus":{"payload":{"$ref":"#/components/schemas/systemStatus"},"description":"Status sent on connection or system status changes."},"unsubscribe":{"payload":{"$ref":"#/components/schemas/unsubscribe"},"correlationId":{"location":"$message.payload#/reqid"},"description":"Unsubscribe, can specify a channelID or multiple currency pairs."}}}}
+ test/golden/examples/reference-examples-mercure-asyncapi.yml.json view
@@ -0,0 +1,1 @@+{"asyncapi":"3.1.0","info":{"title":"Mercure Hub Example","version":"1.0.0","description":"This example demonstrates how to define a Mercure hub."},"servers":{"production":{"host":"demo.mercure.rocks","protocol":"mercure","pathname":"/.well-known/mercure"}},"defaultContentType":"application/ld+json","channels":{"books":{"address":"https://example.com/books/{id}","messages":{"book":{"$ref":"#/components/messages/book"}},"description":"Every time a resource of type `http://schema.org/Book` is created or modified, a JSON-LD representation of the new version of this resource must be pushed in this Mercure topic.","parameters":{"id":{"description":"ID of the book"}}}},"operations":{"ReceiveBooksInfo":{"action":"receive","channel":{"$ref":"#/channels/books"},"messages":[{"$ref":"#/channels/books/messages/book"}]},"SendBooksInfo":{"action":"send","channel":{"$ref":"#/channels/books"},"messages":[{"$ref":"#/channels/books/messages/book"}]}},"components":{"messages":{"book":{"payload":{"type":"object","properties":{"@id":{"type":"string","format":"iri-reference"},"@type":{"type":"string","format":"iri-reference"},"abstract":{"type":"string"},"isbn":{"type":"string"},"name":{"type":"string"}}},"summary":"The content of a book resource.","externalDocs":{"url":"https://schema.org/Book"}}}}}
+ test/golden/examples/reference-examples-not-asyncapi.yml.json view
@@ -0,0 +1,1 @@+{"asyncapi":"3.1.0","info":{"title":"Not example","version":"1.0.0"},"channels":{"test":{"address":"test","messages":{"testMessages":{"$ref":"#/components/messages/testMessages"}}}},"operations":{"onTestMsg":{"action":"receive","channel":{"$ref":"#/channels/test"},"messages":[{"$ref":"#/channels/test/messages/testMessages"}]}},"components":{"schemas":{"testSchema":{"type":"object","properties":{"key":{"not":{"type":"integer"}}}}},"messages":{"testMessages":{"payload":{"$ref":"#/components/schemas/testSchema"}}}}}
+ test/golden/examples/reference-examples-oneof-asyncapi.yml.json view
@@ -0,0 +1,1 @@+{"asyncapi":"3.1.0","info":{"title":"OneOf example","version":"1.0.0"},"channels":{"test":{"address":"test","messages":{"testMessages":{"$ref":"#/components/messages/testMessages"}}},"test2":{"address":"test2","messages":{"objectWithKey":{"payload":{"$ref":"#/components/schemas/objectWithKey"}},"objectWithKey2":{"payload":{"$ref":"#/components/schemas/objectWithKey2"}}}}},"operations":{"onTestMsg":{"action":"receive","channel":{"$ref":"#/channels/test"},"messages":[{"$ref":"#/channels/test/messages/testMessages"}]},"sendTest":{"action":"send","channel":{"$ref":"#/channels/test2"},"messages":[{"$ref":"#/channels/test2/messages/objectWithKey"},{"$ref":"#/channels/test2/messages/objectWithKey2"}]}},"components":{"schemas":{"objectWithKey":{"type":"object","properties":{"key":{"type":"string"}}},"objectWithKey2":{"type":"object","properties":{"key2":{"type":"string"}}}},"messages":{"testMessage1":{"payload":{"$ref":"#/components/schemas/objectWithKey"}},"testMessage2":{"payload":{"$ref":"#/components/schemas/objectWithKey2"}},"testMessages":{"payload":{"oneOf":[{"$ref":"#/components/schemas/objectWithKey"},{"$ref":"#/components/schemas/objectWithKey2"}]}}}}}
+ test/golden/examples/reference-examples-operation-security-asyncapi.yml.json view
@@ -0,0 +1,1 @@+{"asyncapi":"3.1.0","info":{"title":"Notifications","version":"1.0.0","description":"This contract defines HTTP Push notification for  application authorization revocation topic"},"channels":{"authRevoke":{"address":"AUTHORIZATION_REVOCATION","messages":{"message":{"$ref":"#/components/messages/message"}}}},"operations":{"sendAuthRevoke":{"action":"send","channel":{"$ref":"#/channels/authRevoke"},"security":[{"type":"oauth2","description":"The oauth security descriptions","flows":{"clientCredentials":{"tokenUrl":"https://example.com/api/oauth/dialog","availableScopes":{"subscribe:auth_revocations":"Scope required for authorization revocation topic"}}},"scopes":["subscribe:auth_revocations"]}],"bindings":{"http":{"method":"POST"}},"messages":[{"$ref":"#/channels/authRevoke/messages/message"}]}},"components":{"schemas":{"AuthorizationRevocationData":{"type":"object","properties":{"eiasToken":{"type":"string","description":"The legacy eiasToken specific to the user"},"revocationDate":{"type":"string","description":"Date and time when the authorization was revoked"},"revokeReason":{"type":"string","enum":["REVOKED_BY_APP","REVOKED_BY_USER","REVOKED_BY_ADMIN","PASSWORD_CHANGE"],"description":"The reason for authorization revocation"},"userId":{"type":"string","description":"The immutable public userId for the user"},"username":{"type":"string","description":"The username for the user."}},"description":"The Authorization Revocation payload."},"MetaData":{"type":"object","properties":{"deprecated":{"type":"boolean","description":"If this is a deprecated schema or topic.","default":"false"},"schemaVersion":{"type":"string","description":"The schema for this topic."},"topic":{"type":"string","description":"Topic subscribed to."}}},"Notification":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/AuthorizationRevocationData"},"eventDate":{"type":"string","description":"The event date associated with this notification in UTC."},"notificationId":{"type":"string","description":"The notification Id."},"publishAttemptCount":{"type":"integer","description":"The number of attempts made to publish this message."},"publishDate":{"type":"string","description":"The message publish date in UTC."}}}},"messages":{"message":{"headers":{"type":"object","properties":{"Content-Type":{"type":"string","enum":["application/json"]},"X-SIGNATURE":{"type":"string","description":"ECC message signature"}}},"payload":{"type":"object","properties":{"metadata":{"$ref":"#/components/schemas/MetaData"},"notification":{"$ref":"#/components/schemas/Notification"}}}}},"securitySchemes":{"petstore_auth":{"type":"oauth2","description":"The oauth security descriptions","flows":{"clientCredentials":{"tokenUrl":"https://example.com/api/oauth/dialog","availableScopes":{"subscribe:auth_revocations":"Scope required for authorization revocation topic"}}}}}}}
+ test/golden/examples/reference-examples-rpc-client-asyncapi.yml.json view
@@ -0,0 +1,1 @@+{"asyncapi":"3.1.0","id":"urn:example:rpcclient","info":{"title":"RPC Client Example","version":"1.0.0","description":"This example demonstrates how to define an RPC client."},"servers":{"production":{"host":"rabbitmq.example.org","protocol":"amqp"}},"defaultContentType":"application/json","channels":{"queue":{"address":"{queue}","messages":{"receiveSumResult":{"payload":{"type":"object","properties":{"result":{"type":"number","examples":[7]}}},"correlationId":{"location":"$message.header#/correlation_id"}}},"parameters":{"queue":{}},"bindings":{"amqp":{"is":"queue","queue":{"exclusive":true}}}},"rpc_queue":{"address":"rpc_queue","messages":{"requestSum":{"payload":{"type":"object","properties":{"numbers":{"type":"array","examples":[[4,3]],"items":{"type":"number"}}}},"correlationId":{"location":"$message.header#/correlation_id"}}},"bindings":{"amqp":{"is":"queue","queue":{"durable":false}}}}},"operations":{"receiveSumResult":{"action":"receive","channel":{"$ref":"#/channels/queue"},"bindings":{"amqp":{"ack":false}},"messages":[{"$ref":"#/channels/queue/messages/receiveSumResult"}]},"requestSum":{"action":"send","channel":{"$ref":"#/channels/rpc_queue"},"bindings":{"amqp":{"ack":true}},"messages":[{"$ref":"#/channels/rpc_queue/messages/requestSum"}]}}}
+ test/golden/examples/reference-examples-rpc-server-asyncapi.yml.json view
@@ -0,0 +1,1 @@+{"asyncapi":"3.1.0","id":"urn:example:rpcserver","info":{"title":"RPC Server Example","version":"1.0.0","description":"This example demonstrates how to define an RPC server."},"servers":{"production":{"host":"rabbitmq.example.org","protocol":"amqp"}},"defaultContentType":"application/json","channels":{"queue":{"address":"{queue}","messages":{"sendSumResult":{"payload":{"type":"object","properties":{"result":{"type":"number","examples":[7]}}},"correlationId":{"location":"$message.header#/correlation_id"}}},"parameters":{"queue":{}},"bindings":{"amqp":{"is":"queue","queue":{"exclusive":true}}}},"rpc_queue":{"address":"rpc_queue","messages":{"sum":{"payload":{"type":"object","properties":{"numbers":{"type":"array","examples":[[4,3]],"items":{"type":"number"}}}},"correlationId":{"location":"$message.header#/correlation_id"}}},"bindings":{"amqp":{"is":"queue","queue":{"durable":false}}}}},"operations":{"sendSumResult":{"action":"send","channel":{"$ref":"#/channels/queue"},"bindings":{"amqp":{"ack":true}},"messages":[{"$ref":"#/channels/queue/messages/sendSumResult"}]},"sum":{"action":"receive","channel":{"$ref":"#/channels/rpc_queue"},"messages":[{"$ref":"#/channels/rpc_queue/messages/sum"}]}}}
+ test/golden/examples/reference-examples-simple-asyncapi.yml.json view
@@ -0,0 +1,1 @@+{"asyncapi":"3.1.0","info":{"title":"Account Service","version":"1.0.0","description":"This service is in charge of processing user signups"},"channels":{"userSignedup":{"address":"user/signedup","messages":{"UserSignedUp":{"$ref":"#/components/messages/UserSignedUp"}}}},"operations":{"sendUserSignedup":{"action":"send","channel":{"$ref":"#/channels/userSignedup"},"messages":[{"$ref":"#/channels/userSignedup/messages/UserSignedUp"}]}},"components":{"messages":{"UserSignedUp":{"payload":{"type":"object","properties":{"displayName":{"type":"string","description":"Name of the user"},"email":{"type":"string","description":"Email of the user","format":"email"}}}}}}}
+ test/golden/examples/reference-examples-slack-rtm-asyncapi.yml.json view
@@ -0,0 +1,1 @@+{"asyncapi":"3.1.0","id":"wss://wss-primary.slack.com/websocket","info":{"title":"Slack Real Time Messaging API","version":"1.0.0"},"servers":{"production":{"host":"slack.com","protocol":"https","protocolVersion":"1.1","pathname":"/api/rtm.connect","security":[{"$ref":"#/components/securitySchemes/token"}]}},"channels":{"root":{"address":"/","messages":{"accountsChanged":{"$ref":"#/components/messages/accountsChanged"},"botAdded":{"$ref":"#/components/messages/botAdded"},"botChanged":{"$ref":"#/components/messages/botChanged"},"channelArchive":{"$ref":"#/components/messages/channelArchive"},"channelCreated":{"$ref":"#/components/messages/channelCreated"},"channelDeleted":{"$ref":"#/components/messages/channelDeleted"},"channelHistoryChanged":{"$ref":"#/components/messages/channelHistoryChanged"},"channelJoined":{"$ref":"#/components/messages/channelJoined"},"channelLeft":{"$ref":"#/components/messages/channelLeft"},"channelMarked":{"$ref":"#/components/messages/channelMarked"},"channelRename":{"$ref":"#/components/messages/channelRename"},"channelUnarchive":{"$ref":"#/components/messages/channelUnarchive"},"commandsChanged":{"$ref":"#/components/messages/commandsChanged"},"connectionError":{"$ref":"#/components/messages/connectionError"},"dndUpdated":{"$ref":"#/components/messages/dndUpdated"},"dndUpdatedUser":{"$ref":"#/components/messages/dndUpdatedUser"},"emailDomainChanged":{"$ref":"#/components/messages/emailDomainChanged"},"emojiAdded":{"$ref":"#/components/messages/emojiAdded"},"emojiRemoved":{"$ref":"#/components/messages/emojiRemoved"},"fileChange":{"$ref":"#/components/messages/fileChange"},"fileCommentAdded":{"$ref":"#/components/messages/fileCommentAdded"},"fileCommentDeleted":{"$ref":"#/components/messages/fileCommentDeleted"},"fileCommentEdited":{"$ref":"#/components/messages/fileCommentEdited"},"fileCreated":{"$ref":"#/components/messages/fileCreated"},"fileDeleted":{"$ref":"#/components/messages/fileDeleted"},"filePublic":{"$ref":"#/components/messages/filePublic"},"fileShared":{"$ref":"#/components/messages/fileShared"},"fileUnshared":{"$ref":"#/components/messages/fileUnshared"},"goodbye":{"$ref":"#/components/messages/goodbye"},"groupArchive":{"$ref":"#/components/messages/groupArchive"},"groupClose":{"$ref":"#/components/messages/groupClose"},"groupHistoryChanged":{"$ref":"#/components/messages/groupHistoryChanged"},"groupJoined":{"$ref":"#/components/messages/groupJoined"},"groupLeft":{"$ref":"#/components/messages/groupLeft"},"groupMarked":{"$ref":"#/components/messages/groupMarked"},"groupOpen":{"$ref":"#/components/messages/groupOpen"},"groupRename":{"$ref":"#/components/messages/groupRename"},"groupUnarchive":{"$ref":"#/components/messages/groupUnarchive"},"hello":{"$ref":"#/components/messages/hello"},"imClose":{"$ref":"#/components/messages/imClose"},"imCreated":{"$ref":"#/components/messages/imCreated"},"imMarked":{"$ref":"#/components/messages/imMarked"},"imOpen":{"$ref":"#/components/messages/imOpen"},"manualPresenceChange":{"$ref":"#/components/messages/manualPresenceChange"},"memberJoinedChannel":{"$ref":"#/components/messages/memberJoinedChannel"},"message":{"$ref":"#/components/messages/message"},"outgoingMessage":{"$ref":"#/components/messages/outgoingMessage"}}}},"operations":{"receiveOutgoingMessage":{"action":"receive","channel":{"$ref":"#/channels/root"},"messages":[{"$ref":"#/channels/root/messages/outgoingMessage"}]},"sendMessages":{"action":"send","channel":{"$ref":"#/channels/root"},"messages":[{"$ref":"#/channels/root/messages/hello"},{"$ref":"#/channels/root/messages/connectionError"},{"$ref":"#/channels/root/messages/accountsChanged"},{"$ref":"#/channels/root/messages/botAdded"},{"$ref":"#/channels/root/messages/botChanged"},{"$ref":"#/channels/root/messages/channelArchive"},{"$ref":"#/channels/root/messages/channelCreated"},{"$ref":"#/channels/root/messages/channelDeleted"},{"$ref":"#/channels/root/messages/channelHistoryChanged"},{"$ref":"#/channels/root/messages/channelJoined"},{"$ref":"#/channels/root/messages/channelLeft"},{"$ref":"#/channels/root/messages/channelMarked"},{"$ref":"#/channels/root/messages/channelRename"},{"$ref":"#/channels/root/messages/channelUnarchive"},{"$ref":"#/channels/root/messages/commandsChanged"},{"$ref":"#/channels/root/messages/dndUpdated"},{"$ref":"#/channels/root/messages/dndUpdatedUser"},{"$ref":"#/channels/root/messages/emailDomainChanged"},{"$ref":"#/channels/root/messages/emojiRemoved"},{"$ref":"#/channels/root/messages/emojiAdded"},{"$ref":"#/channels/root/messages/fileChange"},{"$ref":"#/channels/root/messages/fileCommentAdded"},{"$ref":"#/channels/root/messages/fileCommentDeleted"},{"$ref":"#/channels/root/messages/fileCommentEdited"},{"$ref":"#/channels/root/messages/fileCreated"},{"$ref":"#/channels/root/messages/fileDeleted"},{"$ref":"#/channels/root/messages/filePublic"},{"$ref":"#/channels/root/messages/fileShared"},{"$ref":"#/channels/root/messages/fileUnshared"},{"$ref":"#/channels/root/messages/goodbye"},{"$ref":"#/channels/root/messages/groupArchive"},{"$ref":"#/channels/root/messages/groupClose"},{"$ref":"#/channels/root/messages/groupHistoryChanged"},{"$ref":"#/channels/root/messages/groupJoined"},{"$ref":"#/channels/root/messages/groupLeft"},{"$ref":"#/channels/root/messages/groupMarked"},{"$ref":"#/channels/root/messages/groupOpen"},{"$ref":"#/channels/root/messages/groupRename"},{"$ref":"#/channels/root/messages/groupUnarchive"},{"$ref":"#/channels/root/messages/imClose"},{"$ref":"#/channels/root/messages/imCreated"},{"$ref":"#/channels/root/messages/imMarked"},{"$ref":"#/channels/root/messages/imOpen"},{"$ref":"#/channels/root/messages/manualPresenceChange"},{"$ref":"#/channels/root/messages/memberJoinedChannel"},{"$ref":"#/channels/root/messages/message"}]}},"components":{"schemas":{"attachment":{"type":"object","properties":{"author_icon":{"type":"string","format":"uri"},"author_link":{"type":"string","format":"uri"},"author_name":{"type":"string"},"color":{"type":"string"},"fallback":{"type":"string"},"fields":{"type":"array","items":{"type":"object","properties":{"short":{"type":"boolean"},"title":{"type":"string"},"value":{"type":"string"}}}},"footer":{"type":"string"},"footer_icon":{"type":"string","format":"uri"},"image_url":{"type":"string","format":"uri"},"pretext":{"type":"string"},"text":{"type":"string"},"thumb_url":{"type":"string","format":"uri"},"title":{"type":"string"},"title_link":{"type":"string","format":"uri"},"ts":{"type":"number"}}}},"messages":{"accountsChanged":{"payload":{"type":"object","properties":{"type":{"type":"string","enum":["accounts_changed"]}}},"summary":"The list of accounts a user is signed into has changed."},"botAdded":{"payload":{"type":"object","properties":{"bot":{"type":"object","properties":{"app_id":{"type":"string"},"icons":{"type":"object","additionalProperties":{"type":"string"}},"id":{"type":"string"},"name":{"type":"string"}}},"type":{"type":"string","enum":["bot_added"]}}},"summary":"A bot user was added."},"botChanged":{"payload":{"type":"object","properties":{"bot":{"type":"object","properties":{"app_id":{"type":"string"},"icons":{"type":"object","additionalProperties":{"type":"string"}},"id":{"type":"string"},"name":{"type":"string"}}},"type":{"type":"string","enum":["bot_added"]}}},"summary":"A bot user was changed."},"channelArchive":{"payload":{"type":"object","properties":{"channel":{"type":"string"},"type":{"type":"string","enum":["channel_archive"]},"user":{"type":"string"}}},"summary":"A channel was archived."},"channelCreated":{"payload":{"type":"object","properties":{"channel":{"type":"object","properties":{"created":{"type":"number"},"creator":{"type":"string"},"id":{"type":"string"},"name":{"type":"string"}}},"type":{"type":"string","enum":["channel_created"]}}},"summary":"A channel was created."},"channelDeleted":{"payload":{"type":"object","properties":{"channel":{"type":"string"},"type":{"type":"string","enum":["channel_deleted"]}}},"summary":"A channel was deleted."},"channelHistoryChanged":{"payload":{"type":"object","properties":{"event_ts":{"type":"string"},"latest":{"type":"string"},"ts":{"type":"string"},"type":{"type":"string","enum":["channel_history_changed"]}}},"summary":"Bulk updates were made to a channel's history."},"channelJoined":{"payload":{"type":"object","properties":{"channel":{"type":"object","properties":{"created":{"type":"number"},"creator":{"type":"string"},"id":{"type":"string"},"name":{"type":"string"}}},"type":{"type":"string","enum":["channel_joined"]}}},"summary":"You joined a channel."},"channelLeft":{"payload":{"type":"object","properties":{"channel":{"type":"string"},"type":{"type":"string","enum":["channel_left"]}}},"summary":"You left a channel."},"channelMarked":{"payload":{"type":"object","properties":{"channel":{"type":"string"},"ts":{"type":"string"},"type":{"type":"string","enum":["channel_marked"]}}},"summary":"Your channel read marker was updated."},"channelRename":{"payload":{"type":"object","properties":{"channel":{"type":"object","properties":{"created":{"type":"number"},"id":{"type":"string"},"name":{"type":"string"}}},"type":{"type":"string","enum":["channel_rename"]}}},"summary":"A channel was renamed."},"channelUnarchive":{"payload":{"type":"object","properties":{"channel":{"type":"string"},"type":{"type":"string","enum":["channel_unarchive"]},"user":{"type":"string"}}},"summary":"A channel was unarchived."},"commandsChanged":{"payload":{"type":"object","properties":{"event_ts":{"type":"string"},"type":{"type":"string","enum":["commands_changed"]}}},"summary":"A slash command has been added or changed."},"connectionError":{"payload":{"type":"object","properties":{"error":{"type":"object","properties":{"code":{"type":"number"},"msg":{"type":"string"}}},"type":{"type":"string","enum":["error"]}}},"summary":"Event received when a connection error happens."},"dndUpdated":{"payload":{"type":"object","properties":{"dnd_status":{"type":"object","properties":{"dnd_enabled":{"type":"boolean"},"next_dnd_end_ts":{"type":"number"},"next_dnd_start_ts":{"type":"number"},"snooze_enabled":{"type":"boolean"},"snooze_endtime":{"type":"number"}}},"type":{"type":"string","enum":["dnd_updated"]},"user":{"type":"string"}}},"summary":"Do not Disturb settings changed for the current user."},"dndUpdatedUser":{"payload":{"type":"object","properties":{"dnd_status":{"type":"object","properties":{"dnd_enabled":{"type":"boolean"},"next_dnd_end_ts":{"type":"number"},"next_dnd_start_ts":{"type":"number"}}},"type":{"type":"string","enum":["dnd_updated_user"]},"user":{"type":"string"}}},"summary":"Do not Disturb settings changed for a member."},"emailDomainChanged":{"payload":{"type":"object","properties":{"email_domain":{"type":"string"},"event_ts":{"type":"string"},"type":{"type":"string","enum":["email_domain_changed"]}}},"summary":"The workspace email domain has changed."},"emojiAdded":{"payload":{"type":"object","properties":{"event_ts":{"type":"string"},"name":{"type":"string"},"subtype":{"type":"string","enum":["add"]},"type":{"type":"string","enum":["emoji_changed"]},"value":{"type":"string","format":"uri"}}},"summary":"A custom emoji has been added."},"emojiRemoved":{"payload":{"type":"object","properties":{"event_ts":{"type":"string"},"names":{"type":"array","items":{"type":"string"}},"subtype":{"type":"string","enum":["remove"]},"type":{"type":"string","enum":["emoji_changed"]}}},"summary":"A custom emoji has been removed."},"fileChange":{"payload":{"type":"object","properties":{"file":{"type":"object","properties":{"id":{"type":"string"}}},"file_id":{"type":"string"},"type":{"type":"string","enum":["file_change"]}}},"summary":"A file was changed."},"fileCommentAdded":{"payload":{"type":"object","properties":{"comment":{},"file":{"type":"object","properties":{"id":{"type":"string"}}},"file_id":{"type":"string"},"type":{"type":"string","enum":["file_comment_added"]}}},"summary":"A file comment was added."},"fileCommentDeleted":{"payload":{"type":"object","properties":{"comment":{"type":"string"},"file":{"type":"object","properties":{"id":{"type":"string"}}},"file_id":{"type":"string"},"type":{"type":"string","enum":["file_comment_deleted"]}}},"summary":"A file comment was deleted."},"fileCommentEdited":{"payload":{"type":"object","properties":{"comment":{},"file":{"type":"object","properties":{"id":{"type":"string"}}},"file_id":{"type":"string"},"type":{"type":"string","enum":["file_comment_edited"]}}},"summary":"A file comment was edited."},"fileCreated":{"payload":{"type":"object","properties":{"file":{"type":"object","properties":{"id":{"type":"string"}}},"file_id":{"type":"string"},"type":{"type":"string","enum":["file_created"]}}},"summary":"A file was created."},"fileDeleted":{"payload":{"type":"object","properties":{"event_ts":{"type":"string"},"file_id":{"type":"string"},"type":{"type":"string","enum":["file_deleted"]}}},"summary":"A file was deleted."},"filePublic":{"payload":{"type":"object","properties":{"file":{"type":"object","properties":{"id":{"type":"string"}}},"file_id":{"type":"string"},"type":{"type":"string","enum":["file_public"]}}},"summary":"A file was made public."},"fileShared":{"payload":{"type":"object","properties":{"file":{"type":"object","properties":{"id":{"type":"string"}}},"file_id":{"type":"string"},"type":{"type":"string","enum":["file_shared"]}}},"summary":"A file was shared."},"fileUnshared":{"payload":{"type":"object","properties":{"file":{"type":"object","properties":{"id":{"type":"string"}}},"file_id":{"type":"string"},"type":{"type":"string","enum":["file_unshared"]}}},"summary":"A file was unshared."},"goodbye":{"payload":{"type":"object","properties":{"type":{"type":"string","enum":["goodbye"]}}},"summary":"The server intends to close the connection soon."},"groupArchive":{"payload":{"type":"object","properties":{"channel":{"type":"string"},"type":{"type":"string","enum":["group_archive"]}}},"summary":"A private channel was archived."},"groupClose":{"payload":{"type":"object","properties":{"channel":{"type":"string"},"type":{"type":"string","enum":["group_close"]},"user":{"type":"string"}}},"summary":"You closed a private channel."},"groupHistoryChanged":{"payload":{"type":"object","properties":{"event_ts":{"type":"string"},"latest":{"type":"string"},"ts":{"type":"string"},"type":{"type":"string","enum":["group_history_changed"]}}},"summary":"Bulk updates were made to a private channel's history."},"groupJoined":{"payload":{"type":"object","properties":{"channel":{"type":"object","properties":{"created":{"type":"number"},"creator":{"type":"string"},"id":{"type":"string"},"name":{"type":"string"}}},"type":{"type":"string","enum":["group_joined"]}}},"summary":"You joined a private channel."},"groupLeft":{"payload":{"type":"object","properties":{"channel":{"type":"string"},"type":{"type":"string","enum":["group_left"]}}},"summary":"You left a private channel."},"groupMarked":{"payload":{"type":"object","properties":{"channel":{"type":"string"},"ts":{"type":"string"},"type":{"type":"string","enum":["group_marked"]}}},"summary":"A private channel read marker was updated."},"groupOpen":{"payload":{"type":"object","properties":{"channel":{"type":"string"},"type":{"type":"string","enum":["group_open"]},"user":{"type":"string"}}},"summary":"You opened a private channel."},"groupRename":{"payload":{"type":"object","properties":{"channel":{"type":"object","properties":{"created":{"type":"number"},"id":{"type":"string"},"name":{"type":"string"}}},"type":{"type":"string","enum":["group_rename"]}}},"summary":"A private channel was renamed."},"groupUnarchive":{"payload":{"type":"object","properties":{"channel":{"type":"string"},"type":{"type":"string","enum":["group_unarchive"]},"user":{"type":"string"}}},"summary":"A private channel was unarchived."},"hello":{"payload":{"type":"object","properties":{"type":{"type":"string","enum":["hello"]}}},"summary":"First event received upon connection."},"imClose":{"payload":{"type":"object","properties":{"channel":{"type":"string"},"type":{"type":"string","enum":["im_close"]},"user":{"type":"string"}}},"summary":"You closed a DM."},"imCreated":{"payload":{"type":"object","properties":{"channel":{"type":"object","properties":{"created":{"type":"number"},"creator":{"type":"string"},"id":{"type":"string"},"name":{"type":"string"}}},"type":{"type":"string","enum":["im_created"]},"user":{"type":"string"}}},"summary":"A DM was created."},"imMarked":{"payload":{"type":"object","properties":{"channel":{"type":"string"},"ts":{"type":"string"},"type":{"type":"string","enum":["im_marked"]}}},"summary":"A direct message read marker was updated."},"imOpen":{"payload":{"type":"object","properties":{"channel":{"type":"string"},"type":{"type":"string","enum":["im_open"]},"user":{"type":"string"}}},"summary":"You opened a DM."},"manualPresenceChange":{"payload":{"type":"object","properties":{"presence":{"type":"string"},"type":{"type":"string","enum":["manual_presence_change"]}}},"summary":"You manually updated your presence."},"memberJoinedChannel":{"payload":{"type":"object","properties":{"channel":{"type":"string"},"channel_type":{"type":"string","enum":["C","G"]},"inviter":{"type":"string"},"team":{"type":"string"},"type":{"type":"string","enum":["member_joined_channel"]},"user":{"type":"string"}}},"summary":"A user joined a public or private channel."},"memberLeftChannel":{"payload":{"type":"object","properties":{"channel":{"type":"string"},"channel_type":{"type":"string","enum":["C","G"]},"team":{"type":"string"},"type":{"type":"string","enum":["member_left_channel"]},"user":{"type":"string"}}},"summary":"A user left a public or private channel."},"message":{"payload":{"type":"object","properties":{"attachments":{"type":"array","items":{"$ref":"#/components/schemas/attachment"}},"channel":{"type":"string"},"edited":{"type":"object","properties":{"ts":{"type":"string"},"user":{"type":"string"}}},"text":{"type":"string"},"ts":{"type":"string"},"type":{"type":"string","enum":["message"]},"user":{"type":"string"}}},"summary":"A message was sent to a channel."},"outgoingMessage":{"payload":{"type":"object","properties":{"channel":{"type":"string"},"id":{"type":"number"},"text":{"type":"string"},"type":{"type":"string","enum":["message"]}}},"summary":"A message was sent to a channel."}},"securitySchemes":{"token":{"type":"httpApiKey","name":"token","in":"query"}}}}
+ test/golden/examples/reference-examples-social-media-backend-asyncapi.yaml.json view
@@ -0,0 +1,1 @@+{"asyncapi":"3.1.0","info":{"title":"Website Backend","version":"1.0.0"},"servers":{"mosquitto":{"host":"test.mosquitto.org","protocol":"mqtt","tags":[{"name":"env:production","description":"This environment is meant for production use case"},{"name":"kind:remote","description":"This server is a remote server. Not exposed by the application"},{"name":"visibility:public","description":"This resource is public and available to everyone"}],"bindings":{"mqtt":{"clientId":"websocketServer"}}},"websiteWebSocketServer":{"$ref":"../common/servers.yaml#/websiteWebSocketServer"}},"channels":{"commentsCountChange":{"address":"comment/{commentId}/changed","messages":{"commentChanged":{"$ref":"../common/messages.yaml#/commentChanged"}},"description":"When an event from the broker arrives telling us to update the comment likes count on the frontend.","servers":[{"$ref":"#/servers/mosquitto"}],"parameters":{"commentId":{"$ref":"../common/parameters.yaml#/commentId"}}},"newLikeComment":{"address":"like/comment","messages":{"likeComment":{"$ref":"../common/messages.yaml#/likeComment"}},"description":"When a comment like is received from the frontend.","servers":[{"$ref":"#/servers/websiteWebSocketServer"}]},"notifyAllCommentLiked":{"address":"comment/liked","messages":{"commentLiked":{"$ref":"../common/messages.yaml#/commentLiked"}},"description":"Notify all the services that a comment has been liked.","servers":[{"$ref":"#/servers/mosquitto"}]},"updateCommentsCount":{"address":"update/comment/likes","messages":{"updateCommentLikes":{"$ref":"../common/messages.yaml#/updateCommentLikes"}},"description":"Update comment likes count in the frontend.","servers":[{"$ref":"#/servers/websiteWebSocketServer"}]}},"operations":{"receiveCommentChange":{"action":"receive","channel":{"$ref":"#/channels/commentsCountChange"},"messages":[{"$ref":"#/channels/commentsCountChange/messages/commentChanged"}]},"receiveCommentLike":{"action":"receive","channel":{"$ref":"#/channels/newLikeComment"},"messages":[{"$ref":"#/channels/newLikeComment/messages/likeComment"}]},"sendCommentLikeUpdate":{"action":"send","channel":{"$ref":"#/channels/updateCommentsCount"},"messages":[{"$ref":"#/channels/updateCommentsCount/messages/updateCommentLikes"}]},"sendCommentLiked":{"action":"send","channel":{"$ref":"#/channels/notifyAllCommentLiked"},"messages":[{"$ref":"#/channels/notifyAllCommentLiked/messages/commentLiked"}]}}}
+ test/golden/examples/reference-examples-social-media-comments-service-asyncapi.yaml.json view
@@ -0,0 +1,1 @@+{"asyncapi":"3.1.0","info":{"title":"Comments Service","version":"1.0.0","description":"This service is in charge of processing all the events related to comments."},"servers":{"mosquitto":{"host":"test.mosquitto.org","protocol":"mqtt","tags":[{"name":"env:production","description":"This environment is meant for production use case"},{"name":"kind:remote","description":"This server is a remote server. Not exposed by the application"},{"name":"visibility:public","description":"This resource is public and available to everyone"}],"bindings":{"mqtt":{"clientId":"comment-service"}}}},"channels":{"commentCountChange":{"address":"comment/{commentId}/changed","messages":{"commentChanged":{"$ref":"../common/messages.yaml#/commentChanged"}},"description":"Sends the new count to the broker after it has been updated in the database.","parameters":{"commentId":{"$ref":"../common/parameters.yaml#/commentId"}}},"commentLiked":{"address":"comment/liked","messages":{"commentLiked":{"$ref":"../common/messages.yaml#/commentLiked"}},"description":"Updates the likes count in the database and sends the new count to the broker."}},"operations":{"receiveCommentLiked":{"action":"receive","channel":{"$ref":"#/channels/commentLiked"},"messages":[{"$ref":"#/channels/commentLiked/messages/commentLiked"}]},"sendCommentChange":{"action":"send","channel":{"$ref":"#/channels/commentCountChange"},"messages":[{"$ref":"#/channels/commentCountChange/messages/commentChanged"}]}}}
+ test/golden/examples/reference-examples-social-media-frontend-asyncapi.yaml.json view
@@ -0,0 +1,1 @@+{"asyncapi":"3.1.0","info":{"title":"Website WebSocket Client","version":"1.0.0"},"servers":{"websiteWebSocketServer":{"$ref":"../common/servers.yaml#/websiteWebSocketServer"}},"channels":{"likeComment":{"address":"like/comment","messages":{"likeComment":{"$ref":"../common/messages.yaml#/likeComment"}},"description":"Notify the backend that a comment has been liked."},"updateCommentLike":{"address":"update/comment/likes","messages":{"updateCommentLikes":{"$ref":"../common/messages.yaml#/updateCommentLikes"}},"description":"Update the UI when the comment likes count is updated."}},"operations":{"receiveUpdateCommentLiked":{"action":"receive","channel":{"$ref":"#/channels/updateCommentLike"},"messages":[{"$ref":"#/channels/updateCommentLike/messages/updateCommentLikes"}]},"sendLikeComment":{"action":"send","channel":{"$ref":"#/channels/likeComment"},"messages":[{"$ref":"#/channels/likeComment/messages/likeComment"}]}}}
+ test/golden/examples/reference-examples-social-media-notification-service-asyncapi.yaml.json view
@@ -0,0 +1,1 @@+{"asyncapi":"3.1.0","info":{"title":"Notifications Service","version":"1.0.0"},"servers":{"mosquitto":{"host":"test.mosquitto.org","protocol":"mqtt","tags":[{"name":"env:production","description":"This environment is meant for production use case"},{"name":"kind:remote","description":"This server is a remote server. Not exposed by the application"},{"name":"visibility:public","description":"This resource is public and available to everyone"}],"bindings":{"mqtt":{"clientId":"notification-service"}}}},"channels":{"commentLiked":{"address":"comment/liked","messages":{"commentLiked":{"$ref":"../common/messages.yaml#/commentLiked"}},"description":"When a \"comment has been liked\" message is received, it sends an SMS or push notification to the author."}},"operations":{"receiveCommentLiked":{"action":"receive","channel":{"$ref":"#/channels/commentLiked"},"messages":[{"$ref":"#/channels/commentLiked/messages/commentLiked"}]}}}
+ test/golden/examples/reference-examples-social-media-public-api-asyncapi.yaml.json view
@@ -0,0 +1,1 @@+{"asyncapi":"3.1.0","info":{"title":"Public API","version":"1.0.0","description":"Public API for others to interact with the system"},"servers":{"mosquitto":{"host":"test.mosquitto.org","protocol":"mqtt","tags":[{"name":"env:production","description":"This environment is meant for production use case"},{"name":"kind:remote","description":"This server is a remote server. Not exposed by the application"},{"name":"visibility:public","description":"This resource is public and available to everyone"}],"bindings":{"mqtt":{"clientId":"public-api"}}}},"channels":{"commentLiked":{"address":"comment/liked","messages":{"commentLiked":{"$ref":"../common/messages.yaml#/commentLiked"}},"description":"Others are publishing to you, whenever a comment is liked, for you to do react to such an event."}},"operations":{"receiveCommentLiked":{"action":"receive","channel":{"$ref":"#/channels/commentLiked"},"messages":[{"$ref":"#/channels/commentLiked/messages/commentLiked"}]}}}
+ test/golden/examples/reference-examples-streetlights-kafka-asyncapi.yml.json view
@@ -0,0 +1,1 @@+{"asyncapi":"3.1.0","info":{"title":"Streetlights Kafka API","version":"1.0.0","description":"The Smartylighting Streetlights API allows you to remotely manage the city lights.\n\n### Check out its awesome features:\n\n* Turn a specific streetlight on/off 🌃\n* Dim a specific streetlight 😎\n* Receive real-time information about environmental lighting conditions 📈\n","license":{"name":"Apache 2.0","url":"https://www.apache.org/licenses/LICENSE-2.0"}},"servers":{"mtls-connections":{"host":"test.mykafkacluster.org:28092","protocol":"kafka-secure","description":"Test broker secured with X509","security":[{"$ref":"#/components/securitySchemes/certs"}],"tags":[{"name":"env:test-mtls","description":"This environment is meant for running internal tests through mtls"},{"name":"kind:remote","description":"This server is a remote server. Not exposed by the application"},{"name":"visibility:private","description":"This resource is private and only available to certain users"}]},"scram-connections":{"host":"test.mykafkacluster.org:18092","protocol":"kafka-secure","description":"Test broker secured with scramSha256","security":[{"$ref":"#/components/securitySchemes/saslScram"}],"tags":[{"name":"env:test-scram","description":"This environment is meant for running internal tests through scramSha256"},{"name":"kind:remote","description":"This server is a remote server. Not exposed by the application"},{"name":"visibility:private","description":"This resource is private and only available to certain users"}]}},"defaultContentType":"application/json","channels":{"lightTurnOff":{"address":"smartylighting.streetlights.1.0.action.{streetlightId}.turn.off","messages":{"turnOff":{"$ref":"#/components/messages/turnOnOff"}},"parameters":{"streetlightId":{"$ref":"#/components/parameters/streetlightId"}}},"lightTurnOn":{"address":"smartylighting.streetlights.1.0.action.{streetlightId}.turn.on","messages":{"turnOn":{"$ref":"#/components/messages/turnOnOff"}},"parameters":{"streetlightId":{"$ref":"#/components/parameters/streetlightId"}}},"lightingMeasured":{"address":"smartylighting.streetlights.1.0.event.{streetlightId}.lighting.measured","messages":{"lightMeasured":{"$ref":"#/components/messages/lightMeasured"}},"description":"The topic on which measured values may be produced and consumed.","parameters":{"streetlightId":{"$ref":"#/components/parameters/streetlightId"}}},"lightsDim":{"address":"smartylighting.streetlights.1.0.action.{streetlightId}.dim","messages":{"dimLight":{"$ref":"#/components/messages/dimLight"}},"parameters":{"streetlightId":{"$ref":"#/components/parameters/streetlightId"}}}},"operations":{"dimLight":{"action":"send","channel":{"$ref":"#/channels/lightsDim"},"traits":[{"$ref":"#/components/operationTraits/kafka"}],"messages":[{"$ref":"#/channels/lightsDim/messages/dimLight"}]},"receiveLightMeasurement":{"action":"receive","channel":{"$ref":"#/channels/lightingMeasured"},"summary":"Inform about environmental lighting conditions of a particular streetlight.","traits":[{"$ref":"#/components/operationTraits/kafka"}],"messages":[{"$ref":"#/channels/lightingMeasured/messages/lightMeasured"}]},"turnOff":{"action":"send","channel":{"$ref":"#/channels/lightTurnOff"},"traits":[{"$ref":"#/components/operationTraits/kafka"}],"messages":[{"$ref":"#/channels/lightTurnOff/messages/turnOff"}]},"turnOn":{"action":"send","channel":{"$ref":"#/channels/lightTurnOn"},"traits":[{"$ref":"#/components/operationTraits/kafka"}],"messages":[{"$ref":"#/channels/lightTurnOn/messages/turnOn"}]}},"components":{"schemas":{"dimLightPayload":{"type":"object","properties":{"percentage":{"type":"integer","maximum":100,"minimum":0,"description":"Percentage to which the light should be dimmed to."},"sentAt":{"$ref":"#/components/schemas/sentAt"}}},"lightMeasuredPayload":{"type":"object","properties":{"lumens":{"type":"integer","minimum":0,"description":"Light intensity measured in lumens."},"sentAt":{"$ref":"#/components/schemas/sentAt"}}},"sentAt":{"type":"string","description":"Date and time when the message was sent.","format":"date-time"},"turnOnOffPayload":{"type":"object","properties":{"command":{"type":"string","enum":["on","off"],"description":"Whether to turn on or off the light."},"sentAt":{"$ref":"#/components/schemas/sentAt"}}}},"messages":{"dimLight":{"payload":{"$ref":"#/components/schemas/dimLightPayload"},"name":"dimLight","title":"Dim light","summary":"Command a particular streetlight to dim the lights.","traits":[{"$ref":"#/components/messageTraits/commonHeaders"}]},"lightMeasured":{"payload":{"$ref":"#/components/schemas/lightMeasuredPayload"},"contentType":"application/json","name":"lightMeasured","title":"Light measured","summary":"Inform about environmental lighting conditions of a particular streetlight.","traits":[{"$ref":"#/components/messageTraits/commonHeaders"}]},"turnOnOff":{"payload":{"$ref":"#/components/schemas/turnOnOffPayload"},"name":"turnOnOff","title":"Turn on/off","summary":"Command a particular streetlight to turn the lights on or off.","traits":[{"$ref":"#/components/messageTraits/commonHeaders"}]}},"securitySchemes":{"certs":{"type":"X509","description":"Download the certificate files from service provider"},"saslScram":{"type":"scramSha256","description":"Provide your username and password for SASL/SCRAM authentication"}},"parameters":{"streetlightId":{"description":"The ID of the streetlight."}},"operationTraits":{"kafka":{"bindings":{"kafka":{"clientId":{"enum":["my-app-id"],"type":"string"}}}}},"messageTraits":{"commonHeaders":{"headers":{"type":"object","properties":{"my-app-header":{"type":"integer","maximum":100,"minimum":0}}}}}}}
+ test/golden/examples/reference-examples-streetlights-mqtt-asyncapi.yml.json view
@@ -0,0 +1,1 @@+{"asyncapi":"3.1.0","info":{"title":"Streetlights MQTT API","version":"1.0.0","description":"The Smartylighting Streetlights API allows you to remotely manage the city lights.\n\n### Check out its awesome features:\n\n* Turn a specific streetlight on/off 🌃\n* Dim a specific streetlight 😎\n* Receive real-time information about environmental lighting conditions 📈\n","license":{"name":"Apache 2.0","url":"https://www.apache.org/licenses/LICENSE-2.0"}},"servers":{"production":{"host":"test.mosquitto.org:{port}","protocol":"mqtt","description":"Test broker","variables":{"port":{"enum":["1883","8883"],"default":"1883","description":"Secure connection (TLS) is available through port 8883."}},"security":[{"$ref":"#/components/securitySchemes/apiKey"},{"type":"oauth2","description":"Flows to support OAuth 2.0","flows":{"implicit":{"authorizationUrl":"https://authserver.example/auth","availableScopes":{"streetlights:dim":"Ability to dim the lights","streetlights:off":"Ability to switch lights off","streetlights:on":"Ability to switch lights on"}},"password":{"tokenUrl":"https://authserver.example/token","availableScopes":{"streetlights:dim":"Ability to dim the lights","streetlights:off":"Ability to switch lights off","streetlights:on":"Ability to switch lights on"}},"clientCredentials":{"tokenUrl":"https://authserver.example/token","availableScopes":{"streetlights:dim":"Ability to dim the lights","streetlights:off":"Ability to switch lights off","streetlights:on":"Ability to switch lights on"}},"authorizationCode":{"authorizationUrl":"https://authserver.example/auth","tokenUrl":"https://authserver.example/token","refreshUrl":"https://authserver.example/refresh","availableScopes":{"streetlights:dim":"Ability to dim the lights","streetlights:off":"Ability to switch lights off","streetlights:on":"Ability to switch lights on"}}},"scopes":["streetlights:on","streetlights:off","streetlights:dim"]},{"$ref":"#/components/securitySchemes/openIdConnectWellKnown"}],"tags":[{"name":"env:production","description":"This environment is meant for production use case"},{"name":"kind:remote","description":"This server is a remote server. Not exposed by the application"},{"name":"visibility:public","description":"This resource is public and available to everyone"}]}},"defaultContentType":"application/json","channels":{"lightTurnOff":{"address":"smartylighting/streetlights/1/0/action/{streetlightId}/turn/off","messages":{"turnOff":{"$ref":"#/components/messages/turnOnOff"}},"parameters":{"streetlightId":{"$ref":"#/components/parameters/streetlightId"}}},"lightTurnOn":{"address":"smartylighting/streetlights/1/0/action/{streetlightId}/turn/on","messages":{"turnOn":{"$ref":"#/components/messages/turnOnOff"}},"parameters":{"streetlightId":{"$ref":"#/components/parameters/streetlightId"}}},"lightingMeasured":{"address":"smartylighting/streetlights/1/0/event/{streetlightId}/lighting/measured","messages":{"lightMeasured":{"$ref":"#/components/messages/lightMeasured"}},"description":"The topic on which measured values may be produced and consumed.","parameters":{"streetlightId":{"$ref":"#/components/parameters/streetlightId"}}},"lightsDim":{"address":"smartylighting/streetlights/1/0/action/{streetlightId}/dim","messages":{"dimLight":{"$ref":"#/components/messages/dimLight"}},"parameters":{"streetlightId":{"$ref":"#/components/parameters/streetlightId"}}}},"operations":{"dimLight":{"action":"send","channel":{"$ref":"#/channels/lightsDim"},"traits":[{"$ref":"#/components/operationTraits/mqtt"}],"messages":[{"$ref":"#/channels/lightsDim/messages/dimLight"}]},"receiveLightMeasurement":{"action":"receive","channel":{"$ref":"#/channels/lightingMeasured"},"summary":"Inform about environmental lighting conditions of a particular streetlight.","traits":[{"$ref":"#/components/operationTraits/mqtt"}],"messages":[{"$ref":"#/channels/lightingMeasured/messages/lightMeasured"}]},"turnOff":{"action":"send","channel":{"$ref":"#/channels/lightTurnOff"},"traits":[{"$ref":"#/components/operationTraits/mqtt"}],"messages":[{"$ref":"#/channels/lightTurnOff/messages/turnOff"}]},"turnOn":{"action":"send","channel":{"$ref":"#/channels/lightTurnOn"},"traits":[{"$ref":"#/components/operationTraits/mqtt"}],"messages":[{"$ref":"#/channels/lightTurnOn/messages/turnOn"}]}},"components":{"schemas":{"dimLightPayload":{"type":"object","properties":{"percentage":{"type":"integer","maximum":100,"minimum":0,"description":"Percentage to which the light should be dimmed to."},"sentAt":{"$ref":"#/components/schemas/sentAt"}}},"lightMeasuredPayload":{"type":"object","properties":{"lumens":{"type":"integer","minimum":0,"description":"Light intensity measured in lumens."},"sentAt":{"$ref":"#/components/schemas/sentAt"}}},"sentAt":{"type":"string","description":"Date and time when the message was sent.","format":"date-time"},"turnOnOffPayload":{"type":"object","properties":{"command":{"type":"string","enum":["on","off"],"description":"Whether to turn on or off the light."},"sentAt":{"$ref":"#/components/schemas/sentAt"}}}},"messages":{"dimLight":{"payload":{"$ref":"#/components/schemas/dimLightPayload"},"name":"dimLight","title":"Dim light","summary":"Command a particular streetlight to dim the lights.","traits":[{"$ref":"#/components/messageTraits/commonHeaders"}]},"lightMeasured":{"payload":{"$ref":"#/components/schemas/lightMeasuredPayload"},"contentType":"application/json","name":"lightMeasured","title":"Light measured","summary":"Inform about environmental lighting conditions of a particular streetlight.","traits":[{"$ref":"#/components/messageTraits/commonHeaders"}]},"turnOnOff":{"payload":{"$ref":"#/components/schemas/turnOnOffPayload"},"name":"turnOnOff","title":"Turn on/off","summary":"Command a particular streetlight to turn the lights on or off.","traits":[{"$ref":"#/components/messageTraits/commonHeaders"}]}},"securitySchemes":{"apiKey":{"type":"apiKey","description":"Provide your API key as the user and leave the password empty.","in":"user"},"openIdConnectWellKnown":{"type":"openIdConnect","openIdConnectUrl":"https://authserver.example/.well-known"},"supportedOauthFlows":{"type":"oauth2","description":"Flows to support OAuth 2.0","flows":{"implicit":{"authorizationUrl":"https://authserver.example/auth","availableScopes":{"streetlights:dim":"Ability to dim the lights","streetlights:off":"Ability to switch lights off","streetlights:on":"Ability to switch lights on"}},"password":{"tokenUrl":"https://authserver.example/token","availableScopes":{"streetlights:dim":"Ability to dim the lights","streetlights:off":"Ability to switch lights off","streetlights:on":"Ability to switch lights on"}},"clientCredentials":{"tokenUrl":"https://authserver.example/token","availableScopes":{"streetlights:dim":"Ability to dim the lights","streetlights:off":"Ability to switch lights off","streetlights:on":"Ability to switch lights on"}},"authorizationCode":{"authorizationUrl":"https://authserver.example/auth","tokenUrl":"https://authserver.example/token","refreshUrl":"https://authserver.example/refresh","availableScopes":{"streetlights:dim":"Ability to dim the lights","streetlights:off":"Ability to switch lights off","streetlights:on":"Ability to switch lights on"}}}}},"parameters":{"streetlightId":{"description":"The ID of the streetlight."}},"operationTraits":{"mqtt":{"bindings":{"mqtt":{"qos":1}}}},"messageTraits":{"commonHeaders":{"headers":{"type":"object","properties":{"my-app-header":{"type":"integer","maximum":100,"minimum":0}}}}}}}
+ test/golden/examples/reference-examples-streetlights-operation-security-asyncapi.yml.json view
@@ -0,0 +1,1 @@+{"asyncapi":"3.1.0","info":{"title":"Streetlights Kafka API","version":"1.0.0","description":"The Smartylighting Streetlights API allows you to remotely manage the city lights.\n\n### Check out its awesome features:\n\n* Turn a specific streetlight on/off 🌃\n* Dim a specific streetlight 😎\n* Receive real-time information about environmental lighting conditions 📈\n","license":{"name":"Apache 2.0","url":"https://www.apache.org/licenses/LICENSE-2.0"}},"servers":{"test":{"host":"test.mykafkacluster.org:8092","protocol":"kafka-secure","description":"Test broker","security":[{"$ref":"#/components/securitySchemes/saslScram"}]},"test_oauth":{"host":"test.mykafkacluster.org:8093","protocol":"kafka-secure","description":"Test port for oauth","security":[{"type":"oauth2","description":"The oauth security descriptions","flows":{"clientCredentials":{"tokenUrl":"https://example.com/api/oauth/dialog","availableScopes":{"streetlights:read":"Scope required for subscribing to channel","streetlights:write":"Scope required for publishing to channel"}}},"scopes":["streetlights:write","streetlights:read"]}]}},"defaultContentType":"application/json","channels":{"lightTurnOff":{"address":"smartylighting.streetlights.1.0.action.{streetlightId}.turn.off","messages":{"turnOff":{"$ref":"#/components/messages/turnOnOff"}},"servers":[{"$ref":"#/servers/test_oauth"}],"parameters":{"streetlightId":{"$ref":"#/components/parameters/streetlightId"}}},"lightTurnOn":{"address":"smartylighting.streetlights.1.0.action.{streetlightId}.turn.on","messages":{"turnOn":{"$ref":"#/components/messages/turnOnOff"}},"servers":[{"$ref":"#/servers/test_oauth"}],"parameters":{"streetlightId":{"$ref":"#/components/parameters/streetlightId"}}},"lightingMeasured":{"address":"smartylighting.streetlights.1.0.event.{streetlightId}.lighting.measured","messages":{"lightMeasured":{"$ref":"#/components/messages/lightMeasured"}},"description":"The topic on which measured values may be produced and consumed.","servers":[{"$ref":"#/servers/test"}],"parameters":{"streetlightId":{"$ref":"#/components/parameters/streetlightId"}}},"lightsDim":{"address":"smartylighting.streetlights.1.0.action.{streetlightId}.dim","messages":{"dimLight":{"$ref":"#/components/messages/dimLight"}},"servers":[{"$ref":"#/servers/test_oauth"}],"parameters":{"streetlightId":{"$ref":"#/components/parameters/streetlightId"}}}},"operations":{"dimLight":{"action":"send","channel":{"$ref":"#/channels/lightsDim"},"security":[{"type":"oauth2","description":"The oauth security descriptions","flows":{"clientCredentials":{"tokenUrl":"https://example.com/api/oauth/dialog","availableScopes":{"streetlights:read":"Scope required for subscribing to channel","streetlights:write":"Scope required for publishing to channel"}}},"scopes":["streetlights:read"]}],"traits":[{"$ref":"#/components/operationTraits/kafka"}],"messages":[{"$ref":"#/channels/lightsDim/messages/dimLight"}]},"receiveLightMeasurement":{"action":"receive","channel":{"$ref":"#/channels/lightingMeasured"},"summary":"Inform about environmental lighting conditions of a particular streetlight.","traits":[{"$ref":"#/components/operationTraits/kafka"}],"messages":[{"$ref":"#/channels/lightingMeasured/messages/lightMeasured"}]},"turnOff":{"action":"send","channel":{"$ref":"#/channels/lightTurnOff"},"security":[{"type":"oauth2","description":"The oauth security descriptions","flows":{"clientCredentials":{"tokenUrl":"https://example.com/api/oauth/dialog","availableScopes":{"streetlights:read":"Scope required for subscribing to channel","streetlights:write":"Scope required for publishing to channel"}}},"scopes":["streetlights:read"]}],"traits":[{"$ref":"#/components/operationTraits/kafka"}],"messages":[{"$ref":"#/channels/lightTurnOff/messages/turnOff"}]},"turnOn":{"action":"send","channel":{"$ref":"#/channels/lightTurnOn"},"security":[{"type":"oauth2","description":"The oauth security descriptions","flows":{"clientCredentials":{"tokenUrl":"https://example.com/api/oauth/dialog","availableScopes":{"streetlights:read":"Scope required for subscribing to channel","streetlights:write":"Scope required for publishing to channel"}}},"scopes":["streetlights:read"]}],"traits":[{"$ref":"#/components/operationTraits/kafka"}],"messages":[{"$ref":"#/channels/lightTurnOn/messages/turnOn"}]}},"components":{"schemas":{"dimLightPayload":{"type":"object","properties":{"percentage":{"type":"integer","maximum":100,"minimum":0,"description":"Percentage to which the light should be dimmed to."},"sentAt":{"$ref":"#/components/schemas/sentAt"}}},"lightMeasuredPayload":{"type":"object","properties":{"lumens":{"type":"integer","minimum":0,"description":"Light intensity measured in lumens."},"sentAt":{"$ref":"#/components/schemas/sentAt"}}},"sentAt":{"type":"string","description":"Date and time when the message was sent.","format":"date-time"},"turnOnOffPayload":{"type":"object","properties":{"command":{"type":"string","enum":["on","off"],"description":"Whether to turn on or off the light."},"sentAt":{"$ref":"#/components/schemas/sentAt"}}}},"messages":{"dimLight":{"payload":{"$ref":"#/components/schemas/dimLightPayload"},"name":"dimLight","title":"Dim light","summary":"Command a particular streetlight to dim the lights.","traits":[{"$ref":"#/components/messageTraits/commonHeaders"}]},"lightMeasured":{"payload":{"$ref":"#/components/schemas/lightMeasuredPayload"},"contentType":"application/json","name":"lightMeasured","title":"Light measured","summary":"Inform about environmental lighting conditions of a particular streetlight.","traits":[{"$ref":"#/components/messageTraits/commonHeaders"}]},"turnOnOff":{"payload":{"$ref":"#/components/schemas/turnOnOffPayload"},"name":"turnOnOff","title":"Turn on/off","summary":"Command a particular streetlight to turn the lights on or off.","traits":[{"$ref":"#/components/messageTraits/commonHeaders"}]}},"securitySchemes":{"saslScram":{"type":"scramSha256","description":"Provide your username and password for SASL/SCRAM authentication"},"streetlights_auth":{"type":"oauth2","description":"The oauth security descriptions","flows":{"clientCredentials":{"tokenUrl":"https://example.com/api/oauth/dialog","availableScopes":{"streetlights:read":"Scope required for subscribing to channel","streetlights:write":"Scope required for publishing to channel"}}}}},"parameters":{"streetlightId":{"description":"The ID of the streetlight."}},"operationTraits":{"kafka":{"bindings":{"kafka":{"clientId":{"enum":["my-app-id"],"type":"string"}}}}},"messageTraits":{"commonHeaders":{"headers":{"type":"object","properties":{"my-app-header":{"type":"integer","maximum":100,"minimum":0}}}}}}}
+ test/golden/examples/reference-examples-websocket-gemini-asyncapi.yml.json view
@@ -0,0 +1,1 @@+{"asyncapi":"3.1.0","info":{"title":"Gemini Market Data Websocket API","version":"1.0.0","description":"Market data is a public API that streams all the market data on a given symbol.\n\nYou can quickly play with the API using [websocat](https://github.com/vi/websocat#installation) like this:\n```bash\nwebsocat wss://api.gemini.com/v1/marketdata/btcusd?heartbeat=true -S\n```\n","contact":{"name":"Gemini","url":"https://www.gemini.com/"},"externalDocs":{"url":"https://docs.sandbox.gemini.com/websocket-api/#market-data"}},"servers":{"public":{"host":"api.gemini.com","protocol":"wss"}},"channels":{"marketDataV1":{"address":"/v1/marketdata/{symbol}","messages":{"marketData":{"$ref":"#/components/messages/marketData"}},"parameters":{"symbol":{"enum":["btcusd","ethbtc","ethusd","zecusd","zecbtc","zeceth","zecbch","zecltc","bchusd","bchbtc","bcheth","ltcusd","ltcbtc","ltceth","ltcbch","batusd","daiusd","linkusd","oxtusd","batbtc","linkbtc","oxtbtc","bateth","linketh","oxteth","ampusd","compusd","paxgusd","mkrusd","zrxusd","kncusd","manausd","storjusd","snxusd","crvusd","balusd","uniusd","renusd","umausd","yfiusd","btcdai","ethdai","aaveusd","filusd","btceur","btcgbp","etheur","ethgbp","btcsgd","ethsgd","sklusd","grtusd","bntusd","1inchusd","enjusd","lrcusd","sandusd","cubeusd","lptusd","bondusd","maticusd","injusd","sushiusd"],"description":"Symbols are formatted as CCY1CCY2 where prices are in CCY2 and quantities are in CCY1. To read more click [here](https://docs.sandbox.gemini.com/websocket-api/#symbols-and-minimums).\n"}},"bindings":{"ws":{"bindingVersion":"0.1.0","query":{"description":"The semantics of entry type filtering is:\n\nIf any entry type is specified as true or false, all of them must be explicitly flagged true to show up in the response\nIf no entry types filtering parameters are included in the url, then all entry types will appear in the response\n\nNOTE: top_of_book has no meaning and initial book events are empty when only trades is specified\n","properties":{"auctions":{"default":true,"description":"Include auction events","type":"boolean"},"bids":{"default":true,"description":"Include bids in change events","type":"boolean"},"heartbeat":{"default":false,"description":"Optionally add this parameter and set to true to receive a heartbeat every 5 seconds","type":"boolean"},"offers":{"default":true,"description":"Include asks in change events","type":"boolean"},"top_of_book":{"default":false,"description":"If absent or false, receive full order book depth; if present and true, receive top of book only. Only applies to bids and offers.","type":"boolean"},"trades":{"default":true,"description":"Include trade events","type":"boolean"}},"type":"object"}}}}},"operations":{"sendMarketData":{"action":"send","channel":{"$ref":"#/channels/marketDataV1"},"summary":"Receive market updates on a given symbol","messages":[{"$ref":"#/channels/marketDataV1/messages/marketData"}]}},"components":{"schemas":{"default":{"type":"object","required":["type","socket_sequence"],"properties":{"socket_sequence":{"type":"integer","description":"zero-indexed monotonic increasing sequence number attached to each message sent - if there is a gap in this sequence, you have missed a message. If you choose to enable heartbeats, then heartbeat and update messages will share a single increasing sequence. See [Sequence Numbers](https://docs.sandbox.gemini.com/websocket-api/#sequence-numbers) for more information."}},"description":"This object is always part of the payload. In case of type=heartbeat, these are the only fields."},"events":{"type":"array","items":{"type":"object","properties":{"delta":{"type":"number","description":"The quantity changed. May be negative, if an order is filled or canceled. For initial messages, delta will equal remaining."},"price":{"type":"number","multipleOf":1.0e-2,"description":"The price of this order book entry."},"reason":{"type":"string","enum":["place","trade","cancel","initial"],"description":"Indicates why the change has occurred. initial is for the initial response message, which will show the entire existing state of the order book."},"remaining":{"type":"number","description":"The quantity remaining at that price level after this change occurred. May be zero if all orders at this price level have been filled or canceled."},"side":{"type":"string","enum":["bid","side"]},"type":{"type":"string","enum":["trade","change","auction, block_trade"]}},"additionalProperties":false},"description":"Either a change to the order book, or the indication that a trade has occurred."},"heartbeat":{"allOf":[{"required":["type"],"properties":{"type":{"type":"string","const":"heartbeat"}}},{"$ref":"#/components/schemas/default"}]},"market":{"type":"object","oneOf":[{"$ref":"#/components/schemas/heartbeat"},{"$ref":"#/components/schemas/update"}]},"update":{"allOf":[{"required":["type","eventId","events","timestamp","timestampms"],"properties":{"eventId":{"type":"integer","description":"A monotonically increasing sequence number indicating when this change occurred. These numbers are persistent and consistent between market data connections."},"events":{"$ref":"#/components/schemas/events"},"timestamp":{"type":"number","description":"The timestamp in seconds for this group of events (included for compatibility reasons). We recommend using the timestampms field instead."},"timestampms":{"type":"number","description":"The timestamp in milliseconds for this group of events."},"type":{"type":"string","const":"update"}}},{"$ref":"#/components/schemas/default"}]}},"messages":{"marketData":{"payload":{"$ref":"#/components/schemas/market"},"summary":"Message with marked data information.","description":"The initial response message will show the existing state of the order book. Subsequent messages will show all executed trades, as well as all other changes to the order book from orders placed or canceled.\n","examples":[{"payload":{"eventId":36902233362,"events":[{"delta":2.0e-3,"price":54350.4,"reason":"place","remaining":2.0e-3,"side":"bid","type":"change"}],"socket_sequence":661,"timestamp":1619769673,"timestampms":1619769673527,"type":"update"},"name":"updateMessage","summary":"Example of an update message that contains a change in price information."},{"payload":{"socket_sequence":1656,"type":"heartbeat"},"name":"heartbeatMessage","summary":"Example of additional heartbeat message when you enable them."}]}}}}
+ test/golden/spec-examples/1-info-object-json.json view
@@ -0,0 +1,1 @@+{"title":"AsyncAPI Sample App","version":"1.0.1","description":"This is a sample app.","termsOfService":"https://asyncapi.org/terms/","contact":{"name":"API Support","url":"https://www.asyncapi.org/support","email":"support@asyncapi.org"},"license":{"name":"Apache 2.0","url":"https://www.apache.org/licenses/LICENSE-2.0.html"},"tags":[{"name":"e-commerce"}],"externalDocs":{"description":"Find more info here","url":"https://www.asyncapi.org"}}
+ test/golden/spec-examples/10-server-object-yaml.json view
@@ -0,0 +1,1 @@+{"host":"kafka.in.mycompany.com:9092","protocol":"kafka","protocolVersion":"3.2","description":"Production Kafka broker."}
+ test/golden/spec-examples/11-server-object-with-pathname-json.json view
@@ -0,0 +1,1 @@+{"host":"rabbitmq.in.mycompany.com:5672","protocol":"amqp","pathname":"/production","description":"Production RabbitMQ broker (uses the `production` vhost)."}
+ test/golden/spec-examples/12-server-object-with-pathname-yaml.json view
@@ -0,0 +1,1 @@+{"host":"rabbitmq.in.mycompany.com:5672","protocol":"amqp","pathname":"/production","description":"Production RabbitMQ broker (uses the `production` vhost)."}
+ test/golden/spec-examples/13-server-object-with-variable-object-json.json view
@@ -0,0 +1,1 @@+{"host":"rabbitmq.in.mycompany.com:5672","protocol":"amqp","pathname":"/{env}","description":"RabbitMQ broker. Use the `env` variable to point to either `production` or `staging`.","variables":{"env":{"enum":["production","staging"],"description":"Environment to connect to. It can be either `production` or `staging`."}}}
+ test/golden/spec-examples/14-server-object-with-variable-object-yaml.json view
@@ -0,0 +1,1 @@+{"host":"rabbitmq.in.mycompany.com:5672","protocol":"amqp","pathname":"/{env}","description":"RabbitMQ broker. Use the `env` variable to point to either `production` or `staging`.","variables":{"env":{"enum":["production","staging"],"description":"Environment to connect to. It can be either `production` or `staging`."}}}
+ test/golden/spec-examples/15-default-content-type-at-root-doc-json.json view
@@ -0,0 +1,1 @@+{"asyncapi":"3.1.0","info":{"title":"AsyncAPI","version":"1.x.x","description":"This is a very good base doc, probably.","termsOfService":"https://asyncapi.org/terms/","license":{"name":"Apache 2.0","url":"https://www.apache.org/licenses/LICENSE-2.0.html"},"tags":[{"name":"e-commerce"}],"externalDocs":{"description":"Find more info here","url":"https://www.asyncapi.org"}},"servers":{"production":{"host":"rabbitmq.in.mycompany.com:5672","protocol":"amqp","protocolVersion":"1.0","pathname":"/v1","description":"Production RabbitMQ broker (uses the `production` vhost).","title":"Production Server","summary":"Production environment server","security":[{"type":"http","scheme":"bearer"}],"tags":[{"name":"production","description":"Production environment"}],"externalDocs":{"description":"Additional documentation for the production server","url":"https://example.com/docs/production"},"bindings":{"amqp":{"exchange":"my-exchange","queue":"my-queue"}}},"rabbitmqInProd":{"host":"{prod}.in.mycompany.com","protocol":"amqp","description":"Production server"},"rabbitmqInStaging":{"host":"{stage}.in.mycompany.com","protocol":"amqp","description":"Staging server"},"staging":{"host":"rabbitmq.in.mycompany.com:5672","protocol":"amqp","protocolVersion":"1.0","pathname":"/v1","description":"Staging RabbitMQ broker (uses the `staging` vhost).","title":"Staging Server","summary":"Staging environment server","security":[{"type":"apiKey","description":"Provide your API key as the user and leave the password empty.","in":"user"}],"tags":[{"name":"staging","description":"Staging environment"}],"externalDocs":{"description":"Additional documentation for the staging server","url":"https://example.com/docs/staging"},"bindings":{"amqp":{"exchange":"my-exchange","queue":"my-queue"}}}},"defaultContentType":"application/json","channels":{"user":{"address":"users.{userId}","messages":{"userCompletedOrder":{"$ref":"#/components/messages/userCompletedOrder"},"userSignedUp":{"$ref":"#/components/messages/userSignedUp"}},"title":"Users channel","description":"This channel is used to exchange messages about user events.","servers":[{"$ref":"#/servers/production"}],"parameters":{"userId":{"$ref":"#/components/parameters/userId"}},"tags":[{"name":"user","description":"User-related messages"}],"externalDocs":{"description":"Find more info here","url":"https://example.com"},"bindings":{"amqp":{"is":"queue","queue":{"exclusive":true}}}},"userSignup":{"address":"users.signup","messages":{"userSignedUp":{"$ref":"#/components/messages/userSignedUp"}},"description":"Channel for user signups"},"userSignupReply":{"address":"users.signup.reply","messages":{"userSignedUpReply":{"payload":{"type":"object","properties":{"message":{"type":"string","description":"Additional information"},"status":{"type":"string","description":"Status of the signup process"}}},"summary":"User signup reply message"}},"description":"Channel for user signup replies"}},"operations":{"sendUserSignUp":{"action":"send","channel":{"$ref":"#/channels/user"},"title":"User sign up","summary":"Action to sign a user up.","description":"A longer description","security":[{"type":"oauth2","description":"The oauth security descriptions","flows":{"clientCredentials":{"tokenUrl":"https://example.com/api/oauth/dialog","availableScopes":{"subscribe:auth_revocations":"Scope required for authorization revocation topic"}}},"scopes":["subscribe:auth_revocations"]}],"tags":[{"name":"user"},{"name":"signup"},{"name":"register"}],"bindings":{"amqp":{"ack":false}},"traits":[],"messages":[{"$ref":"#/channels/user/messages/userSignedUp"}],"reply":{"address":{"location":"$message.header#/replyTo"},"channel":{"$ref":"#/channels/userSignupReply"},"messages":[{"$ref":"#/channels/userSignupReply/messages/userSignedUpReply"}]}}},"components":{"schemas":{"Address":{"type":"object","properties":{"city":{"type":"string"},"state":{"type":"string"},"street":{"type":"string"},"zip":{"type":"string"}}},"AvroExample":{"schemaFormat":"application/vnd.apache.avro+json;version=1.9.0","schema":{"fields":[{"name":"id","type":"int"},{"name":"name","type":"string"}],"name":"UserCreate","namespace":"com.example","type":"record"}},"Category":{"type":"object","properties":{"id":{"type":"integer","format":"int64"}}},"ComplexModel":{"type":"object","properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"}}},"ErrorModel":{"type":"object","properties":{"code":{"type":"integer","format":"int32"},"message":{"type":"string"}}},"Pet":{"type":"object","properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"},"tag":{"type":"string"}}},"signup":{"type":"object","required":["timestamp","source"],"properties":{"source":{"type":"string","description":"The source of the signup"},"timestamp":{"type":"string","description":"The timestamp of the signup","format":"date-time"}}},"userCreate":{"type":"object","required":["id","name","email"],"properties":{"email":{"type":"string","description":"The email of the user","format":"email"},"id":{"type":"string","description":"The ID of the user"},"name":{"type":"string","description":"The name of the user"}}}},"servers":{"development":{"host":"{stage}.in.mycompany.com","protocol":"amqp","description":"RabbitMQ broker","variables":{"stage":{"$ref":"#/components/serverVariables/stage"}},"security":[{"$ref":"#/components/securitySchemes/oauth"}],"bindings":{"$ref":"#/components/serverBindings/devAmqp"}}},"channels":{"user":{"address":"users.{userId}","messages":{"userSignedUp":{"$ref":"#/components/messages/userSignUp"}},"title":"Users channel","description":"This channel is used to exchange messages about user events.","servers":[{"$ref":"#/components/servers/development"}],"parameters":{"userId":{"$ref":"#/components/parameters/userId"}},"tags":[{"$ref":"#/components/tags/user"}],"externalDocs":{"$ref":"#/components/externalDocs/infoDocs"},"bindings":{"$ref":"#/components/channelBindings/user"}}},"operations":{"sendUserSignUp":{"action":"send","channel":{"$ref":"#/channels/user"},"title":"User sign up","bindings":{"$ref":"#/components/operationBindings/sendUser"},"traits":[{"$ref":"#/components/operationTraits/binding"}],"reply":{"$ref":"#/components/replies/signupReply"}}},"messages":{"userCompletedOrder":{"payload":{"type":"object","properties":{"amount":{"type":"number","description":"The total amount of the order"},"orderId":{"type":"string","description":"The ID of the order"},"userId":{"type":"string","description":"The ID of the user"}}},"contentType":"application/json","summary":"User completed order event"},"userSignUp":{"payload":{"$ref":"#/components/schemas/Category"},"correlationId":{"$ref":"#/components/correlationIds/default"},"summary":"Action to sign a user up.","bindings":{"$ref":"#/components/messageBindings/user"},"examples":[],"traits":[{"$ref":"#/components/messageTraits/commonHeaders"}]},"userSignedUp":{"headers":{"type":"object","properties":{"applicationInstanceId":{"type":"string","description":"Unique identifier for a given instance of the publishing application"},"correlationId":{"type":"string","description":"Correlation ID set by application"}}},"payload":{"type":"object","properties":{"signup":{"$ref":"#/components/schemas/signup"},"user":{"$ref":"#/components/schemas/userCreate"}}},"correlationId":{"description":"Default Correlation ID","location":"$message.header#/correlationId"},"contentType":"application/json","name":"UserSignup","title":"User signup","summary":"Action to sign a user up.","description":"A longer description","tags":[{"name":"user"},{"name":"signup"},{"name":"register"}],"examples":[{"headers":{"applicationInstanceId":"myInstanceId","correlationId":"my-correlation-id"},"payload":{"signup":{"someSignupKey":"someSignupValue"},"user":{"someUserKey":"someUserValue"}},"name":"SimpleSignup","summary":"A simple UserSignup example message"}],"traits":[{"$ref":"#/components/messageTraits/commonHeaders"}]},"userSignedUpReply":{"payload":{"type":"object","properties":{"message":{"type":"string","description":"Additional information"},"status":{"type":"string","description":"Status of the signup process"}}},"contentType":"application/json","name":"UserSignupReply","title":"User signup reply","summary":"User signup reply message"}},"securitySchemes":{"JWTAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT"},"X509Auth":{"type":"X509","description":"X509 security scheme"},"apiKeyAuth":{"type":"apiKey","description":"API key security scheme","in":"user"},"basicAuth":{"type":"http","description":"Basic security scheme","scheme":"basic"},"httpApiAuth":{"type":"httpApiKey","description":"api_key","name":"API Key Sample","in":"header"},"oauth":{"type":"oauth2","description":"The oauth security descriptions","flows":{"clientCredentials":{"tokenUrl":"https://example.com/api/oauth/dialog","availableScopes":{"subscribe:auth_revocations":"Scope required for authorization revocation topic"}}},"scopes":["subscribe:auth_revocations"]},"saslAuth":{"type":"scramSha256","description":"SASL security scheme"},"symmetricEncryptionAuth":{"type":"symmetricEncryption","description":"Symmetric encryption security scheme"},"userPasswordAuth":{"type":"userPassword","description":"User password security scheme"}},"serverVariables":{"stage":{"default":"demo","description":"This value is assigned by the service provider in this example of `mycompany.com`"}},"parameters":{"userId":{"description":"Id of the user."}},"correlationIds":{"default":{"description":"Default Correlation ID","location":"$message.header#/correlationId"}},"replies":{"signupReply":{"address":{"$ref":"#/components/replyAddresses/signupReply"},"channel":{"$ref":"#/channels/userSignupReply"}}},"replyAddresses":{"signupReply":{"location":"$message.header#/replyTo"}},"externalDocs":{"infoDocs":{"description":"Find more info here","url":"https://example.com/docs"}},"tags":{"user":{"name":"user","description":"User-related messages"}},"operationTraits":{"binding":{"bindings":{"amqp":{"ack":false}}},"kafka":{"bindings":{"kafka":{"groupId":false}}}},"messageTraits":{"commonHeaders":{"headers":{"type":"object","properties":{"my-app-header":{"type":"integer","maximum":100,"minimum":0}}}}},"serverBindings":{"devAmqp":{"amqp":{"exchange":"my-exchange","queue":"my-queue"}}},"channelBindings":{"user":{"amqp":{"is":"queue","queue":{"exclusive":true}}}},"operationBindings":{"sendUser":{"amqp":{"ack":false}}},"messageBindings":{"user":{"amqp":{"bindingVersion":"0.3.0","contentEncoding":"gzip","messageType":"user.signup"}}}}}
+ test/golden/spec-examples/16-default-content-type-at-root-doc-yaml.json view
@@ -0,0 +1,1 @@+{"asyncapi":"3.1.0","info":{"title":"AsyncAPI","version":"1.x.x","description":"This is a very good base doc, probably.","termsOfService":"https://asyncapi.org/terms/","license":{"name":"Apache 2.0","url":"https://www.apache.org/licenses/LICENSE-2.0.html"},"tags":[{"name":"e-commerce"}],"externalDocs":{"description":"Find more info here","url":"https://www.asyncapi.org"}},"servers":{"production":{"host":"rabbitmq.in.mycompany.com:5672","protocol":"amqp","protocolVersion":"1.0","pathname":"/v1","description":"Production RabbitMQ broker (uses the `production` vhost).","title":"Production Server","summary":"Production environment server","security":[{"type":"http","scheme":"bearer"}],"tags":[{"name":"production","description":"Production environment"}],"externalDocs":{"description":"Additional documentation for the production server","url":"https://example.com/docs/production"},"bindings":{"amqp":{"exchange":"my-exchange","queue":"my-queue"}}},"rabbitmqInProd":{"host":"{prod}.in.mycompany.com","protocol":"amqp","description":"Production server"},"rabbitmqInStaging":{"host":"{stage}.in.mycompany.com","protocol":"amqp","description":"Staging server"},"staging":{"host":"rabbitmq.in.mycompany.com:5672","protocol":"amqp","protocolVersion":"1.0","pathname":"/v1","description":"Staging RabbitMQ broker (uses the `staging` vhost).","title":"Staging Server","summary":"Staging environment server","security":[{"type":"apiKey","description":"Provide your API key as the user and leave the password empty.","in":"user"}],"tags":[{"name":"staging","description":"Staging environment"}],"externalDocs":{"description":"Additional documentation for the staging server","url":"https://example.com/docs/staging"},"bindings":{"amqp":{"exchange":"my-exchange","queue":"my-queue"}}}},"defaultContentType":"application/json","channels":{"user":{"address":"users.{userId}","messages":{"userCompletedOrder":{"$ref":"#/components/messages/userCompletedOrder"},"userSignedUp":{"$ref":"#/components/messages/userSignedUp"}},"title":"Users channel","description":"This channel is used to exchange messages about user events.","servers":[{"$ref":"#/servers/production"}],"parameters":{"userId":{"$ref":"#/components/parameters/userId"}},"tags":[{"name":"user","description":"User-related messages"}],"externalDocs":{"description":"Find more info here","url":"https://example.com"},"bindings":{"amqp":{"is":"queue","queue":{"exclusive":true}}}},"userSignup":{"address":"users.signup","messages":{"userSignedUp":{"$ref":"#/components/messages/userSignedUp"}},"description":"Channel for user signups"},"userSignupReply":{"address":"users.signup.reply","messages":{"userSignedUpReply":{"payload":{"type":"object","properties":{"message":{"type":"string","description":"Additional information"},"status":{"type":"string","description":"Status of the signup process"}}},"summary":"User signup reply message"}},"description":"Channel for user signup replies"}},"operations":{"sendUserSignUp":{"action":"send","channel":{"$ref":"#/channels/user"},"title":"User sign up","summary":"Action to sign a user up.","description":"A longer description","security":[{"type":"oauth2","description":"The oauth security descriptions","flows":{"clientCredentials":{"tokenUrl":"https://example.com/api/oauth/dialog","availableScopes":{"subscribe:auth_revocations":"Scope required for authorization revocation topic"}}},"scopes":["subscribe:auth_revocations"]}],"tags":[{"name":"user"},{"name":"signup"},{"name":"register"}],"bindings":{"amqp":{"ack":false}},"traits":[],"messages":[{"$ref":"#/channels/user/messages/userSignedUp"}],"reply":{"address":{"location":"$message.header#/replyTo"},"channel":{"$ref":"#/channels/userSignupReply"},"messages":[{"$ref":"#/channels/userSignupReply/messages/userSignedUpReply"}]}}},"components":{"schemas":{"Address":{"type":"object","properties":{"city":{"type":"string"},"state":{"type":"string"},"street":{"type":"string"},"zip":{"type":"string"}}},"AvroExample":{"schemaFormat":"application/vnd.apache.avro+json;version=1.9.0","schema":{"fields":[{"name":"id","type":"int"},{"name":"name","type":"string"}],"name":"UserCreate","namespace":"com.example","type":"record"}},"Category":{"type":"object","properties":{"id":{"type":"integer","format":"int64"}}},"ComplexModel":{"type":"object","properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"}}},"ErrorModel":{"type":"object","properties":{"code":{"type":"integer","format":"int32"},"message":{"type":"string"}}},"Pet":{"type":"object","properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"},"tag":{"type":"string"}}},"signup":{"type":"object","required":["timestamp","source"],"properties":{"source":{"type":"string","description":"The source of the signup"},"timestamp":{"type":"string","description":"The timestamp of the signup","format":"date-time"}}},"userCreate":{"type":"object","required":["id","name","email"],"properties":{"email":{"type":"string","description":"The email of the user","format":"email"},"id":{"type":"string","description":"The ID of the user"},"name":{"type":"string","description":"The name of the user"}}}},"servers":{"development":{"host":"{stage}.in.mycompany.com","protocol":"amqp","description":"RabbitMQ broker","variables":{"stage":{"$ref":"#/components/serverVariables/stage"}},"security":[{"$ref":"#/components/securitySchemes/oauth"}],"bindings":{"$ref":"#/components/serverBindings/devAmqp"}}},"channels":{"user":{"address":"users.{userId}","messages":{"userSignedUp":{"$ref":"#/components/messages/userSignUp"}},"title":"Users channel","description":"This channel is used to exchange messages about user events.","servers":[{"$ref":"#/components/servers/development"}],"parameters":{"userId":{"$ref":"#/components/parameters/userId"}},"tags":[{"$ref":"#/components/tags/user"}],"externalDocs":{"$ref":"#/components/externalDocs/infoDocs"},"bindings":{"$ref":"#/components/channelBindings/user"}}},"operations":{"sendUserSignUp":{"action":"send","channel":{"$ref":"#/channels/user"},"title":"User sign up","bindings":{"$ref":"#/components/operationBindings/sendUser"},"traits":[{"$ref":"#/components/operationTraits/binding"}],"reply":{"$ref":"#/components/replies/signupReply"}}},"messages":{"userCompletedOrder":{"payload":{"type":"object","properties":{"amount":{"type":"number","description":"The total amount of the order"},"orderId":{"type":"string","description":"The ID of the order"},"userId":{"type":"string","description":"The ID of the user"}}},"contentType":"application/json","summary":"User completed order event"},"userSignUp":{"payload":{"$ref":"#/components/schemas/Category"},"correlationId":{"$ref":"#/components/correlationIds/default"},"summary":"Action to sign a user up.","bindings":{"$ref":"#/components/messageBindings/user"},"examples":[],"traits":[{"$ref":"#/components/messageTraits/commonHeaders"}]},"userSignedUp":{"headers":{"type":"object","properties":{"applicationInstanceId":{"type":"string","description":"Unique identifier for a given instance of the publishing application"},"correlationId":{"type":"string","description":"Correlation ID set by application"}}},"payload":{"type":"object","properties":{"signup":{"$ref":"#/components/schemas/signup"},"user":{"$ref":"#/components/schemas/userCreate"}}},"correlationId":{"description":"Default Correlation ID","location":"$message.header#/correlationId"},"contentType":"application/json","name":"UserSignup","title":"User signup","summary":"Action to sign a user up.","description":"A longer description","tags":[{"name":"user"},{"name":"signup"},{"name":"register"}],"examples":[{"headers":{"applicationInstanceId":"myInstanceId","correlationId":"my-correlation-id"},"payload":{"signup":{"someSignupKey":"someSignupValue"},"user":{"someUserKey":"someUserValue"}},"name":"SimpleSignup","summary":"A simple UserSignup example message"}],"traits":[{"$ref":"#/components/messageTraits/commonHeaders"}]},"userSignedUpReply":{"payload":{"type":"object","properties":{"message":{"type":"string","description":"Additional information"},"status":{"type":"string","description":"Status of the signup process"}}},"contentType":"application/json","name":"UserSignupReply","title":"User signup reply","summary":"User signup reply message"}},"securitySchemes":{"JWTAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT"},"X509Auth":{"type":"X509","description":"X509 security scheme"},"apiKeyAuth":{"type":"apiKey","description":"API key security scheme","in":"user"},"basicAuth":{"type":"http","description":"Basic security scheme","scheme":"basic"},"httpApiAuth":{"type":"httpApiKey","description":"api_key","name":"API Key Sample","in":"header"},"oauth":{"type":"oauth2","description":"The oauth security descriptions","flows":{"clientCredentials":{"tokenUrl":"https://example.com/api/oauth/dialog","availableScopes":{"subscribe:auth_revocations":"Scope required for authorization revocation topic"}}},"scopes":["subscribe:auth_revocations"]},"saslAuth":{"type":"scramSha256","description":"SASL security scheme"},"symmetricEncryptionAuth":{"type":"symmetricEncryption","description":"Symmetric encryption security scheme"},"userPasswordAuth":{"type":"userPassword","description":"User password security scheme"}},"serverVariables":{"stage":{"default":"demo","description":"This value is assigned by the service provider in this example of `mycompany.com`"}},"parameters":{"userId":{"description":"Id of the user."}},"correlationIds":{"default":{"description":"Default Correlation ID","location":"$message.header#/correlationId"}},"replies":{"signupReply":{"address":{"$ref":"#/components/replyAddresses/signupReply"},"channel":{"$ref":"#/channels/userSignupReply"}}},"replyAddresses":{"signupReply":{"location":"$message.header#/replyTo"}},"externalDocs":{"infoDocs":{"description":"Find more info here","url":"https://example.com/docs"}},"tags":{"user":{"name":"user","description":"User-related messages"}},"operationTraits":{"binding":{"bindings":{"amqp":{"ack":false}}},"kafka":{"bindings":{"kafka":{"groupId":false}}}},"messageTraits":{"commonHeaders":{"headers":{"type":"object","properties":{"my-app-header":{"type":"integer","maximum":100,"minimum":0}}}}},"serverBindings":{"devAmqp":{"amqp":{"exchange":"my-exchange","queue":"my-queue"}}},"channelBindings":{"user":{"amqp":{"is":"queue","queue":{"exclusive":true}}}},"operationBindings":{"sendUser":{"amqp":{"ack":false}}},"messageBindings":{"user":{"amqp":{"bindingVersion":"0.3.0","contentEncoding":"gzip","messageType":"user.signup"}}}}}
+ test/golden/spec-examples/17-channels-object-json.json view
@@ -0,0 +1,1 @@+{"userSignedUp":{"address":"user.signedup","messages":{"userSignedUp":{"$ref":"#/components/messages/userSignedUp"}}}}
+ test/golden/spec-examples/18-channels-object-yaml.json view
@@ -0,0 +1,1 @@+{"userSignedUp":{"address":"user.signedup","messages":{"userSignedUp":{"$ref":"#/components/messages/userSignedUp"}}}}
+ test/golden/spec-examples/19-channel-object-json.json view
@@ -0,0 +1,1 @@+{"address":"users.{userId}","messages":{"userCompletedOrder":{"$ref":"#/components/messages/userCompletedOrder"},"userSignedUp":{"$ref":"#/components/messages/userSignedUp"}},"title":"Users channel","description":"This channel is used to exchange messages about user events.","servers":[{"$ref":"#/servers/rabbitmqInProd"},{"$ref":"#/servers/rabbitmqInStaging"}],"parameters":{"userId":{"$ref":"#/components/parameters/userId"}},"tags":[{"name":"user","description":"User-related messages"}],"externalDocs":{"description":"Find more info here","url":"https://example.com"},"bindings":{"amqp":{"is":"queue","queue":{"exclusive":true}}}}
+ test/golden/spec-examples/2-info-object-yaml.json view
@@ -0,0 +1,1 @@+{"title":"AsyncAPI Sample App","version":"1.0.1","description":"This is a sample app.","termsOfService":"https://asyncapi.org/terms/","contact":{"name":"API Support","url":"https://www.asyncapi.org/support","email":"support@asyncapi.org"},"license":{"name":"Apache 2.0","url":"https://www.apache.org/licenses/LICENSE-2.0.html"},"tags":[{"name":"e-commerce"}],"externalDocs":{"description":"Find more info here","url":"https://www.asyncapi.org"}}
+ test/golden/spec-examples/20-channel-object-yaml.json view
@@ -0,0 +1,1 @@+{"address":"users.{userId}","messages":{"userCompletedOrder":{"$ref":"#/components/messages/userCompletedOrder"},"userSignedUp":{"$ref":"#/components/messages/userSignedUp"}},"title":"Users channel","description":"This channel is used to exchange messages about user events.","servers":[{"$ref":"#/servers/rabbitmqInProd"},{"$ref":"#/servers/rabbitmqInStaging"}],"parameters":{"userId":{"$ref":"#/components/parameters/userId"}},"tags":[{"name":"user","description":"User-related messages"}],"externalDocs":{"description":"Find more info here","url":"https://example.com"},"bindings":{"amqp":{"is":"queue","queue":{"exclusive":true}}}}
+ test/golden/spec-examples/21-messages-object-json.json view
@@ -0,0 +1,1 @@+{"userSignedUp":{"$ref":"#/components/messages/userSignedUp"},"userCompletedOrder":{"$ref":"#/components/messages/userCompletedOrder"}}
+ test/golden/spec-examples/22-messages-object-yaml.json view
@@ -0,0 +1,1 @@+{"userSignedUp":{"$ref":"#/components/messages/userSignedUp"},"userCompletedOrder":{"$ref":"#/components/messages/userCompletedOrder"}}
+ test/golden/spec-examples/23-operations-object-json.json view
@@ -0,0 +1,1 @@+{"onUserSignUp":{"action":"send","channel":{"$ref":"#/channels/userSignup"},"title":"User sign up","summary":"Action to sign a user up.","description":"A longer description","tags":[{"name":"user"},{"name":"signup"},{"name":"register"}],"bindings":{"amqp":{"ack":false}},"traits":[{"$ref":"#/components/operationTraits/kafka"}]}}
+ test/golden/spec-examples/24-operations-object-yaml.json view
@@ -0,0 +1,1 @@+{"onUserSignUp":{"action":"send","channel":{"$ref":"#/channels/userSignup"},"title":"User sign up","summary":"Action to sign a user up.","description":"A longer description","tags":[{"name":"user"},{"name":"signup"},{"name":"register"}],"bindings":{"amqp":{"ack":false}},"traits":[{"$ref":"#/components/operationTraits/kafka"}]}}
+ test/golden/spec-examples/25-operation-object-json.json view
@@ -0,0 +1,1 @@+{"action":"send","channel":{"$ref":"#/channels/userSignup"},"title":"User sign up","summary":"Action to sign a user up.","description":"A longer description","security":[{"type":"oauth2","description":"The oauth security descriptions","flows":{"clientCredentials":{"tokenUrl":"https://example.com/api/oauth/dialog","availableScopes":{"subscribe:auth_revocations":"Scope required for authorization revocation topic"}}},"scopes":["subscribe:auth_revocations"]}],"tags":[{"name":"user"},{"name":"signup"},{"name":"register"}],"bindings":{"amqp":{"ack":false}},"traits":[{"$ref":"#/components/operationTraits/kafka"}],"messages":[{"$ref":"#/channels/userSignup/messages/userSignedUp"}],"reply":{"address":{"location":"$message.header#/replyTo"},"channel":{"$ref":"#/channels/userSignupReply"},"messages":[{"$ref":"#/channels/userSignupReply/messages/userSignedUpReply"}]}}
+ test/golden/spec-examples/26-operation-object-yaml.json view
@@ -0,0 +1,1 @@+{"action":"send","channel":{"$ref":"#/channels/userSignup"},"title":"User sign up","summary":"Action to sign a user up.","description":"A longer description","security":[{"type":"oauth2","description":"The oauth security descriptions","flows":{"clientCredentials":{"tokenUrl":"https://example.com/api/oauth/dialog","availableScopes":{"subscribe:auth_revocations":"Scope required for authorization revocation topic"}}},"scopes":["subscribe:auth_revocations"]}],"tags":[{"name":"user"},{"name":"signup"},{"name":"register"}],"bindings":{"amqp":{"ack":false}},"traits":[{"$ref":"#/components/operationTraits/kafka"}],"messages":[{"$ref":"#/channels/userSignup/messages/userSignedUp"}],"reply":{"address":{"location":"$message.header#/replyTo"},"channel":{"$ref":"#/channels/userSignupReply"},"messages":[{"$ref":"#/channels/userSignupReply/messages/userSignedUpReply"}]}}
+ test/golden/spec-examples/27-operation-traits-object-json.json view
@@ -0,0 +1,1 @@+{"bindings":{"amqp":{"ack":false}}}
+ test/golden/spec-examples/28-operation-traits-object-yaml.json view
@@ -0,0 +1,1 @@+{"bindings":{"amqp":{"ack":false}}}
+ test/golden/spec-examples/29-operation-reply-address-object-json.json view
@@ -0,0 +1,1 @@+{"description":"Consumer inbox","location":"$message.header#/replyTo"}
+ test/golden/spec-examples/3-contact-object-json.json view
@@ -0,0 +1,1 @@+{"name":"API Support","url":"https://www.example.com/support","email":"support@example.com"}
+ test/golden/spec-examples/30-operation-reply-address-object-yaml.json view
@@ -0,0 +1,1 @@+{"description":"Consumer Inbox","location":"$message.header#/replyTo"}
+ test/golden/spec-examples/31-channel-parameters-object-json.json view
@@ -0,0 +1,1 @@+{"address":"user/{userId}/signedup","parameters":{"userId":{"description":"Id of the user."}}}
+ test/golden/spec-examples/32-channel-parameters-object-yaml.json view
@@ -0,0 +1,1 @@+{"address":"user/{userId}/signedup","parameters":{"userId":{"description":"Id of the user."}}}
+ test/golden/spec-examples/33-channel-parameter-object-json.json view
@@ -0,0 +1,1 @@+{"address":"user/{userId}/signedup","parameters":{"userId":{"description":"Id of the user.","location":"$message.payload#/user/id"}}}
+ test/golden/spec-examples/34-channel-parameter-object-yaml.json view
@@ -0,0 +1,1 @@+{"address":"user/{userId}/signedup","parameters":{"userId":{"description":"Id of the user.","location":"$message.payload#/user/id"}}}
+ test/golden/spec-examples/35-message-object-json.json view
@@ -0,0 +1,1 @@+{"headers":{"type":"object","properties":{"applicationInstanceId":{"type":"string","description":"Unique identifier for a given instance of the publishing application"},"correlationId":{"type":"string","description":"Correlation ID set by application"}}},"payload":{"type":"object","properties":{"signup":{"$ref":"#/components/schemas/signup"},"user":{"$ref":"#/components/schemas/userCreate"}}},"correlationId":{"description":"Default Correlation ID","location":"$message.header#/correlationId"},"contentType":"application/json","name":"UserSignup","title":"User signup","summary":"Action to sign a user up.","description":"A longer description","tags":[{"name":"user"},{"name":"signup"},{"name":"register"}],"examples":[{"headers":{"applicationInstanceId":"myInstanceId","correlationId":"my-correlation-id"},"payload":{"signup":{"someSignupKey":"someSignupValue"},"user":{"someUserKey":"someUserValue"}},"name":"SimpleSignup","summary":"A simple UserSignup example message"}],"traits":[{"$ref":"#/components/messageTraits/commonHeaders"}]}
+ test/golden/spec-examples/36-message-object-yaml.json view
@@ -0,0 +1,1 @@+{"headers":{"type":"object","properties":{"applicationInstanceId":{"type":"string","description":"Unique identifier for a given instance of the publishing application"},"correlationId":{"type":"string","description":"Correlation ID set by application"}}},"payload":{"type":"object","properties":{"signup":{"$ref":"#/components/schemas/signup"},"user":{"$ref":"#/components/schemas/userCreate"}}},"correlationId":{"description":"Default Correlation ID","location":"$message.header#/correlationId"},"contentType":"application/json","name":"UserSignup","title":"User signup","summary":"Action to sign a user up.","description":"A longer description","tags":[{"name":"user"},{"name":"signup"},{"name":"register"}],"examples":[{"headers":{"applicationInstanceId":"myInstanceId","correlationId":"my-correlation-id"},"payload":{"signup":{"someSignupKey":"someSignupValue"},"user":{"someUserKey":"someUserValue"}},"name":"SimpleSignup","summary":"A simple UserSignup example message"}],"traits":[{"$ref":"#/components/messageTraits/commonHeaders"}]}
+ test/golden/spec-examples/37-message-object-json.json view
@@ -0,0 +1,1 @@+{"payload":{"schemaFormat":"application/vnd.apache.avro+json;version=1.9.0","schema":{"$ref":"./user-create.avsc"}},"name":"UserSignup","title":"User signup","summary":"Action to sign a user up.","description":"A longer description","tags":[{"name":"user"},{"name":"signup"},{"name":"register"}]}
+ test/golden/spec-examples/38-message-object-yaml.json view
@@ -0,0 +1,1 @@+{"payload":{"schemaFormat":"application/vnd.apache.avro+yaml;version=1.9.0","schema":{"$ref":"./user-create.avsc"}},"name":"UserSignup","title":"User signup","summary":"Action to sign a user up.","description":"A longer description","tags":[{"name":"user"},{"name":"signup"},{"name":"register"}]}
+ test/golden/spec-examples/39-message-trait-object-json.json view
@@ -0,0 +1,1 @@+{"contentType":"application/json"}
+ test/golden/spec-examples/4-contact-object-yaml.json view
@@ -0,0 +1,1 @@+{"name":"API Support","url":"https://www.example.com/support","email":"support@example.com"}
+ test/golden/spec-examples/40-message-trait-object-yaml.json view
@@ -0,0 +1,1 @@+{"contentType":"application/json"}
+ test/golden/spec-examples/41-message-example-object-json.json view
@@ -0,0 +1,1 @@+{"headers":{"applicationInstanceId":"myInstanceId","correlationId":"my-correlation-id"},"payload":{"signup":{"someSignupKey":"someSignupValue"},"user":{"someUserKey":"someUserValue"}},"name":"SimpleSignup","summary":"A simple UserSignup example message"}
+ test/golden/spec-examples/42-message-example-object-yaml.json view
@@ -0,0 +1,1 @@+{"headers":{"applicationInstanceId":"myInstanceId","correlationId":"my-correlation-id"},"payload":{"signup":{"someSignupKey":"someSignupValue"},"user":{"someUserKey":"someUserValue"}},"name":"SimpleSignup","summary":"A simple UserSignup example message"}
+ test/golden/spec-examples/43-tag-object-json.json view
@@ -0,0 +1,1 @@+{"name":"user","description":"User-related messages"}
+ test/golden/spec-examples/44-tag-object-yaml.json view
@@ -0,0 +1,1 @@+{"name":"user","description":"User-related messages"}
+ test/golden/spec-examples/45-external-docs-object-json.json view
@@ -0,0 +1,1 @@+{"description":"Find more info here","url":"https://example.com"}
+ test/golden/spec-examples/46-external-docs-object-yaml.json view
@@ -0,0 +1,1 @@+{"description":"Find more info here","url":"https://example.com"}
+ test/golden/spec-examples/47-reference-object-json.json view
@@ -0,0 +1,1 @@+{"$ref":"#/components/schemas/Pet"}
+ test/golden/spec-examples/48-reference-object-yaml.json view
@@ -0,0 +1,1 @@+{"$ref":"#/components/schemas/Pet"}
+ test/golden/spec-examples/49-components-object-json.json view
@@ -0,0 +1,1 @@+{"asyncapi":"3.1.0","info":{"title":"AsyncAPI","version":"1.x.x","description":"This is a very good base doc, probably.","termsOfService":"https://asyncapi.org/terms/","license":{"name":"Apache 2.0","url":"https://www.apache.org/licenses/LICENSE-2.0.html"},"tags":[{"name":"e-commerce"}],"externalDocs":{"description":"Find more info here","url":"https://www.asyncapi.org"}},"servers":{"production":{"host":"rabbitmq.in.mycompany.com:5672","protocol":"amqp","protocolVersion":"1.0","pathname":"/v1","description":"Production RabbitMQ broker (uses the `production` vhost).","title":"Production Server","summary":"Production environment server","security":[{"type":"http","scheme":"bearer"}],"tags":[{"name":"production","description":"Production environment"}],"externalDocs":{"description":"Additional documentation for the production server","url":"https://example.com/docs/production"},"bindings":{"amqp":{"exchange":"my-exchange","queue":"my-queue"}}},"rabbitmqInProd":{"host":"{prod}.in.mycompany.com","protocol":"amqp","description":"Production server"},"rabbitmqInStaging":{"host":"{stage}.in.mycompany.com","protocol":"amqp","description":"Staging server"},"staging":{"host":"rabbitmq.in.mycompany.com:5672","protocol":"amqp","protocolVersion":"1.0","pathname":"/v1","description":"Staging RabbitMQ broker (uses the `staging` vhost).","title":"Staging Server","summary":"Staging environment server","security":[{"type":"apiKey","description":"Provide your API key as the user and leave the password empty.","in":"user"}],"tags":[{"name":"staging","description":"Staging environment"}],"externalDocs":{"description":"Additional documentation for the staging server","url":"https://example.com/docs/staging"},"bindings":{"amqp":{"exchange":"my-exchange","queue":"my-queue"}}}},"channels":{"user":{"address":"users.{userId}","messages":{"userCompletedOrder":{"$ref":"#/components/messages/userCompletedOrder"},"userSignedUp":{"$ref":"#/components/messages/userSignedUp"}},"title":"Users channel","description":"This channel is used to exchange messages about user events.","servers":[{"$ref":"#/servers/production"}],"parameters":{"userId":{"$ref":"#/components/parameters/userId"}},"tags":[{"name":"user","description":"User-related messages"}],"externalDocs":{"description":"Find more info here","url":"https://example.com"},"bindings":{"amqp":{"is":"queue","queue":{"exclusive":true}}}},"userSignup":{"address":"users.signup","messages":{"userSignedUp":{"$ref":"#/components/messages/userSignedUp"}},"description":"Channel for user signups"},"userSignupReply":{"address":"users.signup.reply","messages":{"userSignedUpReply":{"payload":{"type":"object","properties":{"message":{"type":"string","description":"Additional information"},"status":{"type":"string","description":"Status of the signup process"}}},"summary":"User signup reply message"}},"description":"Channel for user signup replies"}},"operations":{"sendUserSignUp":{"action":"send","channel":{"$ref":"#/channels/user"},"title":"User sign up","summary":"Action to sign a user up.","description":"A longer description","security":[{"type":"oauth2","description":"The oauth security descriptions","flows":{"clientCredentials":{"tokenUrl":"https://example.com/api/oauth/dialog","availableScopes":{"subscribe:auth_revocations":"Scope required for authorization revocation topic"}}},"scopes":["subscribe:auth_revocations"]}],"tags":[{"name":"user"},{"name":"signup"},{"name":"register"}],"bindings":{"amqp":{"ack":false}},"traits":[],"messages":[{"$ref":"#/channels/user/messages/userSignedUp"}],"reply":{"address":{"location":"$message.header#/replyTo"},"channel":{"$ref":"#/channels/userSignupReply"},"messages":[{"$ref":"#/channels/userSignupReply/messages/userSignedUpReply"}]}}},"components":{"schemas":{"Address":{"type":"object","properties":{"city":{"type":"string"},"state":{"type":"string"},"street":{"type":"string"},"zip":{"type":"string"}}},"AvroExample":{"schemaFormat":"application/vnd.apache.avro+json;version=1.9.0","schema":{"$ref":"./user-create.avsc","fields":[{"name":"id","type":"int"},{"name":"name","type":"string"}],"name":"UserCreate","namespace":"com.example","type":"record"}},"Category":{"type":"object","properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"}}},"ComplexModel":{"type":"object","properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"}}},"ErrorModel":{"type":"object","properties":{"code":{"type":"integer","format":"int32"},"message":{"type":"string"}}},"Pet":{"type":"object","properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"},"tag":{"type":"string"}}},"Tag":{"type":"object","properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"}}},"signup":{"type":"object","required":["timestamp","source"],"properties":{"source":{"type":"string","description":"The source of the signup"},"timestamp":{"type":"string","description":"The timestamp of the signup","format":"date-time"}}},"userCreate":{"type":"object","required":["id","name","email"],"properties":{"email":{"type":"string","description":"The email of the user","format":"email"},"id":{"type":"string","description":"The ID of the user"},"name":{"type":"string","description":"The name of the user"}}}},"servers":{"development":{"host":"{stage}.in.mycompany.com:{port}","protocol":"amqp","protocolVersion":"0-9-1","description":"RabbitMQ broker","variables":{"port":{"$ref":"#/components/serverVariables/port"},"stage":{"$ref":"#/components/serverVariables/stage"}},"security":[{"$ref":"#/components/securitySchemes/oauth"}],"bindings":{"$ref":"#/components/serverBindings/devAmqp"}}},"channels":{"user":{"address":"users.{userId}","messages":{"userSignedUp":{"$ref":"#/components/messages/userSignUp"}},"title":"Users channel","description":"This channel is used to exchange messages about user events.","servers":[{"$ref":"#/components/servers/development"}],"parameters":{"userId":{"$ref":"#/components/parameters/userId"}},"tags":[{"$ref":"#/components/tags/user"}],"externalDocs":{"$ref":"#/components/externalDocs/infoDocs"},"bindings":{"$ref":"#/components/channelBindings/user"}},"user/signedup":{}},"operations":{"sendUserSignUp":{"action":"send","channel":{"$ref":"#/channels/user"},"title":"User sign up","bindings":{"$ref":"#/components/operationBindings/sendUser"},"traits":[{"$ref":"#/components/operationTraits/binding"}],"reply":{"$ref":"#/components/replies/signupReply"}}},"messages":{"userCompletedOrder":{"payload":{"type":"object","properties":{"amount":{"type":"number","description":"The total amount of the order"},"orderId":{"type":"string","description":"The ID of the order"},"userId":{"type":"string","description":"The ID of the user"}}},"contentType":"application/json","summary":"User completed order event"},"userSignUp":{"headers":{"type":"object","properties":{"applicationInstanceId":{"type":"string","description":"Unique identifier for a given instance of the publishing application"}}},"payload":{"$ref":"#/components/schemas/Category"},"correlationId":{"$ref":"#/components/correlationIds/default"},"summary":"Action to sign a user up.","description":"Multiline description of what this action does.\nHere you have another line.\n","tags":[{"name":"user"},{"name":"signup"}],"bindings":{"$ref":"#/components/messageBindings/user"},"examples":[],"traits":[{"$ref":"#/components/messageTraits/commonHeaders"}]},"userSignedUp":{"headers":{"type":"object","properties":{"applicationInstanceId":{"type":"string","description":"Unique identifier for a given instance of the publishing application"},"correlationId":{"type":"string","description":"Correlation ID set by application"}}},"payload":{"type":"object","properties":{"signup":{"$ref":"#/components/schemas/signup"},"user":{"$ref":"#/components/schemas/userCreate"}}},"correlationId":{"description":"Default Correlation ID","location":"$message.header#/correlationId"},"contentType":"application/json","name":"UserSignup","title":"User signup","summary":"Action to sign a user up.","description":"A longer description","tags":[{"name":"user"},{"name":"signup"},{"name":"register"}],"examples":[{"headers":{"applicationInstanceId":"myInstanceId","correlationId":"my-correlation-id"},"payload":{"signup":{"someSignupKey":"someSignupValue"},"user":{"someUserKey":"someUserValue"}},"name":"SimpleSignup","summary":"A simple UserSignup example message"}],"traits":[{"$ref":"#/components/messageTraits/commonHeaders"}]},"userSignedUpReply":{"payload":{"type":"object","properties":{"message":{"type":"string","description":"Additional information"},"status":{"type":"string","description":"Status of the signup process"}}},"contentType":"application/json","name":"UserSignupReply","title":"User signup reply","summary":"User signup reply message"}},"securitySchemes":{"JWTAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT"},"X509Auth":{"type":"X509","description":"X509 security scheme"},"apiKeyAuth":{"type":"apiKey","description":"API key security scheme","in":"user"},"basicAuth":{"type":"http","description":"Basic security scheme","scheme":"basic"},"httpApiAuth":{"type":"httpApiKey","description":"api_key","name":"API Key Sample","in":"header"},"oauth":{"type":"oauth2","description":"The oauth security descriptions","flows":{"clientCredentials":{"tokenUrl":"https://example.com/api/oauth/dialog","availableScopes":{"subscribe:auth_revocations":"Scope required for authorization revocation topic"}}},"scopes":["subscribe:auth_revocations"]},"saslAuth":{"type":"scramSha256","description":"SASL security scheme"},"symmetricEncryptionAuth":{"type":"symmetricEncryption","description":"Symmetric encryption security scheme"},"userPasswordAuth":{"type":"userPassword","description":"User password security scheme"}},"serverVariables":{"port":{"enum":["5671","5672"],"default":"5672"},"stage":{"default":"demo","description":"This value is assigned by the service provider, in this example `mycompany.com`"}},"parameters":{"userId":{"description":"Id of the user."}},"correlationIds":{"default":{"description":"Default Correlation ID","location":"$message.header#/correlationId"}},"replies":{"signupReply":{"address":{"$ref":"#/components/replyAddresses/signupReply"},"channel":{"$ref":"#/channels/userSignupReply"}}},"replyAddresses":{"signupReply":{"location":"$message.header#/replyTo"}},"externalDocs":{"infoDocs":{"description":"Find more info here","url":"https://example.com/docs"}},"tags":{"user":{"name":"user","description":"User-related messages"}},"operationTraits":{"binding":{"bindings":{"amqp":{"ack":false}}},"kafka":{"bindings":{"kafka":{"groupId":false}}}},"messageTraits":{"commonHeaders":{"headers":{"type":"object","properties":{"my-app-header":{"type":"integer","maximum":100,"minimum":0}}}}},"serverBindings":{"devAmqp":{"amqp":{"exchange":"my-exchange","queue":"my-queue"}}},"channelBindings":{"user":{"amqp":{"is":"queue","queue":{"exclusive":true}}}},"operationBindings":{"sendUser":{"amqp":{"ack":false}}},"messageBindings":{"user":{"amqp":{"bindingVersion":"0.3.0","contentEncoding":"gzip","messageType":"user.signup"}}}}}
+ test/golden/spec-examples/5-license-object-json.json view
@@ -0,0 +1,1 @@+{"name":"Apache 2.0","url":"https://www.apache.org/licenses/LICENSE-2.0.html"}
+ test/golden/spec-examples/50-components-object-yaml.json view
@@ -0,0 +1,1 @@+{"asyncapi":"3.1.0","info":{"title":"AsyncAPI","version":"1.x.x","description":"This is a very good base doc, probably.","termsOfService":"https://asyncapi.org/terms/","license":{"name":"Apache 2.0","url":"https://www.apache.org/licenses/LICENSE-2.0.html"},"tags":[{"name":"e-commerce"}],"externalDocs":{"description":"Find more info here","url":"https://www.asyncapi.org"}},"servers":{"production":{"host":"rabbitmq.in.mycompany.com:5672","protocol":"amqp","protocolVersion":"1.0","pathname":"/v1","description":"Production RabbitMQ broker (uses the `production` vhost).","title":"Production Server","summary":"Production environment server","security":[{"type":"http","scheme":"bearer"}],"tags":[{"name":"production","description":"Production environment"}],"externalDocs":{"description":"Additional documentation for the production server","url":"https://example.com/docs/production"},"bindings":{"amqp":{"exchange":"my-exchange","queue":"my-queue"}}},"rabbitmqInProd":{"host":"{prod}.in.mycompany.com","protocol":"amqp","description":"Production server"},"rabbitmqInStaging":{"host":"{stage}.in.mycompany.com","protocol":"amqp","description":"Staging server"},"staging":{"host":"rabbitmq.in.mycompany.com:5672","protocol":"amqp","protocolVersion":"1.0","pathname":"/v1","description":"Staging RabbitMQ broker (uses the `staging` vhost).","title":"Staging Server","summary":"Staging environment server","security":[{"type":"apiKey","description":"Provide your API key as the user and leave the password empty.","in":"user"}],"tags":[{"name":"staging","description":"Staging environment"}],"externalDocs":{"description":"Additional documentation for the staging server","url":"https://example.com/docs/staging"},"bindings":{"amqp":{"exchange":"my-exchange","queue":"my-queue"}}}},"channels":{"user":{"address":"users.{userId}","messages":{"userCompletedOrder":{"$ref":"#/components/messages/userCompletedOrder"},"userSignedUp":{"$ref":"#/components/messages/userSignedUp"}},"title":"Users channel","description":"This channel is used to exchange messages about user events.","servers":[{"$ref":"#/servers/production"}],"parameters":{"userId":{"$ref":"#/components/parameters/userId"}},"tags":[{"name":"user","description":"User-related messages"}],"externalDocs":{"description":"Find more info here","url":"https://example.com"},"bindings":{"amqp":{"is":"queue","queue":{"exclusive":true}}}},"userSignup":{"address":"users.signup","messages":{"userSignedUp":{"$ref":"#/components/messages/userSignedUp"}},"description":"Channel for user signups"},"userSignupReply":{"address":"users.signup.reply","messages":{"userSignedUpReply":{"payload":{"type":"object","properties":{"message":{"type":"string","description":"Additional information"},"status":{"type":"string","description":"Status of the signup process"}}},"summary":"User signup reply message"}},"description":"Channel for user signup replies"}},"operations":{"sendUserSignUp":{"action":"send","channel":{"$ref":"#/channels/user"},"title":"User sign up","summary":"Action to sign a user up.","description":"A longer description","security":[{"type":"oauth2","description":"The oauth security descriptions","flows":{"clientCredentials":{"tokenUrl":"https://example.com/api/oauth/dialog","availableScopes":{"subscribe:auth_revocations":"Scope required for authorization revocation topic"}}},"scopes":["subscribe:auth_revocations"]}],"tags":[{"name":"user"},{"name":"signup"},{"name":"register"}],"bindings":{"amqp":{"ack":false}},"traits":[],"messages":[{"$ref":"#/channels/user/messages/userSignedUp"}],"reply":{"address":{"location":"$message.header#/replyTo"},"channel":{"$ref":"#/channels/userSignupReply"},"messages":[{"$ref":"#/channels/userSignupReply/messages/userSignedUpReply"}]}}},"components":{"schemas":{"Address":{"type":"object","properties":{"city":{"type":"string"},"state":{"type":"string"},"street":{"type":"string"},"zip":{"type":"string"}}},"AvroExample":{"schemaFormat":"application/vnd.apache.avro+json;version=1.9.0","schema":{"$ref":"./user-create.avsc","fields":[{"name":"id","type":"int"},{"name":"name","type":"string"}],"name":"UserCreate","namespace":"com.example","type":"record"}},"Category":{"type":"object","properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"}}},"ComplexModel":{"type":"object","properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"}}},"ErrorModel":{"type":"object","properties":{"code":{"type":"integer","format":"int32"},"message":{"type":"string"}}},"Pet":{"type":"object","properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"},"tag":{"type":"string"}}},"Tag":{"type":"object","properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"}}},"signup":{"type":"object","required":["timestamp","source"],"properties":{"source":{"type":"string","description":"The source of the signup"},"timestamp":{"type":"string","description":"The timestamp of the signup","format":"date-time"}}},"userCreate":{"type":"object","required":["id","name","email"],"properties":{"email":{"type":"string","description":"The email of the user","format":"email"},"id":{"type":"string","description":"The ID of the user"},"name":{"type":"string","description":"The name of the user"}}}},"servers":{"development":{"host":"{stage}.in.mycompany.com:{port}","protocol":"amqp","protocolVersion":"0-9-1","description":"RabbitMQ broker","variables":{"port":{"$ref":"#/components/serverVariables/port"},"stage":{"$ref":"#/components/serverVariables/stage"}},"security":[{"$ref":"#/components/securitySchemes/oauth"}],"bindings":{"$ref":"#/components/serverBindings/devAmqp"}}},"channels":{"user":{"address":"users.{userId}","messages":{"userSignedUp":{"$ref":"#/components/messages/userSignUp"}},"title":"Users channel","description":"This channel is used to exchange messages about user events.","servers":[{"$ref":"#/components/servers/development"}],"parameters":{"userId":{"$ref":"#/components/parameters/userId"}},"tags":[{"$ref":"#/components/tags/user"}],"externalDocs":{"$ref":"#/components/externalDocs/infoDocs"},"bindings":{"$ref":"#/components/channelBindings/user"}},"user/signedup":{}},"operations":{"sendUserSignUp":{"action":"send","channel":{"$ref":"#/channels/user"},"title":"User sign up","bindings":{"$ref":"#/components/operationBindings/sendUser"},"traits":[{"$ref":"#/components/operationTraits/binding"}],"reply":{"$ref":"#/components/replies/signupReply"}}},"messages":{"userCompletedOrder":{"payload":{"type":"object","properties":{"amount":{"type":"number","description":"The total amount of the order"},"orderId":{"type":"string","description":"The ID of the order"},"userId":{"type":"string","description":"The ID of the user"}}},"contentType":"application/json","summary":"User completed order event"},"userSignUp":{"headers":{"type":"object","properties":{"applicationInstanceId":{"type":"string","description":"Unique identifier for a given instance of the publishing\napplication\n"}}},"payload":{"$ref":"#/components/schemas/Category"},"correlationId":{"$ref":"#/components/correlationIds/default"},"summary":"Action to sign a user up.","description":"Multiline description of what this action does.\nHere you have another line.\n","tags":[{"name":"user"},{"name":"signup"}],"bindings":{"$ref":"#/components/messageBindings/user"},"examples":[],"traits":[{"$ref":"#/components/messageTraits/commonHeaders"}]},"userSignedUp":{"headers":{"type":"object","properties":{"applicationInstanceId":{"type":"string","description":"Unique identifier for a given instance of the publishing application"},"correlationId":{"type":"string","description":"Correlation ID set by application"}}},"payload":{"type":"object","properties":{"signup":{"$ref":"#/components/schemas/signup"},"user":{"$ref":"#/components/schemas/userCreate"}}},"correlationId":{"description":"Default Correlation ID","location":"$message.header#/correlationId"},"contentType":"application/json","name":"UserSignup","title":"User signup","summary":"Action to sign a user up.","description":"A longer description","tags":[{"name":"user"},{"name":"signup"},{"name":"register"}],"examples":[{"headers":{"applicationInstanceId":"myInstanceId","correlationId":"my-correlation-id"},"payload":{"signup":{"someSignupKey":"someSignupValue"},"user":{"someUserKey":"someUserValue"}},"name":"SimpleSignup","summary":"A simple UserSignup example message"}],"traits":[{"$ref":"#/components/messageTraits/commonHeaders"}]},"userSignedUpReply":{"payload":{"type":"object","properties":{"message":{"type":"string","description":"Additional information"},"status":{"type":"string","description":"Status of the signup process"}}},"contentType":"application/json","name":"UserSignupReply","title":"User signup reply","summary":"User signup reply message"}},"securitySchemes":{"JWTAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT"},"X509Auth":{"type":"X509","description":"X509 security scheme"},"apiKeyAuth":{"type":"apiKey","description":"API key security scheme","in":"user"},"basicAuth":{"type":"http","description":"Basic security scheme","scheme":"basic"},"httpApiAuth":{"type":"httpApiKey","description":"api_key","name":"API Key Sample","in":"header"},"oauth":{"type":"oauth2","description":"The oauth security descriptions","flows":{"clientCredentials":{"tokenUrl":"https://example.com/api/oauth/dialog","availableScopes":{"subscribe:auth_revocations":"Scope required for authorization revocation topic"}}},"scopes":["subscribe:auth_revocations"]},"saslAuth":{"type":"scramSha256","description":"SASL security scheme"},"symmetricEncryptionAuth":{"type":"symmetricEncryption","description":"Symmetric encryption security scheme"},"userPasswordAuth":{"type":"userPassword","description":"User password security scheme"}},"serverVariables":{"port":{"enum":["5671","5672"],"default":"5672"},"stage":{"default":"demo","description":"This value is assigned by the service provider, in this example\n`mycompany.com`\n"}},"parameters":{"userId":{"description":"Id of the user."}},"correlationIds":{"default":{"description":"Default Correlation ID","location":"$message.header#/correlationId"}},"replies":{"signupReply":{"address":{"$ref":"#/components/replyAddresses/signupReply"},"channel":{"$ref":"#/channels/userSignupReply"}}},"replyAddresses":{"signupReply":{"location":"$message.header#/replyTo"}},"externalDocs":{"infoDocs":{"description":"Find more info here","url":"https://example.com/docs"}},"tags":{"user":{"name":"user","description":"User-related messages"}},"operationTraits":{"binding":{"bindings":{"amqp":{"ack":false}}},"kafka":{"bindings":{"kafka":{"groupId":false}}}},"messageTraits":{"commonHeaders":{"headers":{"type":"object","properties":{"my-app-header":{"type":"integer","maximum":100,"minimum":0}}}}},"serverBindings":{"devAmqp":{"amqp":{"exchange":"my-exchange","queue":"my-queue"}}},"channelBindings":{"user":{"amqp":{"is":"queue","queue":{"exclusive":true}}}},"operationBindings":{"sendUser":{"amqp":{"ack":false}}},"messageBindings":{"user":{"amqp":{"bindingVersion":"0.3.0","contentEncoding":"gzip","messageType":"user.signup"}}}}}
+ test/golden/spec-examples/51-multi-format-schema-object---avro-yaml.json view
@@ -0,0 +1,1 @@+{"asyncapi":"3.1.0","info":{"title":"AsyncAPI","version":"1.x.x","description":"This is a very good base doc, probably.","termsOfService":"https://asyncapi.org/terms/","license":{"name":"Apache 2.0","url":"https://www.apache.org/licenses/LICENSE-2.0.html"},"tags":[{"name":"e-commerce"}],"externalDocs":{"description":"Find more info here","url":"https://www.asyncapi.org"}},"servers":{"production":{"host":"rabbitmq.in.mycompany.com:5672","protocol":"amqp","protocolVersion":"1.0","pathname":"/v1","description":"Production RabbitMQ broker (uses the `production` vhost).","title":"Production Server","summary":"Production environment server","security":[{"type":"http","scheme":"bearer"}],"tags":[{"name":"production","description":"Production environment"}],"externalDocs":{"description":"Additional documentation for the production server","url":"https://example.com/docs/production"},"bindings":{"amqp":{"exchange":"my-exchange","queue":"my-queue"}}},"rabbitmqInProd":{"host":"{prod}.in.mycompany.com","protocol":"amqp","description":"Production server"},"rabbitmqInStaging":{"host":"{stage}.in.mycompany.com","protocol":"amqp","description":"Staging server"},"staging":{"host":"rabbitmq.in.mycompany.com:5672","protocol":"amqp","protocolVersion":"1.0","pathname":"/v1","description":"Staging RabbitMQ broker (uses the `staging` vhost).","title":"Staging Server","summary":"Staging environment server","security":[{"type":"apiKey","description":"Provide your API key as the user and leave the password empty.","in":"user"}],"tags":[{"name":"staging","description":"Staging environment"}],"externalDocs":{"description":"Additional documentation for the staging server","url":"https://example.com/docs/staging"},"bindings":{"amqp":{"exchange":"my-exchange","queue":"my-queue"}}}},"channels":{"example":{"messages":{"myMessage":{"payload":{"schemaFormat":"application/vnd.apache.avro;version=1.9.0","schema":{"doc":"User information","fields":[{"name":"displayName","type":"string"},{"name":"age","type":"int"}],"name":"User","namespace":"com.company","type":"record"}}}}},"user":{"address":"users.{userId}","messages":{"userCompletedOrder":{"$ref":"#/components/messages/userCompletedOrder"},"userSignedUp":{"$ref":"#/components/messages/userSignedUp"}},"title":"Users channel","description":"This channel is used to exchange messages about user events.","servers":[{"$ref":"#/servers/production"}],"parameters":{"userId":{"$ref":"#/components/parameters/userId"}},"tags":[{"name":"user","description":"User-related messages"}],"externalDocs":{"description":"Find more info here","url":"https://example.com"},"bindings":{"amqp":{"is":"queue","queue":{"exclusive":true}}}},"userSignup":{"address":"users.signup","messages":{"userSignedUp":{"$ref":"#/components/messages/userSignedUp"}},"description":"Channel for user signups"},"userSignupReply":{"address":"users.signup.reply","messages":{"userSignedUpReply":{"payload":{"type":"object","properties":{"message":{"type":"string","description":"Additional information"},"status":{"type":"string","description":"Status of the signup process"}}},"summary":"User signup reply message"}},"description":"Channel for user signup replies"}},"operations":{"sendUserSignUp":{"action":"send","channel":{"$ref":"#/channels/user"},"title":"User sign up","summary":"Action to sign a user up.","description":"A longer description","security":[{"type":"oauth2","description":"The oauth security descriptions","flows":{"clientCredentials":{"tokenUrl":"https://example.com/api/oauth/dialog","availableScopes":{"subscribe:auth_revocations":"Scope required for authorization revocation topic"}}},"scopes":["subscribe:auth_revocations"]}],"tags":[{"name":"user"},{"name":"signup"},{"name":"register"}],"bindings":{"amqp":{"ack":false}},"traits":[],"messages":[{"$ref":"#/channels/user/messages/userSignedUp"}],"reply":{"address":{"location":"$message.header#/replyTo"},"channel":{"$ref":"#/channels/userSignupReply"},"messages":[{"$ref":"#/channels/userSignupReply/messages/userSignedUpReply"}]}}},"components":{"schemas":{"Address":{"type":"object","properties":{"city":{"type":"string"},"state":{"type":"string"},"street":{"type":"string"},"zip":{"type":"string"}}},"AvroExample":{"schemaFormat":"application/vnd.apache.avro+json;version=1.9.0","schema":{"fields":[{"name":"id","type":"int"},{"name":"name","type":"string"}],"name":"UserCreate","namespace":"com.example","type":"record"}},"Category":{"type":"object","properties":{"id":{"type":"integer","format":"int64"}}},"ComplexModel":{"type":"object","properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"}}},"ErrorModel":{"type":"object","properties":{"code":{"type":"integer","format":"int32"},"message":{"type":"string"}}},"Pet":{"type":"object","properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"},"tag":{"type":"string"}}},"signup":{"type":"object","required":["timestamp","source"],"properties":{"source":{"type":"string","description":"The source of the signup"},"timestamp":{"type":"string","description":"The timestamp of the signup","format":"date-time"}}},"userCreate":{"type":"object","required":["id","name","email"],"properties":{"email":{"type":"string","description":"The email of the user","format":"email"},"id":{"type":"string","description":"The ID of the user"},"name":{"type":"string","description":"The name of the user"}}}},"servers":{"development":{"host":"{stage}.in.mycompany.com","protocol":"amqp","description":"RabbitMQ broker","variables":{"stage":{"$ref":"#/components/serverVariables/stage"}},"security":[{"$ref":"#/components/securitySchemes/oauth"}],"bindings":{"$ref":"#/components/serverBindings/devAmqp"}}},"channels":{"user":{"address":"users.{userId}","messages":{"userSignedUp":{"$ref":"#/components/messages/userSignUp"}},"title":"Users channel","description":"This channel is used to exchange messages about user events.","servers":[{"$ref":"#/components/servers/development"}],"parameters":{"userId":{"$ref":"#/components/parameters/userId"}},"tags":[{"$ref":"#/components/tags/user"}],"externalDocs":{"$ref":"#/components/externalDocs/infoDocs"},"bindings":{"$ref":"#/components/channelBindings/user"}}},"operations":{"sendUserSignUp":{"action":"send","channel":{"$ref":"#/channels/user"},"title":"User sign up","bindings":{"$ref":"#/components/operationBindings/sendUser"},"traits":[{"$ref":"#/components/operationTraits/binding"}],"reply":{"$ref":"#/components/replies/signupReply"}}},"messages":{"userCompletedOrder":{"payload":{"type":"object","properties":{"amount":{"type":"number","description":"The total amount of the order"},"orderId":{"type":"string","description":"The ID of the order"},"userId":{"type":"string","description":"The ID of the user"}}},"contentType":"application/json","summary":"User completed order event"},"userSignUp":{"payload":{"$ref":"#/components/schemas/Category"},"correlationId":{"$ref":"#/components/correlationIds/default"},"summary":"Action to sign a user up.","bindings":{"$ref":"#/components/messageBindings/user"},"examples":[],"traits":[{"$ref":"#/components/messageTraits/commonHeaders"}]},"userSignedUp":{"headers":{"type":"object","properties":{"applicationInstanceId":{"type":"string","description":"Unique identifier for a given instance of the publishing application"},"correlationId":{"type":"string","description":"Correlation ID set by application"}}},"payload":{"type":"object","properties":{"signup":{"$ref":"#/components/schemas/signup"},"user":{"$ref":"#/components/schemas/userCreate"}}},"correlationId":{"description":"Default Correlation ID","location":"$message.header#/correlationId"},"contentType":"application/json","name":"UserSignup","title":"User signup","summary":"Action to sign a user up.","description":"A longer description","tags":[{"name":"user"},{"name":"signup"},{"name":"register"}],"examples":[{"headers":{"applicationInstanceId":"myInstanceId","correlationId":"my-correlation-id"},"payload":{"signup":{"someSignupKey":"someSignupValue"},"user":{"someUserKey":"someUserValue"}},"name":"SimpleSignup","summary":"A simple UserSignup example message"}],"traits":[{"$ref":"#/components/messageTraits/commonHeaders"}]},"userSignedUpReply":{"payload":{"type":"object","properties":{"message":{"type":"string","description":"Additional information"},"status":{"type":"string","description":"Status of the signup process"}}},"contentType":"application/json","name":"UserSignupReply","title":"User signup reply","summary":"User signup reply message"}},"securitySchemes":{"JWTAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT"},"X509Auth":{"type":"X509","description":"X509 security scheme"},"apiKeyAuth":{"type":"apiKey","description":"API key security scheme","in":"user"},"basicAuth":{"type":"http","description":"Basic security scheme","scheme":"basic"},"httpApiAuth":{"type":"httpApiKey","description":"api_key","name":"API Key Sample","in":"header"},"oauth":{"type":"oauth2","description":"The oauth security descriptions","flows":{"clientCredentials":{"tokenUrl":"https://example.com/api/oauth/dialog","availableScopes":{"subscribe:auth_revocations":"Scope required for authorization revocation topic"}}},"scopes":["subscribe:auth_revocations"]},"saslAuth":{"type":"scramSha256","description":"SASL security scheme"},"symmetricEncryptionAuth":{"type":"symmetricEncryption","description":"Symmetric encryption security scheme"},"userPasswordAuth":{"type":"userPassword","description":"User password security scheme"}},"serverVariables":{"stage":{"default":"demo","description":"This value is assigned by the service provider in this example of `mycompany.com`"}},"parameters":{"userId":{"description":"Id of the user."}},"correlationIds":{"default":{"description":"Default Correlation ID","location":"$message.header#/correlationId"}},"replies":{"signupReply":{"address":{"$ref":"#/components/replyAddresses/signupReply"},"channel":{"$ref":"#/channels/userSignupReply"}}},"replyAddresses":{"signupReply":{"location":"$message.header#/replyTo"}},"externalDocs":{"infoDocs":{"description":"Find more info here","url":"https://example.com/docs"}},"tags":{"user":{"name":"user","description":"User-related messages"}},"operationTraits":{"binding":{"bindings":{"amqp":{"ack":false}}},"kafka":{"bindings":{"kafka":{"groupId":false}}}},"messageTraits":{"commonHeaders":{"headers":{"type":"object","properties":{"my-app-header":{"type":"integer","maximum":100,"minimum":0}}}}},"serverBindings":{"devAmqp":{"amqp":{"exchange":"my-exchange","queue":"my-queue"}}},"channelBindings":{"user":{"amqp":{"is":"queue","queue":{"exclusive":true}}}},"operationBindings":{"sendUser":{"amqp":{"ack":false}}},"messageBindings":{"user":{"amqp":{"bindingVersion":"0.3.0","contentEncoding":"gzip","messageType":"user.signup"}}}}}
+ test/golden/spec-examples/52-schema-object---primitive-json.json view
@@ -0,0 +1,1 @@+{"type":"string","format":"email"}
+ test/golden/spec-examples/53-schema-object---primitive-yaml.json view
@@ -0,0 +1,1 @@+{"type":"string","format":"email"}
+ test/golden/spec-examples/54-schema-object---simple-model-json.json view
@@ -0,0 +1,1 @@+{"type":"object","required":["name"],"properties":{"address":{"$ref":"#/components/schemas/Address"},"age":{"type":"integer","minimum":0,"format":"int32"},"name":{"type":"string"}}}
+ test/golden/spec-examples/55-schema-object---simple-model-yaml.json view
@@ -0,0 +1,1 @@+{"type":"object","required":["name"],"properties":{"address":{"$ref":"#/components/schemas/Address"},"age":{"type":"integer","minimum":0,"format":"int32"},"name":{"type":"string"}}}
+ test/golden/spec-examples/56-schema-object---map-dictionary-model-json.json view
@@ -0,0 +1,1 @@+{"type":"object","additionalProperties":{"type":"string"}}
+ test/golden/spec-examples/57-schema-object---map-dictionary-model-yaml.json view
@@ -0,0 +1,1 @@+{"type":"object","additionalProperties":{"type":"string"}}
+ test/golden/spec-examples/58-schema-object---allowing-complex-model-json.json view
@@ -0,0 +1,1 @@+{"type":"object","additionalProperties":{"$ref":"#/components/schemas/ComplexModel"}}
+ test/golden/spec-examples/59-schema-object---allowing-complex-model-yaml.json view
@@ -0,0 +1,1 @@+{"type":"object","additionalProperties":{"$ref":"#/components/schemas/ComplexModel"}}
+ test/golden/spec-examples/6-license-object-yaml.json view
@@ -0,0 +1,1 @@+{"name":"Apache 2.0","url":"https://www.apache.org/licenses/LICENSE-2.0.html"}
+ test/golden/spec-examples/60-schema-object---with-examples-model-json.json view
@@ -0,0 +1,1 @@+{"type":"object","required":["name"],"examples":[{"id":1,"name":"Puma"}],"properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"}}}
+ test/golden/spec-examples/61-schema-object---with-examples-model-yaml.json view
@@ -0,0 +1,1 @@+{"type":"object","required":["name"],"examples":[{"id":1,"name":"Puma"}],"properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"}}}
+ test/golden/spec-examples/62-schema-object---with-boolean-model-json.json view
@@ -0,0 +1,1 @@+{"type":"object","required":["anySchema"],"properties":{"anySchema":true,"cannotBeDefined":false}}
+ test/golden/spec-examples/63-schema-object---with-boolean-model-yaml.json view
@@ -0,0 +1,1 @@+{"type":"object","required":["anySchema"],"properties":{"anySchema":true,"cannotBeDefined":false}}
+ test/golden/spec-examples/64-schema-object---with-composition-model-json.json view
@@ -0,0 +1,1 @@+{}
+ test/golden/spec-examples/65-schema-object---with-composition-model-yaml.json view
@@ -0,0 +1,1 @@+{}
+ test/golden/spec-examples/66-schema-object---with-polymorphism-model-json.json view
@@ -0,0 +1,1 @@+{}
+ test/golden/spec-examples/67-schema-object---with-polymorphism-model-yaml.json view
@@ -0,0 +1,1 @@+{}
+ test/golden/spec-examples/68-security-scheme-object---user-pass-json.json view
@@ -0,0 +1,1 @@+{"type":"userPassword"}
+ test/golden/spec-examples/69-security-scheme-object---user-pass-yaml.json view
@@ -0,0 +1,1 @@+{"type":"userPassword"}
+ test/golden/spec-examples/7-servers-object-json.json view
@@ -0,0 +1,1 @@+{"staging":{"host":"rabbitmq-staging.in.mycompany.com:5672","protocol":"amqp","protocolVersion":"0-9-1","description":"RabbitMQ broker for the staging environment.","tags":[{"name":"env:staging","description":"This environment is a replica of the production environment."}]},"production":{"host":"rabbitmq.in.mycompany.com:5672","protocol":"amqp","protocolVersion":"0-9-1","description":"RabbitMQ broker for the production environment.","tags":[{"name":"env:production","description":"This environment is the live environment available for final users."}]},"development":{"host":"localhost:5672","protocol":"amqp","protocolVersion":"0-9-1","description":"Development AMQP broker.","tags":[{"name":"env:development","description":"This environment is meant for developers to run their own tests."}]}}
+ test/golden/spec-examples/70-security-scheme-object---api-key-auth-json.json view
@@ -0,0 +1,1 @@+{"type":"apiKey","in":"user"}
+ test/golden/spec-examples/71-security-scheme-object---api-key-auth-yaml.json view
@@ -0,0 +1,1 @@+{"type":"apiKey","in":"user"}
+ test/golden/spec-examples/72-security-scheme-object---x-509-json.json view
@@ -0,0 +1,1 @@+{"type":"X509"}
+ test/golden/spec-examples/73-security-scheme-object---x-509-yaml.json view
@@ -0,0 +1,1 @@+{"type":"X509"}
+ test/golden/spec-examples/74-security-scheme-object---end-to-end-encryption-json.json view
@@ -0,0 +1,1 @@+{"type":"symmetricEncryption"}
+ test/golden/spec-examples/75-security-scheme-object---end-to-end-encryption-yaml.json view
@@ -0,0 +1,1 @@+{"type":"symmetricEncryption"}
+ test/golden/spec-examples/76-security-scheme-object---basic-json.json view
@@ -0,0 +1,1 @@+{"type":"http","scheme":"basic"}
+ test/golden/spec-examples/77-security-scheme-object---basic-yaml.json view
@@ -0,0 +1,1 @@+{"type":"http","scheme":"basic"}
+ test/golden/spec-examples/78-security-scheme-object---api-key-json.json view
@@ -0,0 +1,1 @@+{"type":"httpApiKey","name":"api_key","in":"header"}
+ test/golden/spec-examples/79-security-scheme-object---api-key-yaml.json view
@@ -0,0 +1,1 @@+{"type":"httpApiKey","name":"api_key","in":"header"}
+ test/golden/spec-examples/8-servers-object-yaml.json view
@@ -0,0 +1,1 @@+{"staging":{"host":"rabbitmq-staging.in.mycompany.com:5672","protocol":"amqp","protocolVersion":"0-9-1","description":"RabbitMQ broker for the staging environment.","tags":[{"name":"env:staging","description":"This environment is a replica of the production environment."}]},"production":{"host":"rabbitmq.in.mycompany.com:5672","protocol":"amqp","protocolVersion":"0-9-1","description":"RabbitMQ broker for the production environment.","tags":[{"name":"env:production","description":"This environment is the live environment available for final users."}]},"development":{"host":"localhost:5672","protocol":"amqp","protocolVersion":"0-9-1","description":"Development AMQP broker.","tags":[{"name":"env:development","description":"This environment is meant for developers to run their own tests."}]}}
+ test/golden/spec-examples/80-security-scheme-object---jwt-json.json view
@@ -0,0 +1,1 @@+{"type":"http","scheme":"bearer","bearerFormat":"JWT"}
+ test/golden/spec-examples/81-security-scheme-object---jwt-yaml.json view
@@ -0,0 +1,1 @@+{"type":"http","scheme":"bearer","bearerFormat":"JWT"}
+ test/golden/spec-examples/82-security-scheme-object---implicity-oauth2-json.json view
@@ -0,0 +1,1 @@+{"type":"oauth2","flows":{"implicit":{"authorizationUrl":"https://example.com/api/oauth/dialog","availableScopes":{"read:pets":"read your pets","write:pets":"modify pets in your account"}}},"scopes":["write:pets"]}
+ test/golden/spec-examples/83-security-scheme-object---implicity-oauth2-yaml.json view
@@ -0,0 +1,1 @@+{"type":"oauth2","flows":{"implicit":{"authorizationUrl":"https://example.com/api/oauth/dialog","availableScopes":{"read:pets":"read your pets","write:pets":"modify pets in your account"}}},"scopes":["write:pets"]}
+ test/golden/spec-examples/84-security-scheme-object---sasl-json.json view
@@ -0,0 +1,1 @@+{"type":"scramSha512"}
+ test/golden/spec-examples/85-security-scheme-object---sasl-yaml.json view
@@ -0,0 +1,1 @@+{"type":"scramSha512"}
+ test/golden/spec-examples/86-security-scheme-oauth-flow-object-json.json view
@@ -0,0 +1,1 @@+{"tokenUrl":"https://example.com/api/oauth/token","availableScopes":{"read:pets":"read your pets","write:pets":"modify pets in your account"}}
+ test/golden/spec-examples/87-security-scheme-oauth-flow-object-yaml.json view
@@ -0,0 +1,1 @@+{"tokenUrl":"https://example.com/api/oauth/token","availableScopes":{"read:pets":"read your pets","write:pets":"modify pets in your account"}}
+ test/golden/spec-examples/88-message-correlation-id-object-json.json view
@@ -0,0 +1,1 @@+{"description":"Default Correlation ID","location":"$message.header#/correlationId"}
+ test/golden/spec-examples/89-message-correlation-id-object-yaml.json view
@@ -0,0 +1,1 @@+{"description":"Default Correlation ID","location":"$message.header#/correlationId"}
+ test/golden/spec-examples/9-server-object-json.json view
@@ -0,0 +1,1 @@+{"host":"kafka.in.mycompany.com:9092","protocol":"kafka","protocolVersion":"3.2","description":"Production Kafka broker."}