Possibility to Describe Channel Ownership
- Dominant language
- JavaScript
- Stars
- 5.3k
- Forks
- 382
- Avg merge
- 7m
- Merged PRs (30d)
- 4
Description
## Problem Statement: Channel Ownership
In a distributed architecture, applications typically _own_ channels and define a contract for using those channels. For example, an application might define an outgoing channel and publish events on that channel. The data model of the messages is then defined by that application's team. The owner of such a channel appears as the `sender` in the AsyncAPI. However, an application can also define incoming channels, for example when using the command pattern. In this case, the structure of the messages is defined by the application acting as the `receiver`.
### Ways to Use AsyncAPI
AsyncAPI provides means to describe an application’s asynchronous communication. In my view, it is not precisely
specified whether:
1. An application’s AsyncAPI should only include the channels that the application owns - that is, the channels to which the application publishes events and from which it receives commands - or
2. The AsyncAPI should represent the entire asynchronous communication of the application.
Tools that generate AsyncAPI from source code (such as Springwolf) automatically include every discoverable channel in the AsyncAPI. They therefore follow approach 2 by default.
### Problem
If an application’s AsyncAPI includes all channels - even those not owned by the application - it is impossible to
distinguish in the AsyncAPI which channels are defined by the application and which are merely consumed.
This has implications for using the AsyncAPI.
In our ongoing insurance project client code is generated from the full AsyncAPI spec - so even channels we merely consume end up in our generated SDKs. This should be a pretty typical use case.
Client code should only be generated for the channels/messages genuinely owned by the application. AsyncAPI 3.0, however, does not currently support this distinction. We initially considered using `tags` to mark channels, but tags in AsyncAPI are primarily intended for documentation grouping and carry no standardized semantic meaning. Tool support for tags is inconsistent - relying on them would force us to build and maintain custom filtering logic - and they lack the granularity and structure.
## Proposal: Channel Ownership
To solve the problem described above, the concept of `ownership` could be introduced into AsyncAPI. This is most
relevant for channels, but could also be applied to other AsyncAPI objects. By explicitly annotating each channel (or
object) with its ownership status, tooling can automatically filter out external dependencies and generate client code
only for those definitions truly maintained by the service. In addition, this metadata strengthens governance and
traceability, as it clearly identifies which team is responsible for evolving and supporting each part of the
asynchronous contract.
### Introducing an `ownership` Field on `channel` Objects
Below is a first, rough sketch of how an ownership concept could be modeled in AsyncAPI. It serves as an initial
proposal and can be refined further to cover additional use cases and objects.
#### Table of the `ownership` Attribute
| Field | Type | Required? | Description |
|------------------------|--------------|--------------------------------------|-------------------------------------------------------------------------------------------------------|
| `mode` | string | yes | Indicates whether the service **owns** the channel (`owner`) or **follows** the channel (`follower`). |
| `source` | object | no (only allowed if `mode=follower`) | Metadata about the application that owns the channel. |
| `source.id` | string (urn) | yes (within `source`) | The AsyncAPI ID of the application that actually owns the channel. |
| `source.version` | string | no | Version of the owner's specification on which this follower is based. |
| `source.url` | string (url) | no | URL to the original AsyncAPI document of the owning application. |
| `source.contact` | object | no | Contact details of the team owning the channel. |
| `source.contact.email` | email | yes (within `contact`) | Contact person or team email address in the owning service. |
> Note: All `source.*` fields are valid only if `mode=follower`.
#### Example Usage of the `ownership` Attribute
```yaml
asyncapi: '3.0.0'
id: urn:asyncapi:team-a:product-service
info:
title: ProductService
version: '1.0.0'
channels:
# This service owns the channel and publishes events here
productCreated:
ownership:
mode: owner
# This service follows the channel defined by OrderService
orderPlaced:
ownership:
mode: follower
source: # only permitted if mode=follower
id: urn:asyncapi:team-b:order-service
version: '2.1.0'
url: 'https://example.com/specs/order-service.yaml'
contact:
email: 'team-b@ecommerce.example.com'
```
#### Schema Definition of the `ownership` Attribute
```yaml
$schema: "http://json-schema.org/draft-07/schema#"
title: "AsyncAPI Channel Ownership Validation"
description: >
Optionally validates the `ownership` object for all channels in an AsyncAPI spec.
type: object
properties:
channels:
type: object
description: Collection of all channel definitions
additionalProperties:
type: object
description: Individual channel entry
properties:
ownership:
$ref: "#/components/schemas/Ownership"
components:
schemas:
OwnershipSource:
type: object
description: Metadata about the channel owner (only for followers)
properties:
id:
type: string
description: AsyncAPI ID of the owning application
version:
type: string
description: Version of the owner specification
url:
type: string
format: uri
description: URL to the original AsyncAPI document
contact:
type: object
description: Contact details of the owning team
properties:
email:
type: string
format: email
description: Email address of the contact in the owner service
required:
- email
required:
- id
Ownership:
type: object
description: Ownership definition (optional)
properties:
mode:
type: string
enum:
- owner
- follower
source:
$ref: "#/components/schemas/OwnershipSource"
required:
- mode
oneOf:
# owner: forbid any source
- description: Owner variant (no source allowed)
properties:
mode:
const: owner
required:
- mode
not:
required: [ source ]
# follower: source is optional
- description: Follower variant (source optional)
properties:
mode:
const: follower
required:
- mode
```
---
Many thanks to @danielkocot for talking this through with me beforehand.
Contributor guide
Research direction
Start with the AsyncAPI 3.0 channel definitions and the ownership YAML example and schema included in the issue. Compare the proposed owner and follower semantics with existing specification conventions and tooling needs. Done means the ownership model, validation rules, and applicability to channels or other objects are agreed and documented.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- json, yaml
- Domain
- backend-api-design
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100