Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: request/response support in both operation and message objects #594

Closed
wants to merge 2 commits into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions spec/asyncapi.md
Original file line number Diff line number Diff line change
Expand Up @@ -663,6 +663,7 @@ Field Name | Type | Description
<a name="operationObjectBindings"></a>bindings | [Operation Bindings Object](#operationBindingsObject) \| [Reference Object](#referenceObject) | A map where the keys describe the name of the protocol and the values describe protocol-specific definitions for the operation.
<a name="operationObjectTraits"></a>traits | [[Operation Trait Object](#operationTraitObject) &#124; [Reference Object](#referenceObject) ] | A list of traits to apply to the operation object. Traits MUST be merged into the operation object using the [JSON Merge Patch](https://tools.ietf.org/html/rfc7386) algorithm in the same order they are defined here.
<a name="operationObjectMessage"></a>message | [[Message Object](#messageObject) &#124; [Reference Object](#referenceObject)] | A definition of the message that will be published or received on this channel. `oneOf` is allowed here to specify multiple messages, however, **a message MUST be valid only against one of the referenced message objects.**
<a name="operationObjectResponse"></a>response | [[Message Object](#messageObject) &#124; [Reference Object](#referenceObject)] | A OPTIONAL definition of the message that will be produced as direct response to publish or subscribe operation on this channel. `oneOf` is allowed here to specify multiple messages, however, **a message MUST be valid only against one of the referenced message objects.**

This object can be extended with [Specification Extensions](#specificationExtensions).

Expand Down Expand Up @@ -700,6 +701,18 @@ This object can be extended with [Specification Extensions](#specificationExtens
}
}
},
"response": {
"payload": {
"type": "object",
"properties": {
"operationStatusCode": {
"type": "integer",
"format": "int32",
"description": "Operation result status code"
}
}
}
},
"bindings": {
"amqp": {
"ack": false
Expand Down Expand Up @@ -733,6 +746,14 @@ message:
$ref: "#/components/schemas/userCreate"
signup:
$ref: "#/components/schemas/signup"
response:
payload:
type: object
properties:
operationStatusCode:
type: integer
format: int32
description: Operation result status code
bindings:
amqp:
ack: false
Expand Down Expand Up @@ -1018,6 +1039,7 @@ Field Name | Type | Description
<a name="messageObjectBindings"></a>bindings | [Message Bindings Object](#messageBindingsObject) \| [Reference Object](#referenceObject) | A map where the keys describe the name of the protocol and the values describe protocol-specific definitions for the message.
<a name="messageObjectExamples"></a>examples | [Map[`string`, `any`]] | An array of key/value pairs where keys MUST be either **headers** and/or **payload**. Values MUST contain examples that validate against the [headers](#messageObjectHeaders) or [payload](#messageObjectPayload) fields, respectively. Example MAY also have the **name** and **summary** additional keys to provide respectively a machine-friendly name and a short summary of what the example is about.
<a name="messageObjectTraits"></a>traits | [[Message Trait Object](#messageTraitObject) &#124; [Reference Object](#referenceObject)] | A list of traits to apply to the message object. Traits MUST be merged into the message object using the [JSON Merge Patch](https://tools.ietf.org/html/rfc7386) algorithm in the same order they are defined here. The resulting object MUST be a valid [Message Object](#messageObject).
<a name="messageObjectResponse"></a>response | [[Message Object](#messageObject) &#124; [Reference Object](#referenceObject)] | A OPTIONAL definition of the message that the other party can expect to receive as a result to publish operation using this Message Object or as a result to receiving this Message Object in subscription. oneOf is allowed here to specify multiple messages, however, **a message MUST be valid only against one of the referenced message objects.**
Copy link
Member

@jonaslagoni jonaslagoni Oct 25, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have you thought about whether you want to target this PR towards 2.x versions or 3.x? 🤔

Version 2.x

If you choose to target the 2.x version (I assume this is your intention), you will run into a few perspective issues that will need to be considered, let me try to explain it (this blog post explains the operation confusion). This perspective issue is also why at least I, have not tried to push the feature yet, as I could not figure out the meaning of response in this context 😅

Current perspective

Let's consider the two operation keywords (publish and subscribe) and what it means when reading the spec file:

channels:
  basic:
    publish:
      message:
        payload:
        response:
          payload:

From the spec perspective, it means the following:

Others may publish to the channel basic with message payload x. Because I (the application) subscribe to the channel basic expecting a message payload x.

channels:
  basic:
    subscribe:
      message:
        payload:
        response:
          payload:

From the spec perspective, it means the following:

Others may subscribe to the channel basic expecting a message payload x. Because I (the application) publishes to the channel basic with the message payload x.

Response keyword

Now, let's try to use the response keyword, what would it mean in conjunction with the publish operation keyword? The only way I see is that it means:

Others may publish to the channel basic with message payload x and expect a response with message payload y. Because I (the application) subscribe to the channel basic expecting a message payload x and I will response with message payload y.

What would it mean in conjunction with the subscribe operation keyword? The only way I see is that it means:

Others may subscribe to the channel basic expecting the message payload x and I should response with message payload y. Because I (the application) publish to the channel basic with the message payload x and I will expect others to response with message payload y.

As you can see operation keywords do not "match" with the response keyword. As in most cases respond makes more sense, but it switches based on what you try to define.

Maybe it is not a problem, however, I can't see how this confusion won't come up, especially considering how confusing the operation keywords already are 😅

What are your thoughts here?

Version 3.x

If you choose to target 3.x, we are relying on #618 to build upon any agreed change from there 🙂 @fmvilas already included an example of how it could be achieved, just using reply keyword instead of response.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jonaslagoni thank you for heads up, i intent to submit this against 2.x, because it's not major change, and can be ported forward to 3.x as well, but I fear that 3.x compliance among various tools and implementations is too far away for my goal, to get the RFC into production/real-live usage, as soon as possible.

Also thanks for detailed introspection in taxonomy of specification, the perspective is in my opinion:

basic client -> server scenario

I (the application) publish the message payload x on channel basic and I may expect response message payload y which can be correlated with message payload x i've sent.

basic server -> client scenario

I (the application) may provide response message payload y to every message payload x server publishes on channel i've previously subscribed to

basic multi-user scenario (eg. messaging server)

I (the application) subscribe to channel basic and I may provide response message payload x to every received payload x which might originate from server (service/channel) directly or from other clients on the same hub (not sure this term is understandable in context)

And for the linked #618, i actually prefer terms in a physics kind-of way, where action / reaction and request / response are more clear to me than message / reply or request / reply, but I'd definitely prefer consensus on the taxonomy before this gets into 2.x and/or 3.x, since it wouldn't make any sense to change the verb between major versions of specs


This object can be extended with [Specification Extensions](#specificationExtensions).

Expand Down Expand Up @@ -1084,6 +1106,9 @@ Name | Allowed values | Notes
"traits": [
{ "$ref": "#/components/messageTraits/commonHeaders" }
],
"response": {
"$ref": "#/components/messages/userSignedUp"
},
"examples": [
{
"name": "SimpleSignup",
Expand Down Expand Up @@ -1136,6 +1161,8 @@ correlationId:
location: $message.header#/correlationId
traits:
- $ref: "#/components/messageTraits/commonHeaders"
response:
- $ref: "#/components/messages/userSignedUp"
examples:
- name: SimpleSignup
summary: A simple UserSignup example message
Expand Down