From e821d528fcceeb8548ef592ff9af0d41d0645841 Mon Sep 17 00:00:00 2001 From: "jonas-lt@live.dk" Date: Fri, 28 Jul 2023 11:23:46 +0200 Subject: [PATCH 01/15] copy over guide --- components/Asyncapi3Comparison.js | 549 ++++++++++++++++++++++++ pages/docs/migration/_section.md | 4 + pages/docs/migration/migrating-to-v3.md | 393 +++++++++++++++++ 3 files changed, 946 insertions(+) create mode 100644 components/Asyncapi3Comparison.js create mode 100644 pages/docs/migration/_section.md create mode 100644 pages/docs/migration/migrating-to-v3.md diff --git a/components/Asyncapi3Comparison.js b/components/Asyncapi3Comparison.js new file mode 100644 index 00000000000..9362db83628 --- /dev/null +++ b/components/Asyncapi3Comparison.js @@ -0,0 +1,549 @@ +import React, { useState } from 'react'; + +// eslint-disable-next-line react/prop-types +export function Asyncapi3Comparison({ className = '' }) { + const [hoverState, setHoverState] = useState({ + Info: false, + Servers: false, + Paths: false, + PathItem: true, + Summary: false, + Operation: false, + Message: false, + Tags: false, + External: false, + Components: false, + Id: false, + Path: false, + Host: false + }); + + return ( +
+
+

AsyncAPI 2.x

+ +
+
setHoverState(prevState => ({ ...prevState, Info: true }))} onMouseLeave={() => setHoverState({ Info: false })}> + Info +
+
+
setHoverState(prevState => ({ ...prevState, Tags: true }))} onMouseLeave={() => setHoverState({ Tags: false })}> +

Tags

+
+
setHoverState(prevState => ({ ...prevState, External: true }))} onMouseLeave={() => setHoverState({ External: false })}> +

External Docs

+
+
+
+ Servers +
+
+ Server +
+
setHoverState(prevState => ({ ...prevState, Host: true, Path: true }))} onMouseLeave={() => setHoverState({ Host: false, Path: false })}> +

Url

+
+
+
+
+
+
setHoverState(prevState => ({ ...prevState, Paths: true }))} onMouseLeave={() => setHoverState({ Paths: false })}> + Channels + +
+
setHoverState(prevState => ({ ...prevState, PathItem: true }))} onMouseLeave={() => setHoverState({ PathItem: false })}> + Channel Item + +
+
setHoverState(prevState => ({ ...prevState, Operation: true }))} onMouseLeave={() => setHoverState({ Operation: false })}> + Operation (Publish and Subscribe) + +
+
+
setHoverState(prevState => ({ ...prevState, Message: true }))} onMouseLeave={() => setHoverState({ Message: false })}> + Messages +
+ Message + +
+ Headers +
+
+ Payload +
+
+
+
+
+
+
+
+
+
+
+
+
+

AsyncAPI 3.0

+ +
+
setHoverState(prevState => ({ ...prevState, Info: true }))} onMouseLeave={() => setHoverState({ Info: false })}> + Info +
+
setHoverState(prevState => ({ ...prevState, Tags: true }))} onMouseLeave={() => setHoverState({ Tags: false })}> +

Tags

+
+
setHoverState(prevState => ({ ...prevState, External: true }))} onMouseLeave={() => setHoverState({ External: false })}> +

External Docs

+
+
+
+
+ Servers +
+
+ Server +
+
setHoverState(prevState => ({ ...prevState, Host: true }))} onMouseLeave={() => setHoverState({ Host: false })}> +

Host

+
+
setHoverState(prevState => ({ ...prevState, Path: true }))} onMouseLeave={() => setHoverState({ Path: false })}> +

Pathname

+
+
+
+
+
+
setHoverState(prevState => ({ ...prevState, Paths: true }))} onMouseLeave={() => setHoverState({ Paths: false })}> + Channels + +
setHoverState(prevState => ({ ...prevState, PathItem: true }))} onMouseLeave={() => setHoverState({ PathItem: false })}> + Channel Item +
+
+ address +
+
+
setHoverState(prevState => ({ ...prevState, Message: true }))} onMouseLeave={() => setHoverState({ Message: false })}> + Messages +
+ Message + +
+ Headers +
+
+ Payload +
+
+
+
+
+
+
+
setHoverState(prevState => ({ ...prevState, Operation: true }))} onMouseLeave={() => setHoverState({ Operation: false })}> + Operations +
+
+ Operation + +
+
+ action (send or receive) +
+
+ channel +
+
+ messages +
+
+
+
+
+
+
+
+ ) +} + +// eslint-disable-next-line react/prop-types +export function Asyncapi3ChannelComparison({ className = '' }) { + const [hoverState, setHoverState] = useState({ + Paths: false, + PathItem: false, + Operation: false, + Message: false, + }); + + return ( +
+
+

AsyncAPI 2.x

+ +
+
setHoverState(prevState => ({ ...prevState, Paths: true }))} onMouseLeave={() => setHoverState({ Paths: false })}> + Channels + +
+
setHoverState(prevState => ({ ...prevState, PathItem: true }))} onMouseLeave={() => setHoverState({ PathItem: false })}> + Channel Item + +
+
setHoverState(prevState => ({ ...prevState, Operation: true }))} onMouseLeave={() => setHoverState({ Operation: false })}> + Operation (Publish and Subscribe) + +
+
+
setHoverState(prevState => ({ ...prevState, Message: true }))} onMouseLeave={() => setHoverState({ Message: false })}> + Messages +
+ Message + +
+ Headers +
+
+ Payload +
+
+
+
+
+
+
+
+
+
+
+
+
+

AsyncAPI 3.0

+ +
+
setHoverState(prevState => ({ ...prevState, Paths: true }))} onMouseLeave={() => setHoverState({ Paths: false })}> + Channels + +
setHoverState(prevState => ({ ...prevState, PathItem: true }))} onMouseLeave={() => setHoverState({ PathItem: false })}> + Channel Item +
+
setHoverState(prevState => ({ ...prevState, Message: true }))} onMouseLeave={() => setHoverState({ Message: false })}> + Messages +
+ Message + +
+ Headers +
+
+ Payload +
+
+
+
+
+
+
setHoverState(prevState => ({ ...prevState, Operation: true }))} onMouseLeave={() => setHoverState({ Operation: false })}> + Operations +
+
+ Operation +
+
+ action (send or receive) +
+
+ channel +
+
+ messages +
+
+
+
+
+
+
+
+ ) +} + +// eslint-disable-next-line react/prop-types +export function Asyncapi3IdAndAddressComparison({ className = '' }) { + const [hoverState, setHoverState] = useState({ + Paths: false, + PathItem: false, + }); + + return ( +
+
+

AsyncAPI 2.x

+ +
+
setHoverState(prevState => ({ ...prevState, Paths: true }))} onMouseLeave={() => setHoverState({ Paths: false })}> + Channels +
setHoverState(prevState => ({ ...prevState, PathItem: true }))} onMouseLeave={() => setHoverState({ PathItem: false })}> + Channel Item +
+
+
+
+
+

AsyncAPI 3.0

+ +
+
setHoverState(prevState => ({ ...prevState, Paths: true }))} onMouseLeave={() => setHoverState({ Paths: false })}> + Channels + +
setHoverState(prevState => ({ ...prevState, PathItem: true }))} onMouseLeave={() => setHoverState({ PathItem: false })}> + Channel Item + +
+
+ address +
+
+
+
+
+
+
+ ) +} + + +export function Asyncapi3ServerComparison({ className = '' }) { + const [hoverState, setHoverState] = useState({ + Host: false, + path: false, + Servers: false, + }); + + return ( +
+
+

AsyncAPI 2.x

+ +
+
+ Servers +
+
+ Server +
+
setHoverState(prevState => ({ ...prevState, Host: true, Path: true }))} onMouseLeave={() => setHoverState({ Host: false, Path: false })}> +

Url

+
+
+
+
+
+
+
+
+

AsyncAPI 3.0

+ +
+
+ Servers +
+
+ Server +
+
setHoverState(prevState => ({ ...prevState, Host: true }))} onMouseLeave={() => setHoverState({ Host: false })}> +

Host

+
+
setHoverState(prevState => ({ ...prevState, Path: true }))} onMouseLeave={() => setHoverState({ Path: false })}> +

Pathname

+
+
+
+
+
+
+
+
+ ) +} + +export function Asyncapi3MetaComparison({ className = '' }) { + const [hoverState, setHoverState] = useState({ + Info: false, + Tags: false, + External: false + }); + + return ( +
+
+

AsyncAPI 2.x

+ +
+
setHoverState(prevState => ({ ...prevState, Info: true }))} onMouseLeave={() => setHoverState({ Info: false })}> + Info +
+
+
setHoverState(prevState => ({ ...prevState, Tags: true }))} onMouseLeave={() => setHoverState({ Tags: false })}> +

