Post

Describing HTTP operation with AsyncAPI Operation Reply

Few weeks ago I saw interesting question in our Slack.

Thanks, but I’m looking for v3 examples - where operation reply definition can be used afaik it’s not available in v2

It was about how to describe HTTP operation with Operation Reply. In previous note I have already written about describing of SSE application with AsyncAPI.

It’s time to show how to adopt those example for AsyncAPI v3

Contract description

Service which will:

  • Broadcast received messages through a Server-Sent Events connection to any subscribed user
  • Receive messages for broadcasting trough HTTP Resource /messages

Basic contract structure

Let’s start from basic contract structure:

1
2
3
4
5
asyncapi: '3.0.0'
info:
  title: HTTP operations example
  version: 1.0.0
  description: This example shows how to describe HTTP operations with AsyncAPI v3

Introducing channel

Let’s create our channel with address equals to /messages.

We will use it for two things:

  • Subscribe to stream for receiving of incoming messages
  • Send messages for further broadcasting
1
2
3
4
5
6
7
8
9
10
11
12
asyncapi: '3.0.0'
info:
  title: HTTP operations example
  version: 1.0.0
  description: This example shows how to describe HTTP operations with AsyncAPI v3
channels:
  messages:
    address: "/messages"
    description: |
      Channel to:
      - subscribe to SSE connection stream to receive incoming messages
      - send messages to broadcast trough SSE

Introducing messages

When channel was defined, it’s time to tell which messages can be received or sent.

  • messagesStream it’s a wrapper for our response, which holds important response headers
  • messageToBroadcast it’s a message which user can send for further broadcasting to all subscribed users
  • messageReadyForBroadcasting it’s a message which subscribed users will receive trough SSE connection
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
asyncapi: '3.0.0'
info:
  title: HTTP operations example
  version: 1.0.0
  description: This example shows how to describe HTTP operations with AsyncAPI v3
channels:
  messages:
    address: "/messages"
    description: |
      Channel to:
      - subscribe to SSE connection stream to receive incoming messages
      - send messages to broadcast trough SSE
components:
  messages:
    messagesStream:
      summary: Stream of Messages
      payload:
        $ref: "#/components/messages/messageReadyForBroadcasting/payload"
      bindings:
        http:
          headers:
            properties:
              Content-Type:
                type: string
                enum: ["text/event-stream"]
              X-SSE-Content-Type:
                type: string
                enum: ["application/json"]
              transfer-encoding:
                enum: ["chunked"]
          statusCode: 200
          bindingVersion: 0.3.0
    messageToBroadcast:
      payload:
        type: object
        additionalProperties: false
        description: Message received by application for further broadcasting
        required: [message]
        properties:
          message:
            type: object
            additionalProperties: false
            description: Ordinary text which will be send
            examples:
              - broadcast this message \uD83D\uDE80
    messageReadyForBroadcasting:
      payload:
        type: object
        additionalProperties: false
        description: Broadcasting ready message
        required: [message, receivedAt]
        properties:
          message:
            type: object
            additionalProperties: false
            description: Ordinary text which will be send
            examples:
              - broadcast this message \uD83D\uDE80
          receivedAt:
            type: string
            format: date-time
            description: Date-time when application received this message
            examples:
              - 2023-08-31T15:28:21.283+00:00

Binding channel with messages

In our case our channel allows to send and to receive messages.

That’s why we must bind it with all messages.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
asyncapi: '3.0.0'
info:
  title: HTTP operations example
  version: 1.0.0
  description: This example shows how to describe HTTP operations with AsyncAPI v3
channels:
  messages:
    address: "/messages"
    description: |
      Channel to:
      - subscribe to SSE connection stream to receive incoming messages
      - send messages to broadcast trough SSE
    messages:
      messageToBroadcast:
        $ref: "#/components/messages/messageToBroadcast"
      messagesStream:
        $ref: "#/components/messages/messagesStream"
components:
  messages:
    messagesStream:
      summary: Stream of Messages
      payload:
        $ref: "#/components/messages/messageReadyForBroadcasting/payload"
      bindings:
        http:
          headers:
            properties:
              Content-Type:
                type: string
                enum: ["text/event-stream"]
              X-SSE-Content-Type:
                type: string
                enum: ["application/json"]
              transfer-encoding:
                enum: ["chunked"]
          statusCode: 200
          bindingVersion: 0.3.0
    messageToBroadcast:
      payload:
        type: object
        additionalProperties: false
        description: Message received by application for further broadcasting
        required: [message]
        properties:
          message:
            type: object
            additionalProperties: false
            description: Ordinary text which will be send
            examples:
              - broadcast this message \uD83D\uDE80
    messageReadyForBroadcasting:
      payload:
        type: object
        additionalProperties: false
        description: Broadcasting ready message
        required: [message, receivedAt]
        properties:
          message:
            type: object
            additionalProperties: false
            description: Ordinary text which will be send
            examples:
              - broadcast this message \uD83D\uDE80
          receivedAt:
            type: string
            format: date-time
            description: Date-time when application received this message
            examples:
              - 2023-08-31T15:28:21.283+00:00

Introducing send operation

To send message for broadcasting to our subscribed user, operation must be created.

