From d970fb2c05fcacbf0f223c63cc2af3aae782fd8a Mon Sep 17 00:00:00 2001 From: "jonas-lt@live.dk" Date: Wed, 16 Aug 2023 16:44:12 +0200 Subject: [PATCH 01/16] add doc --- .../getting-started/request_reply.md | 237 ++++++++++++++++++ 1 file changed, 237 insertions(+) create mode 100644 pages/docs/tutorials/getting-started/request_reply.md diff --git a/pages/docs/tutorials/getting-started/request_reply.md b/pages/docs/tutorials/getting-started/request_reply.md new file mode 100644 index 000000000000..874f518f68f6 --- /dev/null +++ b/pages/docs/tutorials/getting-started/request_reply.md @@ -0,0 +1,237 @@ +--- +title: Request-reply in AsyncAPI +weight: 20 +--- + +A quite common [messaging pattern is request-reply](https://www.enterpriseintegrationpatterns.com/patterns/messaging/RequestReply.html), that describes a **requester**, which sends a request message and waits for a reply message and a **replier** which receives the request message and responds with a reply message. + +This pattern is now available natively as of AsyncAPI v3. + +# Describing a requester + +To describe a requester in AsyncAPI we make use of an operation that `send`s the ping and expecting a `reply` over `pong`. + +```yml +asyncapi: 3.0.0 + +info: + title: Ping/pong example with requester + version: 1.0.0 + description: Simple example with a requester that initiate the request reply/pattern. + +channels: + ping: + address: / + messages: + ping: + $ref: '#/components/messages/ping' + pong: + address: / + messages: + pong: + $ref: '#/components/messages/pong' + +operations: + pingRequest: + action: send + channel: + $ref: '#/channels/ping' + reply: + channel: + $ref: '#/channels/pong' +``` + +Take notice this is an application level ping and pong and is not related to ping/pong in standards such as WebSocket. + +# Describing a replier + +To describe a replier, we take the same structure as for the requester, with the simple difference, it using the `receive` action instead. + +```yml +asyncapi: 3.0.0 + +info: + title: Ping/pong example with replier + version: 1.0.0 + description: Simple example with a replier that replies to the request. + +channels: + //Same as for the requester + +operations: + pongReply: + action: receive + channel: + $ref: '#/channels/ping' + reply: + channel: + $ref: '#/channels/pong' +``` + +# Different patterns within request/reply + +In the simple example above we saw how you could setup a request and reply pattern across two application, where the request and reply happened over the same channel `/` on an unknown server and protocol, could have been HTTP or WebSocket. + +However, there are sub-patterns to request/reply that AsyncAPI v3 supports, lets take a look at them. + +## Request/reply over different channels +If you come from a REST or websocket environment, this sub-pattern might seem weird, but in the event-driven world of Kafka or NATS this is a common pattern to utilize where you do the request over one channel, and reply on a different one. + +In this example the reply is on a statically defined channel so you at design time know exactly where the reply comes. + +The only difference in this AsyncAPI document to the simple example is that each channel have now been giving a different address `/ping` and `/pong` respectfully. + +```yml +asyncapi: 3.0.0 + +info: + title: Ping/pong example for requester with static reply channel + version: 1.0.0 + description: Example with a requester that initiate the request/reply pattern on a different channel than the reply is using. + +channels: + ping: + address: /ping + messages: + ping: + $ref: '#/components/messages/ping' + pong: + address: /pong + messages: + pong: + $ref: '#/components/messages/pong' + +operations: + pingRequest: + action: send + channel: + $ref: '#/channels/ping' + reply: + channel: + $ref: '#/channels/pong' +``` + +Defining the replier is exactly the same as for requester, again using the `receive` action instead as the only difference. + +```yml +asyncapi: 3.0.0 + +info: + title: Ping/pong example for replier with static reply channel + version: 1.0.0 + description: Example with a replier that returns the response on a different channel than the request happened on. + +channels: + //Same as for the requester + +operations: + pongReply: + action: receive + channel: + $ref: '#/channels/ping' + reply: + channel: + $ref: '#/channels/pong' +``` + +## Request/reply with dynamic response channel + +A second sub-pattern is where we do not know the reply channel at design time, but instead it's dynamic and determined at runtime. This could for example be using the request message payload or header to dictate the response channel. + +```yml +asyncapi: 3.0.0 + +info: + title: Ping/pong example for requester with dynamic reply channel + version: 1.0.0 + description: Example with a requester that initiate the request/reply pattern where the reply will happen on what ever is defined in the header `replyTo` of the request. + +channels: + ping: + address: /ping + messages: + ping: + $ref: '#/components/messages/ping' + pong: + address: null + messages: + pong: + $ref: '#/components/messages/pong' + +operations: + pingRequest: + action: send + channel: + $ref: '#/channels/ping' + reply: + address: + location: "$message.header#/replyTo" + channel: + $ref: '#/channels/pong' +``` + +Defining the replier is exactly the same as for requester, again using the `receive` action instead as the only difference. + +```yml +asyncapi: 3.0.0 + +info: + title: Ping/pong example for replier with dynamic reply channel + version: 1.0.0 + description: Example with a replier that returns the response on a channel determined by the header `replyTo` of the request. + +channels: + //Same as for the requester + +operations: + pongReply: + action: receive + channel: + $ref: '#/channels/ping' + reply: + address: + description: Reply address is dynamically determined based on the request header `replyTo` + location: "$message.header#/replyTo" + channel: + $ref: '#/channels/pong' +``` + +You can use different types of `location` values here as it's not limited to headers specifically, you can also use payload properties with `$message.payload#/replyTo`. + +## Multiple messages over the same channel with request/reply + +In for example WebSocket, often you encounter that a channel will contain multiple messages over the same channel, but when you design the request/reply operations, you want to explicitly state which messages are "active". + +In following example it's very close to the first requester example, where the difference is that we merged the two ping and pong channels into a single one (because they use the same address). The request operation then explicitly defined the request message among the available channel messages, and the same for the reply. + +```yml +asyncapi: 3.0.0 + +info: + title: Ping/pong example when a channel contain multiple multiples + version: 1.0.0 + description: Simple example with a requester that initiate the request reply/pattern, where the root channel contains multiple messages. + +channels: + rootChannel: + address: / + messages: + ping: + $ref: '#/components/messages/ping' + pong: + $ref: '#/components/messages/pong' + +operations: + pingRequest: + action: send + channel: + $ref: '#/channels/rootChannel' + messages: + - $ref: "/components/messages/ping" + reply: + messages: + - $ref: "/components/messages/pong" + channel: + $ref: '#/channels/rootChannel' +``` + From 59a5e58bdb69f88e8f24da5f17f76fbe2d57d94f Mon Sep 17 00:00:00 2001 From: "jonas-lt@live.dk" Date: Wed, 16 Aug 2023 16:50:34 +0200 Subject: [PATCH 02/16] editorial edit --- .../getting-started/request_reply.md | 47 ++++++++++--------- 1 file changed, 25 insertions(+), 22 deletions(-) diff --git a/pages/docs/tutorials/getting-started/request_reply.md b/pages/docs/tutorials/getting-started/request_reply.md index 874f518f68f6..c6f22ef8ca6d 100644 --- a/pages/docs/tutorials/getting-started/request_reply.md +++ b/pages/docs/tutorials/getting-started/request_reply.md @@ -3,21 +3,21 @@ title: Request-reply in AsyncAPI weight: 20 --- -A quite common [messaging pattern is request-reply](https://www.enterpriseintegrationpatterns.com/patterns/messaging/RequestReply.html), that describes a **requester**, which sends a request message and waits for a reply message and a **replier** which receives the request message and responds with a reply message. +A quite common [messaging pattern is request-reply](https://www.enterpriseintegrationpatterns.com/patterns/messaging/RequestReply.html), which describes a **requester**, which sends a request message and waits for a reply message and a **replier** which receives the request message and responds with a reply message. This pattern is now available natively as of AsyncAPI v3. # Describing a requester -To describe a requester in AsyncAPI we make use of an operation that `send`s the ping and expecting a `reply` over `pong`. +To describe a requester in AsyncAPI we make use of an operation that `send`s the ping and expects a `reply` over `pong`. ```yml asyncapi: 3.0.0 info: - title: Ping/pong example with requester + title: Ping/pong example with the requester version: 1.0.0 - description: Simple example with a requester that initiate the request reply/pattern. + description: Simple example with a requester that initiates the request-reply pattern. channels: ping: @@ -41,11 +41,11 @@ operations: $ref: '#/channels/pong' ``` -Take notice this is an application level ping and pong and is not related to ping/pong in standards such as WebSocket. +Take notice this is an application-level ping and pong and is not related to ping/pong in standards such as WebSocket. # Describing a replier -To describe a replier, we take the same structure as for the requester, with the simple difference, it using the `receive` action instead. +To describe a replier, we take the same structure as for the requester, with the simple difference, of using the `receive` action instead. ```yml asyncapi: 3.0.0 @@ -70,24 +70,24 @@ operations: # Different patterns within request/reply -In the simple example above we saw how you could setup a request and reply pattern across two application, where the request and reply happened over the same channel `/` on an unknown server and protocol, could have been HTTP or WebSocket. +In the simple example above we saw how you could set up a request and reply pattern across two applications, where the request and reply happened over the same channel `/` on an unknown server and protocol, which could have been HTTP or WebSocket. -However, there are sub-patterns to request/reply that AsyncAPI v3 supports, lets take a look at them. +However, there are sub-patterns to request/reply that AsyncAPI v3 supports, let's take a look at them. ## Request/reply over different channels -If you come from a REST or websocket environment, this sub-pattern might seem weird, but in the event-driven world of Kafka or NATS this is a common pattern to utilize where you do the request over one channel, and reply on a different one. +If you come from a REST or WebSocket environment, this sub-pattern might seem weird, but in the event-driven world of Kafka or NATS this is a common pattern to utilize where you do the request over one channel, and reply on a different one. -In this example the reply is on a statically defined channel so you at design time know exactly where the reply comes. +In this example, the reply is on a statically defined channel so you at design time know exactly where the reply comes. -The only difference in this AsyncAPI document to the simple example is that each channel have now been giving a different address `/ping` and `/pong` respectfully. +The only difference in this AsyncAPI document to the simple example is that each channel has now been given a different address `/ping` and `/pong` respectfully. ```yml asyncapi: 3.0.0 info: - title: Ping/pong example for requester with static reply channel + title: Ping/pong example for a requester with static reply channel version: 1.0.0 - description: Example with a requester that initiate the request/reply pattern on a different channel than the reply is using. + description: Example with a requester that initiates the request/reply pattern on a different channel than the reply is using. channels: ping: @@ -111,7 +111,7 @@ operations: $ref: '#/channels/pong' ``` -Defining the replier is exactly the same as for requester, again using the `receive` action instead as the only difference. +Defining the replier is the same as for the requester, again using the `receive` action instead as the only difference. ```yml asyncapi: 3.0.0 @@ -136,15 +136,17 @@ operations: ## Request/reply with dynamic response channel -A second sub-pattern is where we do not know the reply channel at design time, but instead it's dynamic and determined at runtime. This could for example be using the request message payload or header to dictate the response channel. +A second sub-pattern is where we do not know the reply channel at design time, but instead, it's dynamic and determined at runtime. This could for example be using the request message payload or header to dictate the response channel. + +Take notice how we utilize `address: null` to define that we dont know the address. ```yml asyncapi: 3.0.0 info: - title: Ping/pong example for requester with dynamic reply channel + title: Ping/pong example for a requester with dynamic reply channel version: 1.0.0 - description: Example with a requester that initiate the request/reply pattern where the reply will happen on what ever is defined in the header `replyTo` of the request. + description: Example with a requester that initiates the request/reply pattern where the reply will happen on whatever is defined in the header `replyTo` of the request. channels: ping: @@ -165,12 +167,13 @@ operations: $ref: '#/channels/ping' reply: address: + description: The reply address is dynamically determined based on the request header `replyTo` location: "$message.header#/replyTo" channel: $ref: '#/channels/pong' ``` -Defining the replier is exactly the same as for requester, again using the `receive` action instead as the only difference. +Defining the replier is the same as for the requester, again using the `receive` action instead as the only difference. ```yml asyncapi: 3.0.0 @@ -190,7 +193,7 @@ operations: $ref: '#/channels/ping' reply: address: - description: Reply address is dynamically determined based on the request header `replyTo` + description: The reply address is dynamically determined based on the request header `replyTo` location: "$message.header#/replyTo" channel: $ref: '#/channels/pong' @@ -202,15 +205,15 @@ You can use different types of `location` values here as it's not limited to hea In for example WebSocket, often you encounter that a channel will contain multiple messages over the same channel, but when you design the request/reply operations, you want to explicitly state which messages are "active". -In following example it's very close to the first requester example, where the difference is that we merged the two ping and pong channels into a single one (because they use the same address). The request operation then explicitly defined the request message among the available channel messages, and the same for the reply. +In the following example it's very close to the first requester example, where the difference is that we merged the two ping and pong channels into a single one (because they use the same address). The request operation then explicitly defined the request message among the available channel messages and the same for the reply. ```yml asyncapi: 3.0.0 info: - title: Ping/pong example when a channel contain multiple multiples + title: Ping/pong example when a channel contains multiple multiples version: 1.0.0 - description: Simple example with a requester that initiate the request reply/pattern, where the root channel contains multiple messages. + description: Simple example with a requester that initiates the request-reply pattern, where the root channel contains multiple messages. channels: rootChannel: From a0cfdff3e8c3a4156c11bd0fc66adefb9b244322 Mon Sep 17 00:00:00 2001 From: "jonas-lt@live.dk" Date: Wed, 16 Aug 2023 18:37:38 +0200 Subject: [PATCH 03/16] editorial edit --- .../getting-started/request_reply.md | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/pages/docs/tutorials/getting-started/request_reply.md b/pages/docs/tutorials/getting-started/request_reply.md index c6f22ef8ca6d..a51f96113c93 100644 --- a/pages/docs/tutorials/getting-started/request_reply.md +++ b/pages/docs/tutorials/getting-started/request_reply.md @@ -1,15 +1,17 @@ --- -title: Request-reply in AsyncAPI +title: Request and reply pattern weight: 20 --- -A quite common [messaging pattern is request-reply](https://www.enterpriseintegrationpatterns.com/patterns/messaging/RequestReply.html), which describes a **requester**, which sends a request message and waits for a reply message and a **replier** which receives the request message and responds with a reply message. +A quite common messaging pattern is [request-reply](https://www.enterpriseintegrationpatterns.com/patterns/messaging/RequestReply.html), which describes a **requester**, which sends a request message and waits for a reply and a **replier** which receives the request and responds with a reply. -This pattern is now available natively as of AsyncAPI v3. +As of AsyncPAI v3, this pattern can be described natively. # Describing a requester -To describe a requester in AsyncAPI we make use of an operation that `send`s the ping and expects a `reply` over `pong`. +We are gonna use a very simple ping and pong example where a requestor sends the ping and responder respond with pong. Take notice this is an application-level ping and pong and is not related to ping/pong in standards such as WebSocket. + +To describe a **requester** in AsyncAPI we make use of an operation that `send`s the ping and expects a `reply` over `pong`. ```yml asyncapi: 3.0.0 @@ -41,11 +43,9 @@ operations: $ref: '#/channels/pong' ``` -Take notice this is an application-level ping and pong and is not related to ping/pong in standards such as WebSocket. - # Describing a replier -To describe a replier, we take the same structure as for the requester, with the simple difference, of using the `receive` action instead. +To describe a **replier**, we take the same structure as for the requester, with the simple difference, of using the `receive` action instead. ```yml asyncapi: 3.0.0 @@ -56,7 +56,7 @@ info: description: Simple example with a replier that replies to the request. channels: - //Same as for the requester + // Same as for the requester operations: pongReply: @@ -68,18 +68,18 @@ operations: $ref: '#/channels/pong' ``` -# Different patterns within request/reply +# Sub-patterns in request and reply -In the simple example above we saw how you could set up a request and reply pattern across two applications, where the request and reply happened over the same channel `/` on an unknown server and protocol, which could have been HTTP or WebSocket. +In the simple example above we saw how you could set up a request and reply pattern across two applications, where the request and reply happened over the same channel `/` on an unknown server and protocol, which could have been HTTP, Kafka or WebSocket, in this simple example it does not really matter, cause the only difference would be how the server information is defined. -However, there are sub-patterns to request/reply that AsyncAPI v3 supports, let's take a look at them. +However, there are sub-patterns to request and reply that AsyncAPI v3 supports, let's take a look at them. ## Request/reply over different channels If you come from a REST or WebSocket environment, this sub-pattern might seem weird, but in the event-driven world of Kafka or NATS this is a common pattern to utilize where you do the request over one channel, and reply on a different one. -In this example, the reply is on a statically defined channel so you at design time know exactly where the reply comes. +In this example, the reply is on a statically defined channel so you at design time know exactly where the reply is returned to. -The only difference in this AsyncAPI document to the simple example is that each channel has now been given a different address `/ping` and `/pong` respectfully. +The only difference in this AsyncAPI document, in relation to the simple example is that each channel has now been given a different address `/ping` and `/pong` respectively. ```yml asyncapi: 3.0.0 @@ -111,7 +111,7 @@ operations: $ref: '#/channels/pong' ``` -Defining the replier is the same as for the requester, again using the `receive` action instead as the only difference. +Defining the **replier** is the same as for the requester, again using the `receive` action instead as the only difference. ```yml asyncapi: 3.0.0 @@ -122,7 +122,7 @@ info: description: Example with a replier that returns the response on a different channel than the request happened on. channels: - //Same as for the requester + //.Same as for the requester operations: pongReply: @@ -138,7 +138,7 @@ operations: A second sub-pattern is where we do not know the reply channel at design time, but instead, it's dynamic and determined at runtime. This could for example be using the request message payload or header to dictate the response channel. -Take notice how we utilize `address: null` to define that we dont know the address. +Take notice how we utilize `address: null` to define that we dont know the address and instead ```yml asyncapi: 3.0.0 @@ -184,7 +184,7 @@ info: description: Example with a replier that returns the response on a channel determined by the header `replyTo` of the request. channels: - //Same as for the requester + //.Same as for the requester operations: pongReply: From e2837a878b1816c4df713521280f01a46a1a5cf8 Mon Sep 17 00:00:00 2001 From: Jonas Lagoni Date: Thu, 17 Aug 2023 11:46:46 +0200 Subject: [PATCH 04/16] Update pages/docs/tutorials/getting-started/request_reply.md Co-authored-by: Alejandra Quetzalli --- pages/docs/tutorials/getting-started/request_reply.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pages/docs/tutorials/getting-started/request_reply.md b/pages/docs/tutorials/getting-started/request_reply.md index a51f96113c93..ae58f2f242a7 100644 --- a/pages/docs/tutorials/getting-started/request_reply.md +++ b/pages/docs/tutorials/getting-started/request_reply.md @@ -1,5 +1,5 @@ --- -title: Request and reply pattern +title: Request/reply pattern weight: 20 --- From 32e70e70a9f50760739132eb03c647f81ed31d3c Mon Sep 17 00:00:00 2001 From: Jonas Lagoni Date: Thu, 17 Aug 2023 11:50:40 +0200 Subject: [PATCH 05/16] Update pages/docs/tutorials/getting-started/request_reply.md Co-authored-by: Alejandra Quetzalli --- pages/docs/tutorials/getting-started/request_reply.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pages/docs/tutorials/getting-started/request_reply.md b/pages/docs/tutorials/getting-started/request_reply.md index ae58f2f242a7..b372a7d89510 100644 --- a/pages/docs/tutorials/getting-started/request_reply.md +++ b/pages/docs/tutorials/getting-started/request_reply.md @@ -68,7 +68,7 @@ operations: $ref: '#/channels/pong' ``` -# Sub-patterns in request and reply +# Sub-patterns in request/reply In the simple example above we saw how you could set up a request and reply pattern across two applications, where the request and reply happened over the same channel `/` on an unknown server and protocol, which could have been HTTP, Kafka or WebSocket, in this simple example it does not really matter, cause the only difference would be how the server information is defined. From 530373d0b5a120815fecac7fd0b42592fa6ee76e Mon Sep 17 00:00:00 2001 From: Jonas Lagoni Date: Thu, 17 Aug 2023 11:53:03 +0200 Subject: [PATCH 06/16] Update pages/docs/tutorials/getting-started/request_reply.md Co-authored-by: Alejandra Quetzalli --- pages/docs/tutorials/getting-started/request_reply.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pages/docs/tutorials/getting-started/request_reply.md b/pages/docs/tutorials/getting-started/request_reply.md index b372a7d89510..b0144238cfb6 100644 --- a/pages/docs/tutorials/getting-started/request_reply.md +++ b/pages/docs/tutorials/getting-started/request_reply.md @@ -138,7 +138,7 @@ operations: A second sub-pattern is where we do not know the reply channel at design time, but instead, it's dynamic and determined at runtime. This could for example be using the request message payload or header to dictate the response channel. -Take notice how we utilize `address: null` to define that we dont know the address and instead +Take notice how we utilize `address: null` to define that we don't know the address: ```yml asyncapi: 3.0.0 From 228d41c2917feeee6ffb3ef5950e83863c0d8e6f Mon Sep 17 00:00:00 2001 From: Jonas Lagoni Date: Thu, 17 Aug 2023 11:53:56 +0200 Subject: [PATCH 07/16] Update pages/docs/tutorials/getting-started/request_reply.md Co-authored-by: Alejandra Quetzalli --- pages/docs/tutorials/getting-started/request_reply.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pages/docs/tutorials/getting-started/request_reply.md b/pages/docs/tutorials/getting-started/request_reply.md index b0144238cfb6..4642fe5ed6f5 100644 --- a/pages/docs/tutorials/getting-started/request_reply.md +++ b/pages/docs/tutorials/getting-started/request_reply.md @@ -17,7 +17,7 @@ To describe a **requester** in AsyncAPI we make use of an operation that `send`s asyncapi: 3.0.0 info: - title: Ping/pong example with the requester + title: Ping/pong example with requester version: 1.0.0 description: Simple example with a requester that initiates the request-reply pattern. From 8ff18cd25774f9684632cb39c4c0a6351cfd1909 Mon Sep 17 00:00:00 2001 From: Jonas Lagoni Date: Thu, 17 Aug 2023 11:59:46 +0200 Subject: [PATCH 08/16] Apply suggestions from code review Co-authored-by: Alejandra Quetzalli Co-authored-by: Sergio Moya <1083296+smoya@users.noreply.github.com> --- .../docs/tutorials/getting-started/request_reply.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/pages/docs/tutorials/getting-started/request_reply.md b/pages/docs/tutorials/getting-started/request_reply.md index 4642fe5ed6f5..3afc86592f5b 100644 --- a/pages/docs/tutorials/getting-started/request_reply.md +++ b/pages/docs/tutorials/getting-started/request_reply.md @@ -19,7 +19,7 @@ asyncapi: 3.0.0 info: title: Ping/pong example with requester version: 1.0.0 - description: Simple example with a requester that initiates the request-reply pattern. + description: Requester example initiating the request-reply pattern. channels: ping: @@ -45,7 +45,7 @@ operations: # Describing a replier -To describe a **replier**, we take the same structure as for the requester, with the simple difference, of using the `receive` action instead. +To describe a **replier**, we take the same structure as for the requester, with the simple difference of using the `receive` action instead. ```yml asyncapi: 3.0.0 @@ -75,9 +75,9 @@ In the simple example above we saw how you could set up a request and reply patt However, there are sub-patterns to request and reply that AsyncAPI v3 supports, let's take a look at them. ## Request/reply over different channels -If you come from a REST or WebSocket environment, this sub-pattern might seem weird, but in the event-driven world of Kafka or NATS this is a common pattern to utilize where you do the request over one channel, and reply on a different one. +If you come from a REST or WebSocket environment, this sub-pattern might seem unfamiliar, but in the event-driven world of Kafka or NATS this is a common pattern to utilize where you do the request over one channel, and reply on a different one. -In this example, the reply is on a statically defined channel so you at design time know exactly where the reply is returned to. +In this example, the reply is on a statically defined channel, so you, at design time, know exactly where the reply is returned to. The only difference in this AsyncAPI document, in relation to the simple example is that each channel has now been given a different address `/ping` and `/pong` respectively. @@ -205,13 +205,13 @@ You can use different types of `location` values here as it's not limited to hea In for example WebSocket, often you encounter that a channel will contain multiple messages over the same channel, but when you design the request/reply operations, you want to explicitly state which messages are "active". -In the following example it's very close to the first requester example, where the difference is that we merged the two ping and pong channels into a single one (because they use the same address). The request operation then explicitly defined the request message among the available channel messages and the same for the reply. +The following example is very similar to the first requester example, with the difference being that we merged the two ping and pong channels into a single one (because they use the same address). The request operation then explicitly defined the request message among the available channel messages and the same for the reply. ```yml asyncapi: 3.0.0 info: - title: Ping/pong example when a channel contains multiple multiples + title: Ping/pong example when a channel contains multiple messages version: 1.0.0 description: Simple example with a requester that initiates the request-reply pattern, where the root channel contains multiple messages. From bdca5135661c627c3d14a60256d472dfee272d41 Mon Sep 17 00:00:00 2001 From: "jonas-lt@live.dk" Date: Thu, 17 Aug 2023 12:00:06 +0200 Subject: [PATCH 09/16] small change --- .../tutorials/getting-started/request_reply.md | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/pages/docs/tutorials/getting-started/request_reply.md b/pages/docs/tutorials/getting-started/request_reply.md index 3afc86592f5b..11f10acfd625 100644 --- a/pages/docs/tutorials/getting-started/request_reply.md +++ b/pages/docs/tutorials/getting-started/request_reply.md @@ -4,14 +4,12 @@ weight: 20 --- A quite common messaging pattern is [request-reply](https://www.enterpriseintegrationpatterns.com/patterns/messaging/RequestReply.html), which describes a **requester**, which sends a request message and waits for a reply and a **replier** which receives the request and responds with a reply. - -As of AsyncPAI v3, this pattern can be described natively. # Describing a requester -We are gonna use a very simple ping and pong example where a requestor sends the ping and responder respond with pong. Take notice this is an application-level ping and pong and is not related to ping/pong in standards such as WebSocket. +We are going to use a very simple ping and pong example where a requestor sends the ping and responder respond with pong. -To describe a **requester** in AsyncAPI we make use of an operation that `send`s the ping and expects a `reply` over `pong`. +To describe a **requester** in AsyncAPI we make use of an operation that `send`s to the `ping` channel and expects a `reply` over `pong`. ```yml asyncapi: 3.0.0 @@ -70,9 +68,9 @@ operations: # Sub-patterns in request/reply -In the simple example above we saw how you could set up a request and reply pattern across two applications, where the request and reply happened over the same channel `/` on an unknown server and protocol, which could have been HTTP, Kafka or WebSocket, in this simple example it does not really matter, cause the only difference would be how the server information is defined. +In the simple example above we saw how you could set up a request/reply pattern across two applications, where the request/reply happened over the same channel `/` on an unknown server and protocol, which could have been HTTP, Kafka or WebSocket, in this simple example it does not really matter, cause the only difference would be how the server information is defined. -However, there are sub-patterns to request and reply that AsyncAPI v3 supports, let's take a look at them. +However, there are sub-patterns to request/reply that AsyncAPI v3 supports, let's take a look at them. ## Request/reply over different channels If you come from a REST or WebSocket environment, this sub-pattern might seem unfamiliar, but in the event-driven world of Kafka or NATS this is a common pattern to utilize where you do the request over one channel, and reply on a different one. @@ -122,7 +120,7 @@ info: description: Example with a replier that returns the response on a different channel than the request happened on. channels: - //.Same as for the requester + // Same as for the requester operations: pongReply: @@ -184,7 +182,7 @@ info: description: Example with a replier that returns the response on a channel determined by the header `replyTo` of the request. channels: - //.Same as for the requester + // Same as for the requester operations: pongReply: @@ -199,7 +197,7 @@ operations: $ref: '#/channels/pong' ``` -You can use different types of `location` values here as it's not limited to headers specifically, you can also use payload properties with `$message.payload#/replyTo`. +You can use different types of `location` values here as it's not limited to headers specifically, you can also use payload properties with `$message.payload#/replyTo`. These types of values are [Runtime Expressions](https://www.asyncapi.com/docs/reference/specification/latest#runtimeExpression). ## Multiple messages over the same channel with request/reply From a9d4c5e964db3b6ccf768cda9aad781bb9430e4d Mon Sep 17 00:00:00 2001 From: "jonas-lt@live.dk" Date: Thu, 17 Aug 2023 12:05:40 +0200 Subject: [PATCH 10/16] small changes --- pages/docs/tutorials/getting-started/request_reply.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pages/docs/tutorials/getting-started/request_reply.md b/pages/docs/tutorials/getting-started/request_reply.md index 11f10acfd625..5eaef0097f88 100644 --- a/pages/docs/tutorials/getting-started/request_reply.md +++ b/pages/docs/tutorials/getting-started/request_reply.md @@ -201,7 +201,7 @@ You can use different types of `location` values here as it's not limited to hea ## Multiple messages over the same channel with request/reply -In for example WebSocket, often you encounter that a channel will contain multiple messages over the same channel, but when you design the request/reply operations, you want to explicitly state which messages are "active". +In WebSocket, you often encounter that a channel will contain multiple messages, which means you will have to make your operations explicitly define which messages are used for each operation. The following example is very similar to the first requester example, with the difference being that we merged the two ping and pong channels into a single one (because they use the same address). The request operation then explicitly defined the request message among the available channel messages and the same for the reply. From 1180a916e5eb07b5922a96701f78ba8978984cbc Mon Sep 17 00:00:00 2001 From: Jonas Lagoni Date: Thu, 17 Aug 2023 15:08:19 +0200 Subject: [PATCH 11/16] Update pages/docs/tutorials/getting-started/request_reply.md --- pages/docs/tutorials/getting-started/request_reply.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pages/docs/tutorials/getting-started/request_reply.md b/pages/docs/tutorials/getting-started/request_reply.md index 5eaef0097f88..275b85ba22bf 100644 --- a/pages/docs/tutorials/getting-started/request_reply.md +++ b/pages/docs/tutorials/getting-started/request_reply.md @@ -3,7 +3,7 @@ title: Request/reply pattern weight: 20 --- -A quite common messaging pattern is [request-reply](https://www.enterpriseintegrationpatterns.com/patterns/messaging/RequestReply.html), which describes a **requester**, which sends a request message and waits for a reply and a **replier** which receives the request and responds with a reply. +A quite common messaging pattern is [request-reply](https://www.enterpriseintegrationpatterns.com/patterns/messaging/RequestReply.html). It describes a **requester**, which sends a request message and waits for a reply - and a **replier** which receives the request and responds with a reply. # Describing a requester From a95da2a3662fef861768db9e4ab0e6535f184acf Mon Sep 17 00:00:00 2001 From: "jonas-lt@live.dk" Date: Thu, 17 Aug 2023 12:08:06 +0200 Subject: [PATCH 12/16] add info about null address --- pages/docs/tutorials/getting-started/request_reply.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pages/docs/tutorials/getting-started/request_reply.md b/pages/docs/tutorials/getting-started/request_reply.md index 275b85ba22bf..422d55e128a1 100644 --- a/pages/docs/tutorials/getting-started/request_reply.md +++ b/pages/docs/tutorials/getting-started/request_reply.md @@ -136,7 +136,7 @@ operations: A second sub-pattern is where we do not know the reply channel at design time, but instead, it's dynamic and determined at runtime. This could for example be using the request message payload or header to dictate the response channel. -Take notice how we utilize `address: null` to define that we don't know the address: +Take notice how we utilize `address: null` to define that we don't know the address. This is just for illustration purpose as you can also omit the property entirely. ```yml asyncapi: 3.0.0 From 500adfc3c559a0b3694d7e41a6b2001751359c4b Mon Sep 17 00:00:00 2001 From: "jonas-lt@live.dk" Date: Thu, 17 Aug 2023 15:09:07 +0200 Subject: [PATCH 13/16] rename file --- .../getting-started/{request_reply.md => request-reply.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename pages/docs/tutorials/getting-started/{request_reply.md => request-reply.md} (100%) diff --git a/pages/docs/tutorials/getting-started/request_reply.md b/pages/docs/tutorials/getting-started/request-reply.md similarity index 100% rename from pages/docs/tutorials/getting-started/request_reply.md rename to pages/docs/tutorials/getting-started/request-reply.md From bf39055b3ebb2159a855bab48e066d0eed7ab02d Mon Sep 17 00:00:00 2001 From: "jonas-lt@live.dk" Date: Thu, 17 Aug 2023 15:10:53 +0200 Subject: [PATCH 14/16] small edits --- pages/docs/tutorials/getting-started/request-reply.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pages/docs/tutorials/getting-started/request-reply.md b/pages/docs/tutorials/getting-started/request-reply.md index 422d55e128a1..363058554f69 100644 --- a/pages/docs/tutorials/getting-started/request-reply.md +++ b/pages/docs/tutorials/getting-started/request-reply.md @@ -68,7 +68,7 @@ operations: # Sub-patterns in request/reply -In the simple example above we saw how you could set up a request/reply pattern across two applications, where the request/reply happened over the same channel `/` on an unknown server and protocol, which could have been HTTP, Kafka or WebSocket, in this simple example it does not really matter, cause the only difference would be how the server information is defined. +In the simple example above we saw how you could set up a request/reply pattern across two applications, where the request/reply happened over the same channel `/` on an unknown server and protocol, which could have been HTTP, Kafka, or WebSocket, in this simple example it does not matter, cause the only difference would be how the server information is defined. However, there are sub-patterns to request/reply that AsyncAPI v3 supports, let's take a look at them. @@ -136,7 +136,7 @@ operations: A second sub-pattern is where we do not know the reply channel at design time, but instead, it's dynamic and determined at runtime. This could for example be using the request message payload or header to dictate the response channel. -Take notice how we utilize `address: null` to define that we don't know the address. This is just for illustration purpose as you can also omit the property entirely. +Take notice how we utilize `address: null` to define that we don't know the address. This is just for illustration purposes as you can also omit the property entirely. ```yml asyncapi: 3.0.0 From b6833b88dd01ce732518664a1d3ecf0122547342 Mon Sep 17 00:00:00 2001 From: Jonas Lagoni Date: Tue, 29 Aug 2023 15:00:16 +0200 Subject: [PATCH 15/16] Apply suggestions from code review Co-authored-by: Animesh Kumar --- .../getting-started/request-reply.md | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/pages/docs/tutorials/getting-started/request-reply.md b/pages/docs/tutorials/getting-started/request-reply.md index 363058554f69..39480e836b7d 100644 --- a/pages/docs/tutorials/getting-started/request-reply.md +++ b/pages/docs/tutorials/getting-started/request-reply.md @@ -7,9 +7,9 @@ A quite common messaging pattern is [request-reply](https://www.enterpriseintegr # Describing a requester -We are going to use a very simple ping and pong example where a requestor sends the ping and responder respond with pong. +We are going to use a very simple ping and pong example where a requester sends the ping and responder responds with a pong. -To describe a **requester** in AsyncAPI we make use of an operation that `send`s to the `ping` channel and expects a `reply` over `pong`. +To describe a **requester** in AsyncAPI, we make use of an operation that `send`s to the `ping` channel and expects a `reply` over `pong`. ```yml asyncapi: 3.0.0 @@ -68,16 +68,16 @@ operations: # Sub-patterns in request/reply -In the simple example above we saw how you could set up a request/reply pattern across two applications, where the request/reply happened over the same channel `/` on an unknown server and protocol, which could have been HTTP, Kafka, or WebSocket, in this simple example it does not matter, cause the only difference would be how the server information is defined. +In the simple example above, we saw how you could set up a request/reply pattern across two applications. The request/reply happened over the same channel `/` on an unknown server and protocol, which could have been HTTP, Kafka, or WebSocket. In this example, it does not matter because the only difference would be how the server information is defined. -However, there are sub-patterns to request/reply that AsyncAPI v3 supports, let's take a look at them. +However, there are sub-patterns to request/reply that AsyncAPI v3 supports. Let's take a look at them below. ## Request/reply over different channels If you come from a REST or WebSocket environment, this sub-pattern might seem unfamiliar, but in the event-driven world of Kafka or NATS this is a common pattern to utilize where you do the request over one channel, and reply on a different one. -In this example, the reply is on a statically defined channel, so you, at design time, know exactly where the reply is returned to. +In this example, the reply is on a statically defined channel, so you, at design time, know exactly where the reply is being returned to. -The only difference in this AsyncAPI document, in relation to the simple example is that each channel has now been given a different address `/ping` and `/pong` respectively. +The only difference in this AsyncAPI document, in relation to the simple example, is that each channel has now been given a different address `/ping` and `/pong` respectively. ```yml asyncapi: 3.0.0 @@ -134,9 +134,9 @@ operations: ## Request/reply with dynamic response channel -A second sub-pattern is where we do not know the reply channel at design time, but instead, it's dynamic and determined at runtime. This could for example be using the request message payload or header to dictate the response channel. +A second sub-pattern is where we do not know the reply channel at design time, but instead, it's dynamic and determined at runtime. This could, for example, be using the request message payload or header to dictate the response channel. -Take notice how we utilize `address: null` to define that we don't know the address. This is just for illustration purposes as you can also omit the property entirely. +Take a notice on how we utilize `address: null` to define that we don't know the address. This is just for illustration purposes as you can also omit the property entirely. ```yml asyncapi: 3.0.0 @@ -171,7 +171,7 @@ operations: $ref: '#/channels/pong' ``` -Defining the replier is the same as for the requester, again using the `receive` action instead as the only difference. +Defining the replier is the same as for the requester, again using the `receive` action instead is the only difference. ```yml asyncapi: 3.0.0 @@ -197,7 +197,7 @@ operations: $ref: '#/channels/pong' ``` -You can use different types of `location` values here as it's not limited to headers specifically, you can also use payload properties with `$message.payload#/replyTo`. These types of values are [Runtime Expressions](https://www.asyncapi.com/docs/reference/specification/latest#runtimeExpression). +You can use different types of `location` values here as it's not limited to headers specifically. You can also use payload properties with `$message.payload#/replyTo`. These types of values are [Runtime Expressions](https://www.asyncapi.com/docs/reference/specification/latest#runtimeExpression). ## Multiple messages over the same channel with request/reply From 85238dbc2e45486793817f7f657475ab397953b2 Mon Sep 17 00:00:00 2001 From: "jonas-lt@live.dk" Date: Wed, 30 Aug 2023 14:33:57 +0200 Subject: [PATCH 16/16] reformat document to use different channels first --- .../getting-started/request-reply.md | 86 ++++++++++--------- 1 file changed, 44 insertions(+), 42 deletions(-) diff --git a/pages/docs/tutorials/getting-started/request-reply.md b/pages/docs/tutorials/getting-started/request-reply.md index 39480e836b7d..404395b02f1e 100644 --- a/pages/docs/tutorials/getting-started/request-reply.md +++ b/pages/docs/tutorials/getting-started/request-reply.md @@ -4,29 +4,27 @@ weight: 20 --- A quite common messaging pattern is [request-reply](https://www.enterpriseintegrationpatterns.com/patterns/messaging/RequestReply.html). It describes a **requester**, which sends a request message and waits for a reply - and a **replier** which receives the request and responds with a reply. - -# Describing a requester -We are going to use a very simple ping and pong example where a requester sends the ping and responder responds with a pong. +## Describing a requester -To describe a **requester** in AsyncAPI, we make use of an operation that `send`s to the `ping` channel and expects a `reply` over `pong`. +We are going to use a very simple ping and pong example where a requester sends the ping and the responder responds with a pong. To describe a **requester** in AsyncAPI, we make use of an operation that `send`s to the `ping` channel and expects a `reply` over `pong`. ```yml asyncapi: 3.0.0 info: - title: Ping/pong example with requester + title: Ping/pong example for a requester with static reply channel version: 1.0.0 - description: Requester example initiating the request-reply pattern. + description: Example with a requester that initiates the request/reply pattern on a different channel than the reply is using. channels: ping: - address: / + address: /ping messages: ping: $ref: '#/components/messages/ping' pong: - address: / + address: /pong messages: pong: $ref: '#/components/messages/pong' @@ -41,17 +39,19 @@ operations: $ref: '#/channels/pong' ``` -# Describing a replier +The `reply` section defines all the necessary information to properly reply to the request, such as where to, and with what message. This is just a simple example, but you can check the full list of properties under the [Operation Reply Object](https://www.asyncapi.com/docs/reference/specification/latest#operationReplyObject) + +## Describing a replier -To describe a **replier**, we take the same structure as for the requester, with the simple difference of using the `receive` action instead. +Defining the **replier** is the same as for the requester, where we instead make use of the `receive` action. ```yml asyncapi: 3.0.0 info: - title: Ping/pong example with replier + title: Ping/pong example for replier with static reply channel version: 1.0.0 - description: Simple example with a replier that replies to the request. + description: Example with a replier that returns the response on a different channel than the request happened on. channels: // Same as for the requester @@ -66,26 +66,27 @@ operations: $ref: '#/channels/pong' ``` +This means that we `receive` a message over `ping` and we are expected to return a reply over `pong`. + # Sub-patterns in request/reply -In the simple example above, we saw how you could set up a request/reply pattern across two applications. The request/reply happened over the same channel `/` on an unknown server and protocol, which could have been HTTP, Kafka, or WebSocket. In this example, it does not matter because the only difference would be how the server information is defined. +In the simple example above, we saw how you could set up a request/reply pattern across two applications where one application is the requester and the other is the replier. -However, there are sub-patterns to request/reply that AsyncAPI v3 supports. Let's take a look at them below. +However, in an protocol-agnostic world there are many different sub-patterns to the simple request/reply. All of which AsyncAPI v3 enables. -## Request/reply over different channels -If you come from a REST or WebSocket environment, this sub-pattern might seem unfamiliar, but in the event-driven world of Kafka or NATS this is a common pattern to utilize where you do the request over one channel, and reply on a different one. +## Request/reply with dynamic response channel -In this example, the reply is on a statically defined channel, so you, at design time, know exactly where the reply is being returned to. +In some cases, we do not know the reply channel at design time, but instead, it's dynamically determined at runtime. This could, for example, be using the request message payload or header to dictate the response address. -The only difference in this AsyncAPI document, in relation to the simple example, is that each channel has now been given a different address `/ping` and `/pong` respectively. +Take notice of how we utilize `address: null` to define that we don't know the address just yet. This is just for illustration purposes as you can also omit the property entirely. We then utilize the [Operation Reply Address Object](https://www.asyncapi.com/docs/reference/specification/latest#operationReplyAddressObject) to define that the address of where to send the reply is located dynamically in the message header under `replyTo`. ```yml asyncapi: 3.0.0 info: - title: Ping/pong example for a requester with static reply channel + title: Ping/pong example for a requester with a dynamic reply channel version: 1.0.0 - description: Example with a requester that initiates the request/reply pattern on a different channel than the reply is using. + description: Example with a requester that initiates the request/reply pattern where the reply will happen on whatever is defined in the header `replyTo` of the request. channels: ping: @@ -94,7 +95,7 @@ channels: ping: $ref: '#/components/messages/ping' pong: - address: /pong + address: null messages: pong: $ref: '#/components/messages/pong' @@ -105,19 +106,22 @@ operations: channel: $ref: '#/channels/ping' reply: + address: + description: The reply address is dynamically determined based on the request header `replyTo` + location: "$message.header#/replyTo" channel: $ref: '#/channels/pong' ``` -Defining the **replier** is the same as for the requester, again using the `receive` action instead as the only difference. +Defining the replier is the same as for the requester, again using the `receive` action instead is the only difference. ```yml asyncapi: 3.0.0 info: - title: Ping/pong example for replier with static reply channel + title: Ping/pong example for replier with a dynamic reply channel version: 1.0.0 - description: Example with a replier that returns the response on a different channel than the request happened on. + description: Example with a replier that returns the response on a channel determined by the header `replyTo` of the request. channels: // Same as for the requester @@ -128,32 +132,37 @@ operations: channel: $ref: '#/channels/ping' reply: + address: + description: The reply address is dynamically determined based on the request header `replyTo` + location: "$message.header#/replyTo" channel: $ref: '#/channels/pong' ``` -## Request/reply with dynamic response channel +You can use different types of `location` values here as it's not limited to headers specifically. You can also use payload properties with `$message.payload#/replyTo`. These types of values are [Runtime Expressions](https://www.asyncapi.com/docs/reference/specification/latest#runtimeExpression). + +## Request/reply over the same channel -A second sub-pattern is where we do not know the reply channel at design time, but instead, it's dynamic and determined at runtime. This could, for example, be using the request message payload or header to dictate the response channel. +The request/reply can also occur over the same channel (for example `/`), which could be HTTP or WebSocket. -Take a notice on how we utilize `address: null` to define that we don't know the address. This is just for illustration purposes as you can also omit the property entirely. +To do this it's as simple as having both channels use the same address. ```yml asyncapi: 3.0.0 info: - title: Ping/pong example for a requester with dynamic reply channel + title: Ping/pong example with requester version: 1.0.0 - description: Example with a requester that initiates the request/reply pattern where the reply will happen on whatever is defined in the header `replyTo` of the request. + description: Requester example initiating the request-reply pattern. channels: ping: - address: /ping + address: / messages: ping: $ref: '#/components/messages/ping' pong: - address: null + address: / messages: pong: $ref: '#/components/messages/pong' @@ -164,9 +173,6 @@ operations: channel: $ref: '#/channels/ping' reply: - address: - description: The reply address is dynamically determined based on the request header `replyTo` - location: "$message.header#/replyTo" channel: $ref: '#/channels/pong' ``` @@ -177,9 +183,9 @@ Defining the replier is the same as for the requester, again using the `receive` asyncapi: 3.0.0 info: - title: Ping/pong example for replier with dynamic reply channel + title: Ping/pong example with replier version: 1.0.0 - description: Example with a replier that returns the response on a channel determined by the header `replyTo` of the request. + description: Simple example with a replier that replies to the request. channels: // Same as for the requester @@ -190,20 +196,15 @@ operations: channel: $ref: '#/channels/ping' reply: - address: - description: The reply address is dynamically determined based on the request header `replyTo` - location: "$message.header#/replyTo" channel: $ref: '#/channels/pong' ``` -You can use different types of `location` values here as it's not limited to headers specifically. You can also use payload properties with `$message.payload#/replyTo`. These types of values are [Runtime Expressions](https://www.asyncapi.com/docs/reference/specification/latest#runtimeExpression). - ## Multiple messages over the same channel with request/reply In WebSocket, you often encounter that a channel will contain multiple messages, which means you will have to make your operations explicitly define which messages are used for each operation. -The following example is very similar to the first requester example, with the difference being that we merged the two ping and pong channels into a single one (because they use the same address). The request operation then explicitly defined the request message among the available channel messages and the same for the reply. +The following example is very similar to the above example, with the difference being that we merged the two ping and pong channels into a single one (because they use the same address). The request operation then explicitly defined the request message among the available channel messages and the same for the reply. ```yml asyncapi: 3.0.0 @@ -236,3 +237,4 @@ operations: $ref: '#/channels/rootChannel' ``` +Notice how we have to add `messages` to the operation and reply information, to explicitly state which messages are used for when.