Tags

+
+
setHoverState(prevState => ({ ...prevState, External: true }))} onMouseLeave={() => setHoverState({ External: false })}> +

External Docs

+
+
+
+
+
+

AsyncAPI 3.0

+ +
+
setHoverState(prevState => ({ ...prevState, Info: true }))} onMouseLeave={() => setHoverState({ Info: false })}> + Info +
+
setHoverState(prevState => ({ ...prevState, Tags: true }))} onMouseLeave={() => setHoverState({ Tags: false })}> +

Tags

+
+
setHoverState(prevState => ({ ...prevState, External: true }))} onMouseLeave={() => setHoverState({ External: false })}> +

External Docs

+
+
+
+
+
+
+ ) +} + + +// eslint-disable-next-line react/prop-types +export function Asyncapi3OperationComparison({ className = '' }) { + return ( +
+
+

AsyncAPI 2.x

+ +
+
+ Channels + +
+
+ Channel Item + +
+
+ Operation (Publish and Subscribe) +
+
+
+
+
+
+
+
+

AsyncAPI 3.0

+ +
+
+ Operations +
+
+ Operation + +
+
+ action (send or receive) +
+
+
+
+
+
+
+
+ ) +} + + +// eslint-disable-next-line react/prop-types +export function Asyncapi3SchemaFormatComparison({ className = '' }) { + const [hoverState, setHoverState] = useState({ + SchemaFormat: false, + Payload: false + }); + + return ( +
+
+

AsyncAPI 2.x

+ +
+
+ components | channels + +
+
+ messages + +
+
+ message +
+
setHoverState(prevState => ({ ...prevState, SchemaFormat: true }))} onMouseLeave={() => setHoverState({ SchemaFormat: false })}> + schemaFormat +
+ +
setHoverState(prevState => ({ ...prevState, Payload: true }))} onMouseLeave={() => setHoverState({ Payload: false })}> + payload +
+
+ schema +
+
+
+
+
+
+
+
+
+
+
+
+

AsyncAPI 3.0

