Request/reply pattern

Found an error? Have a suggestion?Edit this page on GitHub

In this tutorial, you'll learn how to implement the request/reply pattern in an AsyncAPI document using a straightforward ping-pong example.

Before we begin, it would be beneficial for you to have a basic understanding of AsyncAPI and Event-Driven Architectures (EDA). If you need a refresher, refer to our Event-Driven Architecture document.

Request/reply is a messaging pattern involving two key components: the requester, which sends a request message, and the replier, responsible for receiving this request and responding with a reply. This pattern fundamentally revolves around these two roles, requester and replier.

Static reply address

Here's how you can implement the request/reply pattern when the response address is known at the compile or design time.

A requester can be configured with the send operation, where it dispatches a message to the ping channel and anticipates receiving a response through the pong channel.

In the below example, the Operation Reply object within the pingRequest operation provides essential details, like the destination for the reply, which is the pong channel. Since the pong channel is configured with only one message, there's no need to explicitly define the reply message. Similarly, the ping channel has just one message, eliminating the need to specify the message sent in the request.

1asyncapi: 3.0.0
2info:
3title: Ping/pong example with static reply channel
4version: 1.0.0
5description: Requester example that initiates the request/reply pattern on a different channel than the reply is using
6channels:
7ping:
8  address: /ping
9  messages:
10    ping:
11      $ref: '#/components/messages/ping'
12pong:
13  address: /pong
14  messages:
15    pong:
16      $ref: '#/components/messages/pong'
17operations:
18pingRequest:
19  action: send
20  channel: 
21    $ref: '#/channels/ping'
22  reply:
23    channel: 
24      $ref: '#/channels/pong'
25components: 
26messages: 
27  ping:
28    payload:
29      type: object
30      properties:
31        event:
32          type: string
33          const: ping
34  pong:
35    payload:
36      type: object
37      properties:
38        event:
39          type: string
40          const: pong

Dynamic reply address

Occasionally, the destination for a reply cannot be predetermined during the design or compile phase. In such cases, the address for the reply is dynamically determined at runtime, allowing for more flexible and adaptive communication.

In scenarios where the address or reply channel is unknown at design time, the address property can either be set to null or omitted entirely. To define the reply address dynamically, the Operation Reply Address object can be used, allowing for runtime expressions. That enables the requester to specify where the replier should send the reply, detailing the address's location and its specific position within the request.

In this situation, the location property is assigned the runtime expression $message.header#/replyTo. Such an expression indicates that the address for the reply is located within the header of the request, specifically in the replyTo field. This method dynamically determines the reply address based on the content of the request header.

1asyncapi: 3.0.0
2info:
3title: Ping/pong example with reply specified as dynamic information provided in the runtime
4version: 1.0.0
5description: Example document for an application that processes ping requests and replies to the address dynamically specified by the requestor in the message header
6channels:
7ping:
8  address: /ping
9  messages:
10    ping:
11      $ref: '#/components/messages/ping'
12pong:
13  address: null
14  messages:
15    pong:
16      $ref: '#/components/messages/pong'
17operations:
18pingRequest:
19  action: receive
20  channel: 
21    $ref: '#/channels/ping'
22  reply:
23    address:
24      description: Reply is sent to topic specified in 'replyTo' property in the message header
25      location: "$message.header#/replyTo"
26    channel: 
27      $ref: '#/channels/pong'
28components:
29messages:
30  ping:
31    headers:
32      type: object
33      properties:
34        replyTo:
35          type: string
36          description: Provide path to which reply must be provided
37        requestId:
38          type: string
39          format: uuid
40          description: Provide request id that you will use to identify the reply match
41    payload:
42      type: object
43      properties:
44        event:
45          type: string
46          const: ping
47    correlationId:
48      $ref: "#/components/correlationIds/pingCorrelationId"
49  pong:
50    headers:
51      type: object
52      properties:
53        requestId:
54          type: string
55          format: uuid
56          description: Reply message must contain id of the request message
57    payload:
58      type: object
59      properties:
60        event:
61          type: string
62          const: pong
63    correlationId:
64      $ref: "#/components/correlationIds/pingCorrelationId"
65correlationIds:
66  pingCorrelationId:
67    location: '$message.header#/requestId'

While the above examples are a simple implementation of the request/reply pattern, in a protocol-agnostic world there are many different ways to represent the request/reply pattern. All of which are supported by AsyncAPI.

Was this helpful?
Help us improve the docs by adding your contribution.
OR
Github:AsyncAPICreate Issue on GitHub