This operation must have next properties:

  • action is send
  • channel is /messages
  • request schema: messages is array with only one value - reference to #/channels/messages/messages/messageToBroadcast
  • HTTP binding which defines that POST method will be used
  • response schema: operation reply definitions where we will define:
    • channel equals to #/channels/messages
    • messages is array with only one value - reference to #/channels/messages/messages/messageToBroadcast
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
asyncapi: '3.0.0'
info:
  title: HTTP operations example
  version: 1.0.0
  description: This example shows how to describe HTTP operations with AsyncAPI v3
channels:
  messages:
    address: "/messages"
    description: |
      Channel to:
      - subscribe to SSE connection stream to receive incoming messages
      - send messages to broadcast trough SSE
    messages:
      messageToBroadcast:
        $ref: "#/components/messages/messageToBroadcast"
      messagesStream:
        $ref: "#/components/messages/messagesStream"
operations:
  publishMessage:
    action: send
    description: Send message to subscribed users
    channel:
      $ref: "#/channels/messages"
    messages:
      - $ref: "#/channels/messages/messages/messageToBroadcast" # Request schema
    reply:
      channel:
        $ref: "#/channels/messages"
      messages:
        - $ref: "#/channels/messages/messages/messageToBroadcast" # Response schema
    bindings:
      http:
        method: POST
        bindingVersion: 0.3.0
components:
  messages:
    messagesStream:
      summary: Stream of Messages
      payload:
        $ref: "#/components/messages/messageReadyForBroadcasting/payload"
      bindings:
        http:
          headers:
            properties:
              Content-Type:
                type: string
                enum: ["text/event-stream"]
              X-SSE-Content-Type:
                type: string
                enum: ["application/json"]
              transfer-encoding:
                enum: ["chunked"]
          statusCode: 200
          bindingVersion: 0.3.0
    messageToBroadcast:
      payload:
        type: object
        additionalProperties: false
        description: Message received by application for further broadcasting
        required: [message]
        properties:
          message:
            type: object
            additionalProperties: false
            description: Ordinary text which will be send
            examples:
              - broadcast this message \uD83D\uDE80
    messageReadyForBroadcasting:
      payload:
        type: object
        additionalProperties: false
        description: Broadcasting ready message
        required: [message, receivedAt]
        properties:
          message:
            type: object
            additionalProperties: false
            description: Ordinary text which will be send
            examples:
              - broadcast this message \uD83D\uDE80
          receivedAt:
            type: string
            format: date-time
            description: Date-time when application received this message
            examples:
              - 2023-08-31T15:28:21.283+00:00

Introducing receive operation

To subscribe to stream of messages we must create operation with next properties:

  • action is receive
  • channel is /messages
  • messages is array with only one value - reference to #/channels/messages/messages/messagesStream
  • HTTP binding which defines that GET method will be used
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
asyncapi: '3.0.0'
info:
  title: HTTP operations example
  version: 1.0.0
  description: This example shows how to describe HTTP operations with AsyncAPI v3
channels:
  messages:
    address: "/messages"
    description: |
      Channel to:
      - subscribe to SSE connection stream to receive incoming messages
      - send messages to broadcast trough SSE
    messages:
      messageToBroadcast:
        $ref: "#/components/messages/messageToBroadcast"
      messagesStream:
        $ref: "#/components/messages/messagesStream"
operations:
  subscribesToMessagesStream:
    action: receive
    description: Returns SSE stream of messages
    channel:
      $ref: "#/channels/messages"
    messages:
      - $ref: "#/channels/messages/messages/messagesStream"
    bindings:
      http:
        method: GET
        bindingVersion: 0.3.0
  publishMessage:
    action: send
    description: Send message to subscribed users
    channel:
      $ref: "#/channels/messages"
    messages:
      - $ref: "#/channels/messages/messages/messageToBroadcast"
    reply:
      channel:
        $ref: "#/channels/messages"
      messages:
        - $ref: "#/channels/messages/messages/messageToBroadcast"
    bindings:
      http:
        method: POST
        bindingVersion: 0.3.0
components:
  messages:
    messagesStream:
      summary: Stream of Messages
      payload:
        $ref: "#/components/messages/messageReadyForBroadcasting/payload"
      bindings:
        http:
          headers:
            properties:
              Content-Type:
                type: string
                enum: ["text/event-stream"]
              X-SSE-Content-Type:
                type: string
                enum: ["application/json"]
              transfer-encoding:
                enum: ["chunked"]
          statusCode: 200
          bindingVersion: 0.3.0
    messageToBroadcast:
      payload:
        type: object
        additionalProperties: false
        description: Message received by application for further broadcasting
        required: [message]
        properties:
          message:
            type: object
            additionalProperties: false
            description: Ordinary text which will be send
            examples:
              - broadcast this message \uD83D\uDE80
    messageReadyForBroadcasting:
      payload:
        type: object
        additionalProperties: false
        description: Broadcasting ready message
        required: [message, receivedAt]
        properties:
          message:
            type: object
            additionalProperties: false
            description: Ordinary text which will be send
            examples:
              - broadcast this message \uD83D\uDE80
          receivedAt:
            type: string
            format: date-time
            description: Date-time when application received this message
            examples:
              - 2023-08-31T15:28:21.283+00:00
This post is licensed under CC BY 4.0 by the author.