[2.0.0 REVIEW] Reusing channel definitions across files is hard
It's currently very hard to reuse channel definitions across multiple AsyncAPI files. The reason is that they contain the operation definition too. An example:
channels:
example:
subscribe:
message:
payload: ...
The document above describes an example channel with the subscribe operation. If this AsyncAPI file was describing an internal broker-centric architecture, it would probably have many applications consuming messages from this channel and therefore the definition of these subscribers would be:
channels:
example:
publish:
message:
payload: ...
As you can see, the only difference is the publish and subscribe verbs and possibly some other information related to the operation, like protocol bindings, description, summary, etc. And the most important part, message should belong to the channel, not the operation.
This is a spec flaw because it's intermixing channels-related and application-related information, making it hard to extract into a separate file for reusability.
Proposal
Find a new way to define channels and operations. Possibly syntactically separated so we can leverage the $ref mechanism to improve reusability.
In that particular case, I was under the impression that we had to use the $ref that would refer to a message in a different file ("library")? A view property would seem to confuse the original intent of the application yml file to describe the application's publish/subscribe operations.
I am just gonna spark the discussion with a suggestion to how we can solve this problem.
I suggest we change the layout of channels to be an array rather then an object and add a operation keyword to keep the channel and operation on the same object. Also I would remove the publish and subscribe operation keywords and merge the operation item object into the channel item object. This however does comes at the cost of readability, however i think this is something that should be sacrificed for usability. If we find any other keywords which are unique depending on the operation this could easily be added to the same object.
With the new setup you would define channels as such:
channels:
- example/: # keep the current setup
operation: publish/subscribe
And enables referencing for channels as such:
channels:
- $ref: Example.yaml # In this example nothing changes regardless of operation.
operation: publish/subscribe
Example.yaml
example/: # keep the current setup
parameters: # Channel parameters
message: # Message for the channel regardless of operation
That's a great suggestion, @jonaslagoni. I foresee a couple of issues at a glance:
- If channels is an array, it would be easy to have inconsistencies. For instance, you can have the
examplechannel defined many different times each of them with different details. For sure, we can avoid this by restricting the presence of a channel to just one item of the array but I don't completely like it. - In case we use
$ref(like in- $ref: Example.yaml), there would be an inconsistency if the Example.yaml file had more than one root key, e.g.,exampleandexample2. If we point to a specific one —- $ref: Example.yaml#/example—, then there's no way to know the name of the channel once the $ref has been resolved and dereferenced. I mean, theexamplepart would then be gone.
I've been working on a proposal some time ago but still have to find time to properly frame it. Will share as soon as possible.
1. If channels is an array, it would be easy to have inconsistencies. For instance, you can have the `example` channel defined many different times each of them with different details. For sure, we can avoid this by restricting the presence of a channel to just one item of the array but I don't completely like it.
Yea I agree I dont like the array as well... But if we wanna stick to an Object we could maybe use some sort of key instead of channel name :thinking: ? and still move the channel name inside the object like in the example.
2. In case we use `$ref` (like in `- $ref: Example.yaml`), there would be an inconsistency if the Example.yaml file had more than one root key, e.g., `example` and `example2`. If we point to a specific one —`- $ref: Example.yaml#/example`—, then there's no way to know the name of the channel once the $ref has been resolved and dereferenced. I mean, the `example` part would then be gone.
I dont understand? Cant it be achieved as the following: Example.yaml contains:
example:
example/: # channel, and keep the current object.
parameters: # Channel parameters
message: # Message for the channel regardless of operation
Which can then be referenced as - $ref: Example.yaml#/example?
Yes but nothing prevents you for doing something like:
example:
example/: # channel, and keep the current object.
parameters: # Channel parameters
message: # Message for the channel regardless of operation
example2/:
parameters: # Channel parameters
message: # Message for the channel regardless of operation
In this case, $ref: Example.yaml#/example would be referencing two different channels. See what I mean?
But with the proposed setup this would not be a valid file though 🤔 ?
Sure. Just arguing that it's leaving a lot of room for failure. We should aim to make it less error prone.
Ahh! Yes! Then I agree with you 😄
This issue has been automatically marked as stale because it has not had recent activity :sleeping: It will be closed in 30 days if no further activity occurs. To unstale this issue, add a comment with detailed explanation. Thank you for your contributions :heart:
In the case https://github.com/asyncapi/spec/issues/618 moves forward, would this issue be considered as fixed? cc @fmvilas
I'd say so, yes.