+ +
+
+ components | channels + +
+
+ messages + +
+
+ message +
+
setHoverState(prevState => ({ ...prevState, Payload: true }))} onMouseLeave={() => setHoverState({ Payload: false })}> + payload + +
+
setHoverState(prevState => ({ ...prevState, SchemaFormat: true }))} onMouseLeave={() => setHoverState({ SchemaFormat: false })}> + schemaFormat +
+
+ schema +
+
+
+
+
+
+
+
+
+
+
+
+ ) +} diff --git a/pages/docs/migration/_section.md b/pages/docs/migration/_section.md new file mode 100644 index 00000000000..12839bbb260 --- /dev/null +++ b/pages/docs/migration/_section.md @@ -0,0 +1,4 @@ +--- +title: Migrations +weight: 3 +--- \ No newline at end of file diff --git a/pages/docs/migration/migrating-to-v3.md b/pages/docs/migration/migrating-to-v3.md new file mode 100644 index 00000000000..aef60528cfa --- /dev/null +++ b/pages/docs/migration/migrating-to-v3.md @@ -0,0 +1,393 @@ +--- +title: "Migrating to v3" +--- +Migration to a new major version is always difficult, and AsyncAPI is no exception, but we want to provide as smooth a transition as possible, and this is where this document comes in. It shows the breaking changes between AsyncAPI v2 and v3 in an interactive manner. + +If you are just looking to update your AsyncAPI document, then we suggest you use the [AsyncAPI converter](https://github.com/asyncapi/converter-js). You can do this directly in the CLI with: + +```bash +asyncapi convert asyncapi.json --output=asyncapi_v3.json --target-version=3.0.0 +``` + +For a detailed read-through about all the changes (non-breaking as well), please do read [the release notes for v3](/blog/release-notes-3.0.0) before this, as it will give you some more context about the changes in v3. + +import {Asyncapi3Comparison, Asyncapi3ChannelComparison, Asyncapi3IdAndAddressComparison, Asyncapi3MetaComparison, Asyncapi3OperationComparison,Asyncapi3SchemaFormatComparison, Asyncapi3ServerComparison} from '../../../components/Asyncapi3Comparison' + + + +### Metadata being moved + +In v2 two properties, `tags` and `externalDocs` was placed outside of the meta information object `info`, this has been moved in v3 to stay consistent. + + + +```yml +asyncapi: 2.6.0 +info: + ... +externalDocs: + description: Find more info here + url: https://www.asyncapi.org +tags: + - name: e-commerce +``` + +```yml +asyncapi: 3.0.0 +info: + externalDocs: + description: Find more info here + url: https://www.asyncapi.org + tags: + - name: e-commerce +``` + +### Server URL splitting up +A confusion that arrived from time to time, was what the URL of a server should include. + + + +In v2, connecting to a server was always defined as one long URL, sometimes even duplicating information such as protocol. + +In v3, the `url` property has now been split up into `host`, `pathname`, and as in v2 `protocol`. Making the information explicit. +```yml +asyncapi: 2.6.0 +servers: + production: + url: "amqp://rabbitmq.in.mycompany.com:5672/production" + protocol: "amqp" +``` + +```yml +asyncapi: 3.0.0 +servers: + production: + host: "rabbitmq.in.mycompany.com:5672", + pathname: "/production", + protocol: "amqp", +``` + +### Operation, Channel, and message decoupling + +The decoupling between operations, channels, and messages, is by far the most intrusive breaking change in v3 that completely splits out how they are related to each other. + + + +In v2, it was impossible to reuse channels, and impossible to have more than one operation per channel, i.e. operation variants. + +In v3, this is now possible, with the mindset, a channel and message should be detached from the operations performed. + +For any message broker, for example, Kafka, this is the same as defining topics and the messages it contains. For REST interfaces it's all the paths and corresponding messages across all request types. For WebSocket, it's all the messages flowing through the WebSocket server. For Socket.Io, it defines all the rooms and messages therein. + +This change makes the channels reusable across multiple AsyncAPI documents, each performing a slightly different action. + +```yml +asyncapi: 2.6.0 +... +channels: + user/signedup: + publish: + message: + payload: + type: object + properties: + displayName: + type: string + description: Name of the user +``` + +```yml +asyncapi: 3.0.0 +... +channels: + UserSignup: + address: "user/signedup" + messages: + UserMessage: + payload: + type: object + properties: + displayName: + type: string + description: Name of the user +operations: + ConsumeUserSignups: + action: receive + channel: + $ref: "#/channels/UserSignup" +``` + +Read more about the publish and subscribe confusion under [Operation keywords](#operation-keywords). + +### Channel address and object id's + +Another breaking change is that the object id of a channel is no longer the channel path, instead, it's an arbitrary unique id, and instead, channel paths are described with the `address` property. + + + +In v2, the address/topic/path of the channel was also the ID of the channel, which complicated reusability and simply didn't allow you to define certain use cases where you were using the same address for different contexts. + +In v3, the address/topic/path is now located in an `address` property, while the ID of the channel can be anything. + +```yml +asyncapi: 2.6.0 +... +channels: + test/path: + ... +``` + +```yml +asyncapi: 3.0.0 +channels: + testPathChannel: + address: "test/path" +``` + +### Operation keywords + +Another breaking change is that operations no longer are defined with `publish` and `subscribe` and their opposite meaning for your application. Instead, you define your application behavior directly, with `send` and `receive` through an `action` property. + + + +In v2, the `publish` and `subscribe` operations were always a great source of confusion, even to folks that knew the confusion. + +Because if you define `publish` it means others may `publish` to this channel because you (the application) subscribe to it, and `subscribe` meant others may subscribe to this channel because you publish to it. + +In v3, the two operations are completely removed and replaced with an `action` property, that explicitly says what you (the application) do. Nothing about `others` and different perspectives to take into account. + +For more information about this publish and subscribe confusion here are some more reading materials: +- Fran Méndez's [Proposal to solve publish/subscribe confusion](https://github.com/asyncapi/spec/issues/618) +- Nic Townsend's blog post [Demystifying the Semantics of Publish and Subscribe](https://www.asyncapi.com/blog/publish-subscribe-semantics) + +Here is an example where, for simplicity, the application both consumes and produces messages to the test channel. + +```yml +asyncapi: 2.6.0 +... +channels: + test/path: + subscribe: + ... + publish: + ... +``` + +```yml +asyncapi: 3.0.0 +channels: + testPathChannel: + address: "test/path" + ... +operations: + publishToTestPath: + action: send + channel: + $ref: "#/channels/testPathChannel" + consumeFromTestPath: + action: receive + channel: + $ref: "#/channels/testPathChannel" +``` + +### Messages instead of message +In v2, if you wanted to define channels to have one or more messages, you would do it with `oneOf`, or if just a single message. + +In v3, messages are now defined with an object, if you want a channel to have one or more messages, you just define multiple key/value pairs, or if a single message, it's just a single key/value pair. + +```yml +asyncapi: 2.6.0 +... +channels: + user/signedup: + message: + oneOf: + - ... + - ... + +asyncapi: 2.6.0 +... +channels: + user/signedup: + message: + ... +``` + +```yml +asyncapi: 3.0.0 +... +channels: + UserSignup: + address: user/signedup + messages: + UserMessage: + ... + UserMessage2: + ... + +asyncapi: 3.0.0 +... +channels: + UserSignup: + address: user/signedup + messages: + UserMessage: + ... +``` + +### Unifying explicit and implicit references + +In v2, it was possible to do implicit references in some places, for example for server security configuration, it was by name which referred to a security requirement Object in components - And for a channel to reference global servers by name. + +In v3, this information MUST be explicit references. This did mean that we had to slightly change the Server Object `security` property, which is now an array instead of an object. We then moved the information about needed scopes for OAuth and OpenID Connect to the Security Scheme Object. + +```yml +asyncapi: 2.6.0 +servers: + production: + ... + security: + oauth_test: ["write:pets"] +... +channels: + test/path: + severs: + - production +components: + securitySchemes: + oauth_test: + 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' +``` + +```yml +asyncapi: 3.0.0 +servers: + production: + ... + security: + - $ref: "#/components/securitySchemes/oauth_test" +... +channels: + test/path: + severs: + - $ref: "#/servers/production" +components: + securitySchemes: + oauth_test: + 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" +``` + +### New trait behavior +Traits in v2 always replaced any duplicate properties that were defined both in traits and the associated object. This meant for example if the message traits defined headers and the message object did as well, only the message trait headers would be applied because it overwrote anything you wrote in the message object. + +In v3, this has now been changed so that main objects have a higher priority than what ever you define in traits. This applies to traits in both operation and message objects. + +Let's go through a few examples, for example here with the message object and associated traits: +```yml +messageId: userSignup +description: A longer description. +payload: + $ref: '#/components/schemas/userSignupPayload' +traits: + - summary: Action to sign a user up. + description: Description from trait. +``` + +After traits have been applied in v2, the full message object would look like this, take notice of how the `description` was overwritten: +```yml +messageId: userSignup +summary: Action to sign a user up. +description: Description from trait. +payload: + $ref: '#/components/schemas/userSignupPayload' +``` +This is the default behavior of the [JSON Merge Patch](https://tools.ietf.org/html/rfc7386) algorithm we use. + +However, in v3, we enforce a rule that `A property on a trait MUST NOT override the same property on the target object`. This means that in v3, after traits have been applied this is the full message object in v3: +```yml +messageId: userSignup +summary: Action to sign a user up. +description: A longer description. # it's still description from "main" object +payload: + $ref: '#/components/schemas/userSignupPayload' +``` +Take notice how the `description` is now no longer overwritten. + +### Schema format and schemas + +With schemas, one thing that has always been impossible was reusing schemas with different schema formats. + + + +In v2, the information about which schema the payload is defined with is located under the message object and not directly associated with the schema itself. This makes reusability impossible because the two pieces of information are not directly associated with each other. + +So in v3, we add [a multi-format schema object](https://www.asyncapi.com/docs/reference/specification/v3.0.0-next-major-spec.12#multiFormatSchemaObject), encapsulating this information together. That means that if you anywhere use `schemaFormat`, you have to change the schema like below. + + +```yml +asyncapi: 2.6.0 +... +channels: + user/signedup: + publish: + message: + schemaFormat: 'application/vnd.apache.avro;version=1.9.0' + payload: + type: record + name: User + namespace: com.company + doc: User information + fields: + - name: displayName + type: string +``` + +```yml +asyncapi: 3.0.0 +... +channels: + UserSignup: + address: user/signedup + messages: + userSignup: + 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 +``` + +### Optional channels +In v3 channels are now completely optional, which means that you dont have to define channels as an empty object as you did in v2. + +```yml +asyncapi: 2.6.0 +... +channels: {} +``` + +```yml +asyncapi: 3.0.0 +... +``` From d6f01c563f4328ddfd7b74f3c69227337b443fab Mon Sep 17 00:00:00 2001 From: "jonas-lt@live.dk" Date: Fri, 28 Jul 2023 11:27:12 +0200 Subject: [PATCH 02/15] update links --- pages/docs/migration/migrating-to-v3.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pages/docs/migration/migrating-to-v3.md b/pages/docs/migration/migrating-to-v3.md index aef60528cfa..a0bf35b8069 100644 --- a/pages/docs/migration/migrating-to-v3.md +++ b/pages/docs/migration/migrating-to-v3.md @@ -27,7 +27,7 @@ info: ... externalDocs: description: Find more info here - url: https://www.asyncapi.org + url: https://www.asyncapi.com tags: - name: e-commerce ``` @@ -37,7 +37,7 @@ asyncapi: 3.0.0 info: externalDocs: description: Find more info here - url: https://www.asyncapi.org + url: https://www.asyncapi.com tags: - name: e-commerce ``` From b9549e764d86b0d33d91f5f28794bc7ec9b4829a Mon Sep 17 00:00:00 2001 From: "jonas-lt@live.dk" Date: Fri, 28 Jul 2023 11:42:35 +0200 Subject: [PATCH 03/15] update links --- pages/docs/migration/migrating-to-v3.md | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/pages/docs/migration/migrating-to-v3.md b/pages/docs/migration/migrating-to-v3.md index a0bf35b8069..1b0e6e50297 100644 --- a/pages/docs/migration/migrating-to-v3.md +++ b/pages/docs/migration/migrating-to-v3.md @@ -17,7 +17,7 @@ import {Asyncapi3Comparison, Asyncapi3ChannelComparison, Asyncapi3IdAndAddressCo ### Metadata being moved -In v2 two properties, `tags` and `externalDocs` was placed outside of the meta information object `info`, this has been moved in v3 to stay consistent. +In v2 two properties, `tags` and `externalDocs` was placed outside of the [Info Object](https://www.asyncapi.com/docs/reference/specification/v3.0.0-next-major-spec.12#infoObject) `info`, this has been moved in v3 to stay consistent. @@ -43,11 +43,11 @@ info: ``` ### Server URL splitting up -A confusion that arrived from time to time, was what the URL of a server should include. +A confusion that arrived from time to time, was what the URL of a [Server Object](https://www.asyncapi.com/docs/reference/specification/v3.0.0-next-major-spec.12#serverObject) should include. -In v2, connecting to a server was always defined as one long URL, sometimes even duplicating information such as protocol. +In v2, defining the URL was always as one long URL, sometimes even duplicating information such as protocol. In v3, the `url` property has now been split up into `host`, `pathname`, and as in v2 `protocol`. Making the information explicit. ```yml @@ -67,7 +67,7 @@ servers: protocol: "amqp", ``` -### Operation, Channel, and message decoupling +### Operation, channel, and message decoupling The decoupling between operations, channels, and messages, is by far the most intrusive breaking change in v3 that completely splits out how they are related to each other. @@ -119,9 +119,9 @@ operations: Read more about the publish and subscribe confusion under [Operation keywords](#operation-keywords). -### Channel address and object id's +### Channel address and channel key -Another breaking change is that the object id of a channel is no longer the channel path, instead, it's an arbitrary unique id, and instead, channel paths are described with the `address` property. +Another breaking change is that the channel key is no longer the channel path, instead, it's an arbitrary unique id, and instead, channel paths are described with the `address` property as part of the [Channel Object](https://www.asyncapi.com/docs/reference/specification/v3.0.0-next-major-spec.12#channelObject). @@ -146,7 +146,7 @@ channels: ### Operation keywords -Another breaking change is that operations no longer are defined with `publish` and `subscribe` and their opposite meaning for your application. Instead, you define your application behavior directly, with `send` and `receive` through an `action` property. +Another breaking change is that operations no longer are defined with `publish` and `subscribe` and their opposite meaning for your application. Instead, you define your application behavior directly, with `send` and `receive` through an `action` property in the [Operation Object](https://www.asyncapi.com/docs/reference/specification/v3.0.0-next-major-spec.12#operationObject). @@ -193,7 +193,7 @@ operations: ### Messages instead of message In v2, if you wanted to define channels to have one or more messages, you would do it with `oneOf`, or if just a single message. -In v3, messages are now defined with an object, if you want a channel to have one or more messages, you just define multiple key/value pairs, or if a single message, it's just a single key/value pair. +In v3, messages are now defined with the [Messages Object](https://www.asyncapi.com/docs/reference/specification/v3.0.0-next-major-spec.12#messagesObject), if you want a channel to have one or more messages, you just define multiple key/value pairs, or if a single message, it's just a single key/value pair. ```yml asyncapi: 2.6.0 @@ -237,9 +237,9 @@ channels: ### Unifying explicit and implicit references -In v2, it was possible to do implicit references in some places, for example for server security configuration, it was by name which referred to a security requirement Object in components - And for a channel to reference global servers by name. +In v2, it was possible to do implicit references in some places, for example for server security configuration, it was by name which referred to a [Security Schema Object](https://www.asyncapi.com/docs/reference/specification/v2.6.0#securitySchemeObject) in components - And for a channel to reference global servers by name. -In v3, this information MUST be explicit references. This did mean that we had to slightly change the Server Object `security` property, which is now an array instead of an object. We then moved the information about needed scopes for OAuth and OpenID Connect to the Security Scheme Object. +In v3, this information MUST be explicit references. This did mean that we had to slightly change the [Server Object](https://www.asyncapi.com/docs/reference/specification/v3.0.0-next-major-spec.12#serverObject) `security` property, which is now an array instead of an object. We then moved the information about needed scopes for OAuth and OpenID Connect to the [Security Scheme Object](https://www.asyncapi.com/docs/reference/specification/v3.0.0-next-major-spec.12#securitySchemeObject). ```yml asyncapi: 2.6.0 @@ -294,7 +294,7 @@ components: ``` ### New trait behavior -Traits in v2 always replaced any duplicate properties that were defined both in traits and the associated object. This meant for example if the message traits defined headers and the message object did as well, only the message trait headers would be applied because it overwrote anything you wrote in the message object. +Traits in v2 always replaced any duplicate properties that were defined both in traits and the associated object. This meant for example if the message traits defined headers and the message object did as well, only the message trait headers would be applied because it overwrote anything you wrote in the Message Object. In v3, this has now been changed so that main objects have a higher priority than what ever you define in traits. This applies to traits in both operation and message objects. From 14efa915ff24c79981265efd9375c79603c5009e Mon Sep 17 00:00:00 2001 From: Jonas Lagoni Date: Mon, 31 Jul 2023 11:45:39 +0200 Subject: [PATCH 04/15] Update pages/docs/migration/migrating-to-v3.md Co-authored-by: Animesh Kumar --- pages/docs/migration/migrating-to-v3.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pages/docs/migration/migrating-to-v3.md b/pages/docs/migration/migrating-to-v3.md index 1b0e6e50297..42b8cf719b4 100644 --- a/pages/docs/migration/migrating-to-v3.md +++ b/pages/docs/migration/migrating-to-v3.md @@ -49,7 +49,7 @@ A confusion that arrived from time to time, was what the URL of a [Server Object In v2, defining the URL was always as one long URL, sometimes even duplicating information such as protocol. -In v3, the `url` property has now been split up into `host`, `pathname`, and as in v2 `protocol`. Making the information explicit. +In v3, the `url` property has now been split up into `host`, `pathname`, and as in v2 `protocol`, making the information explicit. ```yml asyncapi: 2.6.0 servers: From de6510a1db2512290c9e3d6a9b23f9eb68cdea69 Mon Sep 17 00:00:00 2001 From: Jonas Lagoni Date: Mon, 31 Jul 2023 12:02:11 +0200 Subject: [PATCH 05/15] Apply suggestions from code review Co-authored-by: Animesh Kumar --- pages/docs/migration/migrating-to-v3.md | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/pages/docs/migration/migrating-to-v3.md b/pages/docs/migration/migrating-to-v3.md index 42b8cf719b4..3525d240fff 100644 --- a/pages/docs/migration/migrating-to-v3.md +++ b/pages/docs/migration/migrating-to-v3.md @@ -121,7 +121,7 @@ Read more about the publish and subscribe confusion under [Operation keywords](# ### Channel address and channel key -Another breaking change is that the channel key is no longer the channel path, instead, it's an arbitrary unique id, and instead, channel paths are described with the `address` property as part of the [Channel Object](https://www.asyncapi.com/docs/reference/specification/v3.0.0-next-major-spec.12#channelObject). +Another breaking change is that the channel key is no longer the channel path, instead, it's an arbitrary unique ID, and instead, channel paths are described with the `address` property as part of the [Channel Object](https://www.asyncapi.com/docs/reference/specification/v3.0.0-next-major-spec.12#channelObject). @@ -146,7 +146,7 @@ channels: ### Operation keywords -Another breaking change is that operations no longer are defined with `publish` and `subscribe` and their opposite meaning for your application. Instead, you define your application behavior directly, with `send` and `receive` through an `action` property in the [Operation Object](https://www.asyncapi.com/docs/reference/specification/v3.0.0-next-major-spec.12#operationObject). +Another breaking change is that operations no longer are defined with `publish` and `subscribe` and their opposite meaning for your application. Instead, you define your application behavior directly with `send` and `receive` through an `action` property in the [Operation Object](https://www.asyncapi.com/docs/reference/specification/v3.0.0-next-major-spec.12#operationObject). @@ -156,7 +156,7 @@ Because if you define `publish` it means others may `publish` to this channel be In v3, the two operations are completely removed and replaced with an `action` property, that explicitly says what you (the application) do. Nothing about `others` and different perspectives to take into account. -For more information about this publish and subscribe confusion here are some more reading materials: +For more information about this publish and subscribe confusion, here are some more reading materials: - Fran Méndez's [Proposal to solve publish/subscribe confusion](https://github.com/asyncapi/spec/issues/618) - Nic Townsend's blog post [Demystifying the Semantics of Publish and Subscribe](https://www.asyncapi.com/blog/publish-subscribe-semantics) @@ -191,9 +191,9 @@ operations: ``` ### Messages instead of message -In v2, if you wanted to define channels to have one or more messages, you would do it with `oneOf`, or if just a single message. +In v2, if you wanted to define channels to have one or more messages, you would do it with `oneOf`. -In v3, messages are now defined with the [Messages Object](https://www.asyncapi.com/docs/reference/specification/v3.0.0-next-major-spec.12#messagesObject), if you want a channel to have one or more messages, you just define multiple key/value pairs, or if a single message, it's just a single key/value pair. +In v3, messages are now defined with the [Messages Object](https://www.asyncapi.com/docs/reference/specification/v3.0.0-next-major-spec.12#messagesObject). If you want a channel to have one or more messages, you just define multiple key-value pairs, or if a single message, it's just a single key-value pair. ```yml asyncapi: 2.6.0 @@ -237,7 +237,7 @@ channels: ### Unifying explicit and implicit references -In v2, it was possible to do implicit references in some places, for example for server security configuration, it was by name which referred to a [Security Schema Object](https://www.asyncapi.com/docs/reference/specification/v2.6.0#securitySchemeObject) in components - And for a channel to reference global servers by name. +In v2, it was possible to do implicit references in some places. For example, for server security configuration, it was by name which referred to a [Security Schema Object](https://www.asyncapi.com/docs/reference/specification/v2.6.0#securitySchemeObject) in components - And for a channel to reference global servers by name. In v3, this information MUST be explicit references. This did mean that we had to slightly change the [Server Object](https://www.asyncapi.com/docs/reference/specification/v3.0.0-next-major-spec.12#serverObject) `security` property, which is now an array instead of an object. We then moved the information about needed scopes for OAuth and OpenID Connect to the [Security Scheme Object](https://www.asyncapi.com/docs/reference/specification/v3.0.0-next-major-spec.12#securitySchemeObject). @@ -294,11 +294,11 @@ components: ``` ### New trait behavior -Traits in v2 always replaced any duplicate properties that were defined both in traits and the associated object. This meant for example if the message traits defined headers and the message object did as well, only the message trait headers would be applied because it overwrote anything you wrote in the Message Object. +Traits in v2 always replaced any duplicate properties that were defined both in traits and the associated object. This meant for example, if the message traits defined headers and the message object did as well, only the message trait headers would be applied because it overwrote anything you wrote in the Message Object. In v3, this has now been changed so that main objects have a higher priority than what ever you define in traits. This applies to traits in both operation and message objects. -Let's go through a few examples, for example here with the message object and associated traits: +Let's go through a few examples. Here with the message object and associated traits: ```yml messageId: userSignup description: A longer description. @@ -319,7 +319,7 @@ payload: ``` This is the default behavior of the [JSON Merge Patch](https://tools.ietf.org/html/rfc7386) algorithm we use. -However, in v3, we enforce a rule that `A property on a trait MUST NOT override the same property on the target object`. This means that in v3, after traits have been applied this is the full message object in v3: +However, in v3, we enforce a rule that `A property on a trait MUST NOT override the same property on the target object`. This means that in v3, after traits have been applied, this is the full message object in v3: ```yml messageId: userSignup summary: Action to sign a user up. @@ -337,7 +337,7 @@ With schemas, one thing that has always been impossible was reusing schemas with In v2, the information about which schema the payload is defined with is located under the message object and not directly associated with the schema itself. This makes reusability impossible because the two pieces of information are not directly associated with each other. -So in v3, we add [a multi-format schema object](https://www.asyncapi.com/docs/reference/specification/v3.0.0-next-major-spec.12#multiFormatSchemaObject), encapsulating this information together. That means that if you anywhere use `schemaFormat`, you have to change the schema like below. +So in v3, we add [a multi-format schema object](https://www.asyncapi.com/docs/reference/specification/v3.0.0-next-major-spec.12#multiFormatSchemaObject), encapsulating this information together. This means that if you anywhere use `schemaFormat`, you have to change the schema like below: ```yml @@ -379,7 +379,7 @@ channels: ``` ### Optional channels -In v3 channels are now completely optional, which means that you dont have to define channels as an empty object as you did in v2. +In v3, channels are now completely optional. It means that you don't have to define channels as an empty object as you did in v2. ```yml asyncapi: 2.6.0 From 91aefc77569269a24551e71ec230b086b2d50e24 Mon Sep 17 00:00:00 2001 From: akshatnema Date: Tue, 1 Aug 2023 22:06:39 +0530 Subject: [PATCH 06/15] Update mobile view comparison --- components/Asyncapi3Comparison.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/components/Asyncapi3Comparison.js b/components/Asyncapi3Comparison.js index 9362db83628..ea39eb68def 100644 --- a/components/Asyncapi3Comparison.js +++ b/components/Asyncapi3Comparison.js @@ -19,7 +19,7 @@ export function Asyncapi3Comparison({ className = '' }) { }); return ( -
+

AsyncAPI 2.x

@@ -177,7 +177,7 @@ export function Asyncapi3ChannelComparison({ className = '' }) { }); return ( -
+

AsyncAPI 2.x

@@ -276,7 +276,7 @@ export function Asyncapi3IdAndAddressComparison({ className = '' }) { }); return ( -
+

AsyncAPI 2.x

@@ -321,7 +321,7 @@ export function Asyncapi3ServerComparison({ className = '' }) { }); return ( -
+

AsyncAPI 2.x

@@ -375,7 +375,7 @@ export function Asyncapi3MetaComparison({ className = '' }) { }); return ( -
+

AsyncAPI 2.x

@@ -418,7 +418,7 @@ export function Asyncapi3MetaComparison({ className = '' }) { // eslint-disable-next-line react/prop-types export function Asyncapi3OperationComparison({ className = '' }) { return ( -
+

AsyncAPI 2.x

@@ -473,7 +473,7 @@ export function Asyncapi3SchemaFormatComparison({ className = '' }) { }); return ( -
+

AsyncAPI 2.x

From e85226fb1f00c182c6457ff9cd667ab5e913d1ab Mon Sep 17 00:00:00 2001 From: "jonas-lt@live.dk" Date: Wed, 16 Aug 2023 20:15:44 +0200 Subject: [PATCH 07/15] remove eslint ignore --- components/Asyncapi3Comparison.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/components/Asyncapi3Comparison.js b/components/Asyncapi3Comparison.js index ea39eb68def..01933f9b49a 100644 --- a/components/Asyncapi3Comparison.js +++ b/components/Asyncapi3Comparison.js @@ -1,6 +1,6 @@ import React, { useState } from 'react'; -// eslint-disable-next-line react/prop-types + export function Asyncapi3Comparison({ className = '' }) { const [hoverState, setHoverState] = useState({ Info: false, @@ -167,7 +167,7 @@ export function Asyncapi3Comparison({ className = '' }) { ) } -// eslint-disable-next-line react/prop-types + export function Asyncapi3ChannelComparison({ className = '' }) { const [hoverState, setHoverState] = useState({ Paths: false, @@ -268,7 +268,7 @@ export function Asyncapi3ChannelComparison({ className = '' }) { ) } -// eslint-disable-next-line react/prop-types + export function Asyncapi3IdAndAddressComparison({ className = '' }) { const [hoverState, setHoverState] = useState({ Paths: false, @@ -415,7 +415,7 @@ export function Asyncapi3MetaComparison({ className = '' }) { } -// eslint-disable-next-line react/prop-types + export function Asyncapi3OperationComparison({ className = '' }) { return (
@@ -465,7 +465,7 @@ export function Asyncapi3OperationComparison({ className = '' }) { } -// eslint-disable-next-line react/prop-types + export function Asyncapi3SchemaFormatComparison({ className = '' }) { const [hoverState, setHoverState] = useState({ SchemaFormat: false, From d214e3f7135a626b4619e2e8fce87cc86ccffa35 Mon Sep 17 00:00:00 2001 From: "jonas-lt@live.dk" Date: Thu, 17 Aug 2023 15:31:03 +0200 Subject: [PATCH 08/15] add jsdoc --- components/Asyncapi3Comparison.js | 29 +++++++++++++++++++++-------- 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/components/Asyncapi3Comparison.js b/components/Asyncapi3Comparison.js index 01933f9b49a..c4e8800204b 100644 --- a/components/Asyncapi3Comparison.js +++ b/components/Asyncapi3Comparison.js @@ -1,6 +1,8 @@ import React, { useState } from 'react'; - +/** + * Main comparison that shows the full picture between v2 and v3 + */ export function Asyncapi3Comparison({ className = '' }) { const [hoverState, setHoverState] = useState({ Info: false, @@ -167,7 +169,9 @@ export function Asyncapi3Comparison({ className = '' }) { ) } - +/** + * Used to compare how channels, operations and messages have changed + */ export function Asyncapi3ChannelComparison({ className = '' }) { const [hoverState, setHoverState] = useState({ Paths: false, @@ -268,7 +272,9 @@ export function Asyncapi3ChannelComparison({ className = '' }) { ) } - +/** + * Shows the comparison between v2 and v3 for the channel IDs and channel address + */ export function Asyncapi3IdAndAddressComparison({ className = '' }) { const [hoverState, setHoverState] = useState({ Paths: false, @@ -312,7 +318,9 @@ export function Asyncapi3IdAndAddressComparison({ className = '' }) { ) } - +/** + * Compares how the server object changes from v2 to v3. + */ export function Asyncapi3ServerComparison({ className = '' }) { const [hoverState, setHoverState] = useState({ Host: false, @@ -367,6 +375,9 @@ export function Asyncapi3ServerComparison({ className = '' }) { ) } +/** + * Compare how the meta data moved place between v2 and v3 + */ export function Asyncapi3MetaComparison({ className = '' }) { const [hoverState, setHoverState] = useState({ Info: false, @@ -414,8 +425,9 @@ export function Asyncapi3MetaComparison({ className = '' }) { ) } - - +/** + * Compares how operations changed from v2 to v3 + */ export function Asyncapi3OperationComparison({ className = '' }) { return (
@@ -464,8 +476,9 @@ export function Asyncapi3OperationComparison({ className = '' }) { ) } - - +/** + * Compares how the schema and schemaFormat changed location from v2 to v3 + */ export function Asyncapi3SchemaFormatComparison({ className = '' }) { const [hoverState, setHoverState] = useState({ SchemaFormat: false, From 8053bed1e33b552e49c04bb3e8a63954a7a9bd04 Mon Sep 17 00:00:00 2001 From: "jonas-lt@live.dk" Date: Thu, 17 Aug 2023 15:39:05 +0200 Subject: [PATCH 09/15] add basic tests --- cypress/test/Asyncapi3Comparison.cy.js | 40 ++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 cypress/test/Asyncapi3Comparison.cy.js diff --git a/cypress/test/Asyncapi3Comparison.cy.js b/cypress/test/Asyncapi3Comparison.cy.js new file mode 100644 index 00000000000..15893bfd5f9 --- /dev/null +++ b/cypress/test/Asyncapi3Comparison.cy.js @@ -0,0 +1,40 @@ +import { mount } from '@cypress/react' +import {Asyncapi3Comparison, Asyncapi3ChannelComparison, Asyncapi3IdAndAddressComparison, Asyncapi3MetaComparison, Asyncapi3OperationComparison, Asyncapi3SchemaFormatComparison, Asyncapi3ServerComparison} from '../../components/Asyncapi3Comparison' + +describe('Asyncapi3Comparison.cy', () => { + describe('Asyncapi3Comparison', () => { + it('renders without errors', () => { + mount(); + }); + }); + describe('Asyncapi3ChannelComparison', () => { + it('renders without errors', () => { + mount(); + }); + }); + describe('Asyncapi3IdAndAddressComparison', () => { + it('renders without errors', () => { + mount(); + }); + }); + describe('Asyncapi3MetaComparison', () => { + it('renders without errors', () => { + mount(); + }); + }); + describe('Asyncapi3OperationComparison', () => { + it('renders without errors', () => { + mount(); + }); + }); + describe('Asyncapi3SchemaFormatComparison', () => { + it('renders without errors', () => { + mount(); + }); + }); + describe('Asyncapi3ServerComparison', () => { + it('renders without errors', () => { + mount(); + }); + }); +}); From dd6e552846fbccf78869dcd9869629afdb079921 Mon Sep 17 00:00:00 2001 From: Jonas Lagoni Date: Tue, 29 Aug 2023 14:57:15 +0200 Subject: [PATCH 10/15] Update pages/docs/migration/migrating-to-v3.md --- pages/docs/migration/migrating-to-v3.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pages/docs/migration/migrating-to-v3.md b/pages/docs/migration/migrating-to-v3.md index 3525d240fff..648b0ebedf7 100644 --- a/pages/docs/migration/migrating-to-v3.md +++ b/pages/docs/migration/migrating-to-v3.md @@ -43,7 +43,7 @@ info: ``` ### Server URL splitting up -A confusion that arrived from time to time, was what the URL of a [Server Object](https://www.asyncapi.com/docs/reference/specification/v3.0.0-next-major-spec.12#serverObject) should include. +A confusion that arose from time to time was what the URL of a [Server Object](https://www.asyncapi.com/docs/reference/specification/v3.0.0-next-major-spec.12#serverObject) should include. From fdd54268bbfb17270c8e3d4edd778aa6371b79a9 Mon Sep 17 00:00:00 2001 From: Jonas Lagoni Date: Tue, 29 Aug 2023 14:57:26 +0200 Subject: [PATCH 11/15] Update pages/docs/migration/migrating-to-v3.md --- pages/docs/migration/migrating-to-v3.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pages/docs/migration/migrating-to-v3.md b/pages/docs/migration/migrating-to-v3.md index 648b0ebedf7..4b495398490 100644 --- a/pages/docs/migration/migrating-to-v3.md +++ b/pages/docs/migration/migrating-to-v3.md @@ -77,7 +77,7 @@ In v2, it was impossible to reuse channels, and impossible to have more than one In v3, this is now possible, with the mindset, a channel and message should be detached from the operations performed. -For any message broker, for example, Kafka, this is the same as defining topics and the messages it contains. For REST interfaces it's all the paths and corresponding messages across all request types. For WebSocket, it's all the messages flowing through the WebSocket server. For Socket.Io, it defines all the rooms and messages therein. +For any message broker, for example, Kafka, this is the same as defining topics and the messages it contains. For REST interfaces it's the path and request type (POST, GET, etc.) and the request and response messages. For WebSocket, it's all the messages flowing through the WebSocket server. For Socket.Io, it defines all the rooms and messages therein. This change makes the channels reusable across multiple AsyncAPI documents, each performing a slightly different action. From 0aa58111b9c53687644febe033f943c5e2564469 Mon Sep 17 00:00:00 2001 From: "jonas-lt@live.dk" Date: Wed, 11 Oct 2023 11:53:38 +0200 Subject: [PATCH 12/15] add menu for migrations --- components/data/buckets.js | 14 ++++++++++++-- components/icons/Users.js | 18 +++++++++--------- components/navigation/learningItems.js | 2 ++ pages/docs/community/_section.md | 4 ++-- pages/docs/migration/_section.md | 4 ++-- 5 files changed, 27 insertions(+), 15 deletions(-) diff --git a/components/data/buckets.js b/components/data/buckets.js index a171d271885..2dd21112c0b 100644 --- a/components/data/buckets.js +++ b/components/data/buckets.js @@ -4,6 +4,7 @@ import IconUseCases from '../icons/UseCases' import IconGuide from '../icons/Guide' import IconSpec from '../icons/Spec' import IconUsers from '../icons/Users' +import IconMigration from '../icons/Migration' export const buckets = [ { @@ -51,7 +52,16 @@ export const buckets = [ borderClassName: 'border-yellow-200', Icon: IconSpec, }, - { + { + name: 'migration', + title: 'Migration', + description: 'Our migration guides on how to newer AsyncAPI versions.', + link: '/docs/migration', + className: 'bg-blue-400', + borderClassName: 'border-blue-400', + Icon: IconMigration, + }, + { name: 'community', title: 'Community', description: 'Our Community section documents the community guidelines and resources.', @@ -61,7 +71,7 @@ export const buckets = [ Icon: IconUsers, }, ].map(bucket => { - // we need such a mapping for some parts of website, e.g navigation blocks use the `icon` property, not `Icon` etc. + // we need such a mapping for some parts of website, e.g navigation blocks use the `icon` property, not `Icon` etc. return { ...bucket, href: bucket.link, diff --git a/components/icons/Users.js b/components/icons/Users.js index c46a89deb77..9f43fdcb633 100644 --- a/components/icons/Users.js +++ b/components/icons/Users.js @@ -1,14 +1,14 @@ export default function IconUsers({ ...rest }) { return ( - diff --git a/components/navigation/learningItems.js b/components/navigation/learningItems.js index 65ba491f9a9..653bbc8dbc5 100644 --- a/components/navigation/learningItems.js +++ b/components/navigation/learningItems.js @@ -4,6 +4,7 @@ import IconPlant from '../icons/Plant' import IconGuide from '../icons/Guide' import IconPaper from '../icons/Paper' import IconUsers from '../icons/Users' +import IconMigration from '../icons/Migration' export default [ { href: '/docs/concepts', icon: IconRocket, className: 'bg-secondary-200', title: 'Concepts', description: 'Our Concepts section defines the concepts of AsyncAPI features and capabilities.' }, @@ -11,5 +12,6 @@ export default [ { href: '/docs/tools', icon: IconPlant, className: 'bg-green-200', title: 'Tools', description: 'Our Tools section documents the AsyncAPI tools ecosystem.' }, { href: '/docs/guides', icon: IconGuide, className: 'bg-primary-200', title: 'Guides', description: `Our Guides section teaches AsyncAPI's capabilities at a high level.` }, { href: '/docs/reference', icon: IconPaper, className: 'bg-yellow-200', title: 'Reference', description: `Our Reference section documents the AsyncAPI specification.` }, + { href: '/docs/migration', icon: IconMigration, className: 'bg-blue-400', title: 'Migrations', description: `Our migration guides on how to newer AsyncAPI versions.` }, { href: '/docs/community', icon: IconUsers, className: 'bg-red-200', title: 'Community', description: `Our Community section documents the community guidelines and resources.` }, ] diff --git a/pages/docs/community/_section.md b/pages/docs/community/_section.md index 6874743a00f..1ef99a267b1 100644 --- a/pages/docs/community/_section.md +++ b/pages/docs/community/_section.md @@ -1,4 +1,4 @@ --- title: 'Community' -weight: 6 ---- \ No newline at end of file +weight: 7 +--- diff --git a/pages/docs/migration/_section.md b/pages/docs/migration/_section.md index 12839bbb260..48556fd333c 100644 --- a/pages/docs/migration/_section.md +++ b/pages/docs/migration/_section.md @@ -1,4 +1,4 @@ --- title: Migrations -weight: 3 ---- \ No newline at end of file +weight: 6 +--- From 1cbd7d421a4fa9a047a27bf1a3e22216c53fa605 Mon Sep 17 00:00:00 2001 From: "jonas-lt@live.dk" Date: Wed, 11 Oct 2023 11:55:02 +0200 Subject: [PATCH 13/15] add menu for migrations --- components/data/buckets.js | 2 +- components/navigation/learningItems.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/components/data/buckets.js b/components/data/buckets.js index 2dd21112c0b..8ecab700fa1 100644 --- a/components/data/buckets.js +++ b/components/data/buckets.js @@ -55,7 +55,7 @@ export const buckets = [ { name: 'migration', title: 'Migration', - description: 'Our migration guides on how to newer AsyncAPI versions.', + description: 'Our migration guides on how to upgrade to newer AsyncAPI versions.', link: '/docs/migration', className: 'bg-blue-400', borderClassName: 'border-blue-400', diff --git a/components/navigation/learningItems.js b/components/navigation/learningItems.js index 653bbc8dbc5..f04382b44ae 100644 --- a/components/navigation/learningItems.js +++ b/components/navigation/learningItems.js @@ -12,6 +12,6 @@ export default [ { href: '/docs/tools', icon: IconPlant, className: 'bg-green-200', title: 'Tools', description: 'Our Tools section documents the AsyncAPI tools ecosystem.' }, { href: '/docs/guides', icon: IconGuide, className: 'bg-primary-200', title: 'Guides', description: `Our Guides section teaches AsyncAPI's capabilities at a high level.` }, { href: '/docs/reference', icon: IconPaper, className: 'bg-yellow-200', title: 'Reference', description: `Our Reference section documents the AsyncAPI specification.` }, - { href: '/docs/migration', icon: IconMigration, className: 'bg-blue-400', title: 'Migrations', description: `Our migration guides on how to newer AsyncAPI versions.` }, + { href: '/docs/migration', icon: IconMigration, className: 'bg-blue-400', title: 'Migrations', description: `Our migration guides on how to upgrade to newer AsyncAPI versions.` }, { href: '/docs/community', icon: IconUsers, className: 'bg-red-200', title: 'Community', description: `Our Community section documents the community guidelines and resources.` }, ] From 50c28855289ecaec22a81f00a679a04f9cea60ac Mon Sep 17 00:00:00 2001 From: "jonas-lt@live.dk" Date: Wed, 11 Oct 2023 11:59:34 +0200 Subject: [PATCH 14/15] add menu for migrations --- components/icons/Migration.js | 15 +++++++++++++++ pages/docs/migration/index.md | 15 +++++++++++++++ 2 files changed, 30 insertions(+) create mode 100644 components/icons/Migration.js create mode 100644 pages/docs/migration/index.md diff --git a/components/icons/Migration.js b/components/icons/Migration.js new file mode 100644 index 00000000000..77180efeba8 --- /dev/null +++ b/components/icons/Migration.js @@ -0,0 +1,15 @@ +export default function IconUsers({ ...rest }) { + // + return ( + + + + ); +} diff --git a/pages/docs/migration/index.md b/pages/docs/migration/index.md new file mode 100644 index 00000000000..195bcc35cf5 --- /dev/null +++ b/pages/docs/migration/index.md @@ -0,0 +1,15 @@ +--- +title: "Overview" +--- +Migration to a new major version is always difficult, and AsyncAPI is no exception, but we want to provide as smooth a transition as possible. + +If you are just looking to update your AsyncAPI document, then we suggest you use the [AsyncAPI converter](https://github.com/asyncapi/converter-js). You can do this directly in the CLI with: + +```bash +asyncapi convert asyncapi.json --output=new_asyncapi.json --target-version=x.x.x +``` + +For a detailed read-through about all the changes (non-breaking as well), please do [read the release notes](https://www.asyncapi.com/blog?tags=Release+Notes) for the desired version before hand, as it will give you some more context about the changes. + +Here are all the migration guides: +- [Migrating to v3](/docs/migration/migrating-to-v3) From e3962c6cf08f913dc3d0f32023dd0f72ef72785e Mon Sep 17 00:00:00 2001 From: Alejandra Quetzalli Date: Mon, 30 Oct 2023 17:57:08 -0700 Subject: [PATCH 15/15] editorial re-write --- pages/docs/migration/migrating-to-v3.md | 98 +++++++++++++------------ 1 file changed, 50 insertions(+), 48 deletions(-) diff --git a/pages/docs/migration/migrating-to-v3.md b/pages/docs/migration/migrating-to-v3.md index 4b495398490..9d20b8bbefc 100644 --- a/pages/docs/migration/migrating-to-v3.md +++ b/pages/docs/migration/migrating-to-v3.md @@ -1,23 +1,23 @@ --- title: "Migrating to v3" --- -Migration to a new major version is always difficult, and AsyncAPI is no exception, but we want to provide as smooth a transition as possible, and this is where this document comes in. It shows the breaking changes between AsyncAPI v2 and v3 in an interactive manner. +Migration to a new major version is always difficult, and AsyncAPI is no exception. To provide as smooth a transition as possible, this document shows the breaking changes between AsyncAPI v2 and v3 in an interactive manner. -If you are just looking to update your AsyncAPI document, then we suggest you use the [AsyncAPI converter](https://github.com/asyncapi/converter-js). You can do this directly in the CLI with: +If you want to update your AsyncAPI document, use the [AsyncAPI converter](https://github.com/asyncapi/converter-js) directly in the CLI with the following command: ```bash asyncapi convert asyncapi.json --output=asyncapi_v3.json --target-version=3.0.0 ``` -For a detailed read-through about all the changes (non-breaking as well), please do read [the release notes for v3](/blog/release-notes-3.0.0) before this, as it will give you some more context about the changes in v3. +For a detailed read-through about all the changes (non-breaking as well), read all the [v3 release notes](/blog/release-notes-3.0.0) first to acquire additional context about the changes introduced in v3. import {Asyncapi3Comparison, Asyncapi3ChannelComparison, Asyncapi3IdAndAddressComparison, Asyncapi3MetaComparison, Asyncapi3OperationComparison,Asyncapi3SchemaFormatComparison, Asyncapi3ServerComparison} from '../../../components/Asyncapi3Comparison' -### Metadata being moved +## Moved metadata -In v2 two properties, `tags` and `externalDocs` was placed outside of the [Info Object](https://www.asyncapi.com/docs/reference/specification/v3.0.0-next-major-spec.12#infoObject) `info`, this has been moved in v3 to stay consistent. +In v2, two properties of `tags` and `externalDocs` were placed outside of the [Info Object](https://www.asyncapi.com/docs/reference/specification/v3.0.0-next-major-spec.12#infoObject). For consistency, `info` has been moved in v3. @@ -42,14 +42,15 @@ info: - name: e-commerce ``` -### Server URL splitting up -A confusion that arose from time to time was what the URL of a [Server Object](https://www.asyncapi.com/docs/reference/specification/v3.0.0-next-major-spec.12#serverObject) should include. +## Server URL splitting up +There was occasional confusion regarding what the URL of a [Server Object](https://www.asyncapi.com/docs/reference/specification/v3.0.0-next-major-spec.12#serverObject) should include. -In v2, defining the URL was always as one long URL, sometimes even duplicating information such as protocol. +In v2, the URL was often a lengthy string, sometimes redundantly including details like the protocol. + +In v3, the `url` property has been divided into `host`, `pathname`, and `protocol`—as was the case in v2—making the information more explicit. -In v3, the `url` property has now been split up into `host`, `pathname`, and as in v2 `protocol`, making the information explicit. ```yml asyncapi: 2.6.0 servers: @@ -67,19 +68,19 @@ servers: protocol: "amqp", ``` -### Operation, channel, and message decoupling +## Operation, channel, and message decoupling -The decoupling between operations, channels, and messages, is by far the most intrusive breaking change in v3 that completely splits out how they are related to each other. +The decoupling of operations, channels, and messages is the most significant breaking change in v3, fundamentally altering how they relate to each other. -In v2, it was impossible to reuse channels, and impossible to have more than one operation per channel, i.e. operation variants. +In v2, reusing channels and having multiple operations per channel, such as operation variants, was impossible. -In v3, this is now possible, with the mindset, a channel and message should be detached from the operations performed. +In v3, this has become possible, emphasizing that a channel and message should be independent of the operations performed. -For any message broker, for example, Kafka, this is the same as defining topics and the messages it contains. For REST interfaces it's the path and request type (POST, GET, etc.) and the request and response messages. For WebSocket, it's all the messages flowing through the WebSocket server. For Socket.Io, it defines all the rooms and messages therein. +For message brokers like Kafka, this is akin to defining topics and their associated messages. In REST interfaces, it pertains to the path and request type (e.g., POST, GET), along with the corresponding request and response messages. For WebSocket, it encompasses all messages transmitted through the WebSocket server. For Socket.IO, it delineates all the rooms and their messages. -This change makes the channels reusable across multiple AsyncAPI documents, each performing a slightly different action. +Channels are now reusable across multiple AsyncAPI documents, each facilitating a slightly different action. ```yml asyncapi: 2.6.0 @@ -117,17 +118,17 @@ operations: $ref: "#/channels/UserSignup" ``` -Read more about the publish and subscribe confusion under [Operation keywords](#operation-keywords). +Read more about the confusion between publishing and subscribing in the [Operation keywords](#operation-keywords) section. -### Channel address and channel key +## Channel address and channel key -Another breaking change is that the channel key is no longer the channel path, instead, it's an arbitrary unique ID, and instead, channel paths are described with the `address` property as part of the [Channel Object](https://www.asyncapi.com/docs/reference/specification/v3.0.0-next-major-spec.12#channelObject). +Another breaking change is that the channel key no longer represents the channel path. Instead, it's now an arbitrary unique ID. The channel paths are now defined using the `address` property within the [Channel Object](https://www.asyncapi.com/docs/reference/specification/v3.0.0-next-major-spec.12#channelObject). -In v2, the address/topic/path of the channel was also the ID of the channel, which complicated reusability and simply didn't allow you to define certain use cases where you were using the same address for different contexts. +In v2, the channel's `address/topic/path` doubled as its ID, hindering reusability and preventing the definition of scenarios where the same address was used in different contexts. -In v3, the address/topic/path is now located in an `address` property, while the ID of the channel can be anything. +In v3, the `address/topic/path` has been shifted to an `address` property, allowing the channel ID to be distinct and arbitrary. ```yml asyncapi: 2.6.0 @@ -144,23 +145,23 @@ channels: address: "test/path" ``` -### Operation keywords +## Operation keywords -Another breaking change is that operations no longer are defined with `publish` and `subscribe` and their opposite meaning for your application. Instead, you define your application behavior directly with `send` and `receive` through an `action` property in the [Operation Object](https://www.asyncapi.com/docs/reference/specification/v3.0.0-next-major-spec.12#operationObject). +Another significant change is the shift away from defining operations using `publish` and `subscribe`, which had inverse meanings for your application. Now, you directly specify your application's behavior using `send` and `receive` via the `action` property in the [Operation Object](https://www.asyncapi.com/docs/reference/specification/v3.0.0-next-major-spec.12#operationObject). -In v2, the `publish` and `subscribe` operations were always a great source of confusion, even to folks that knew the confusion. +In v2, the `publish` and `subscribe` operations consistently caused confusion, even among those familiar with the intricacies. -Because if you define `publish` it means others may `publish` to this channel because you (the application) subscribe to it, and `subscribe` meant others may subscribe to this channel because you publish to it. +When you specified `publish`, it implied that others could `publish` to this channel since your application subscribed to it. Conversely, `subscribe` meant that others could subscribe because your application was the one publishing. -In v3, the two operations are completely removed and replaced with an `action` property, that explicitly says what you (the application) do. Nothing about `others` and different perspectives to take into account. +In v3, these operations have been entirely replaced with an `action` property that clearly indicates what your application does. That eliminates ambiguities related to other parties or differing perspectives. -For more information about this publish and subscribe confusion, here are some more reading materials: +Read more information about the confusion between publishing and subscribing: - Fran Méndez's [Proposal to solve publish/subscribe confusion](https://github.com/asyncapi/spec/issues/618) - Nic Townsend's blog post [Demystifying the Semantics of Publish and Subscribe](https://www.asyncapi.com/blog/publish-subscribe-semantics) -Here is an example where, for simplicity, the application both consumes and produces messages to the test channel. +Here is an example where the application both consumes and produces messages to the test channel: ```yml asyncapi: 2.6.0 @@ -190,10 +191,10 @@ operations: $ref: "#/channels/testPathChannel" ``` -### Messages instead of message -In v2, if you wanted to define channels to have one or more messages, you would do it with `oneOf`. +## Messages instead of message +In v2, channels were defined with one or more messages using the `oneOf` property. -In v3, messages are now defined with the [Messages Object](https://www.asyncapi.com/docs/reference/specification/v3.0.0-next-major-spec.12#messagesObject). If you want a channel to have one or more messages, you just define multiple key-value pairs, or if a single message, it's just a single key-value pair. +In v3, messages are defined using the [Messages Object](https://www.asyncapi.com/docs/reference/specification/v3.0.0-next-major-spec.12#messagesObject). For a channel with multiple messages, you specify multiple key-value pairs. For a channel with just one message, you use a single key-value pair. ```yml asyncapi: 2.6.0 @@ -235,11 +236,11 @@ channels: ... ``` -### Unifying explicit and implicit references +## Unifying explicit and implicit references -In v2, it was possible to do implicit references in some places. For example, for server security configuration, it was by name which referred to a [Security Schema Object](https://www.asyncapi.com/docs/reference/specification/v2.6.0#securitySchemeObject) in components - And for a channel to reference global servers by name. +In v2, implicit references were allowed in certain instances. For instance, the server security configuration was identified by name, linking to a [Security Schema Object](https://www.asyncapi.com/docs/reference/specification/v2.6.0#securitySchemeObject) within the components. Similarly, a channel could reference global servers by name. -In v3, this information MUST be explicit references. This did mean that we had to slightly change the [Server Object](https://www.asyncapi.com/docs/reference/specification/v3.0.0-next-major-spec.12#serverObject) `security` property, which is now an array instead of an object. We then moved the information about needed scopes for OAuth and OpenID Connect to the [Security Scheme Object](https://www.asyncapi.com/docs/reference/specification/v3.0.0-next-major-spec.12#securitySchemeObject). +In v3, all such references MUST be explicit. As a result, we made a minor modification to the [Server Object](https://www.asyncapi.com/docs/reference/specification/v3.0.0-next-major-spec.12#serverObject) `security` property, transforming it from an object to an array. The details regarding required scopes for OAuth and OpenID Connect were then relocated to the [Security Scheme Object](https://www.asyncapi.com/docs/reference/specification/v3.0.0-next-major-spec.12#securitySchemeObject). ```yml asyncapi: 2.6.0 @@ -293,12 +294,12 @@ components: - "write:pets" ``` -### New trait behavior -Traits in v2 always replaced any duplicate properties that were defined both in traits and the associated object. This meant for example, if the message traits defined headers and the message object did as well, only the message trait headers would be applied because it overwrote anything you wrote in the Message Object. +## New trait behavior +In v2, traits invariably overwrote any duplicate properties specified both in the traits and the corresponding object. For instance, if both message traits and the message object defined headers, only the headers from the message traits would be recognized, effectively overriding those in the Message Object. -In v3, this has now been changed so that main objects have a higher priority than what ever you define in traits. This applies to traits in both operation and message objects. +In v3, this behavior has been revised. The primary objects now take precedence over any definitions in the traits. Such an adjustment is consistent for traits in both operation and message objects. -Let's go through a few examples. Here with the message object and associated traits: +Here is a message object and associated traits: ```yml messageId: userSignup description: A longer description. @@ -309,7 +310,8 @@ traits: description: Description from trait. ``` -After traits have been applied in v2, the full message object would look like this, take notice of how the `description` was overwritten: +In v2, after applying the traits, the complete message object appeared as follows. Note how the `description` was overridden: + ```yml messageId: userSignup summary: Action to sign a user up. @@ -317,9 +319,10 @@ description: Description from trait. payload: $ref: '#/components/schemas/userSignupPayload' ``` -This is the default behavior of the [JSON Merge Patch](https://tools.ietf.org/html/rfc7386) algorithm we use. +That is the default behavior of the [JSON Merge Patch](https://tools.ietf.org/html/rfc7386) algorithm we use. + +In v3, we've instituted a guideline stating, `A property on a trait MUST NOT override the same property on the target object`. Consequently, after applying the traits in v3, the complete message object appears as follows: -However, in v3, we enforce a rule that `A property on a trait MUST NOT override the same property on the target object`. This means that in v3, after traits have been applied, this is the full message object in v3: ```yml messageId: userSignup summary: Action to sign a user up. @@ -327,18 +330,17 @@ description: A longer description. # it's still description from "main" object payload: $ref: '#/components/schemas/userSignupPayload' ``` -Take notice how the `description` is now no longer overwritten. +Notice how the `description` is no longer overwritten. -### Schema format and schemas +## Schema format and schemas -With schemas, one thing that has always been impossible was reusing schemas with different schema formats. +One limitation with schemas has always been the inability to reuse them across different schema formats. -In v2, the information about which schema the payload is defined with is located under the message object and not directly associated with the schema itself. This makes reusability impossible because the two pieces of information are not directly associated with each other. - -So in v3, we add [a multi-format schema object](https://www.asyncapi.com/docs/reference/specification/v3.0.0-next-major-spec.12#multiFormatSchemaObject), encapsulating this information together. This means that if you anywhere use `schemaFormat`, you have to change the schema like below: +In v2, the details about which schema format the payload uses are found within the message object, rather than being directly linked to the schema itself. Such separation hampers reusability, as the two data points aren't directly correlated. +To address this in v3, we've introduced [a multi-format schema object](https://www.asyncapi.com/docs/reference/specification/v3.0.0-next-major-spec.12#multiFormatSchemaObject) that consolidates this information. Consequently, whenever you utilize `schemaFormat`, you'll need to modify the schema as follows: ```yml asyncapi: 2.6.0 @@ -378,8 +380,8 @@ channels: type: string ``` -### Optional channels -In v3, channels are now completely optional. It means that you don't have to define channels as an empty object as you did in v2. +## Optional channels +In v3, defining channels has become entirely optional, eliminating the need to specify channels as an empty object (required in v2). ```yml asyncapi: 2.6.0