Skip to content

Channel object have no Traits field (RFC Stage 1) #1220

Description

@ivangsa

As explained in #1219 Channel object have no traits field:

Proposal: Channel Traits (RFC Stage 1)

PR body + concrete edits for asyncapi/spec, source of truth spec/asyncapi.md.
Target release: 3.2.0 (next minor, non-breaking — new optional field).

This proposal adds traits to the Channel Object, closing the only gap left after Operation Traits and Message Traits. It standardizes channel binding composition and removes the combinatorial explosion of pre-built per-combination channels.


Edit 1 — Channel Object: add the traits field

In the Channel Object fixed-fields table in spec/asyncapi.md, add this row (place it last, after bindings):

| <a name="channelObjectTraits"></a>traits | [[Channel Trait Object](#channelTraitObject) &#124; [Reference Object](#referenceObject)] | A list of traits to apply to the channel object. Traits MUST be merged using [traits merge mechanism](#traitsMergeMechanism). The resulting object MUST be a valid [Channel Object](#channelObject). |

Copy the exact wording and anchor from the existing Message Object traits row in the same file so the merge reference (#traitsMergeMechanism vs inline) matches whatever 3.1.0 already uses. Do not invent the anchor — mirror the sibling row verbatim.


Edit 2 — New section: Channel Trait Object

Insert a new section immediately after the Channel Object section (and its example), mirroring the Operation Trait Object / Message Trait Object sections:

#### <a name="channelTraitObject"></a>Channel Trait Object

Describes a trait that MAY be applied to a [Channel Object](#channelObject). This object MAY contain any property from the [Channel Object](#channelObject), except the `address`, `messages`, and `traits` properties.

If you're looking to apply traits to an operation, see the [Operation Trait Object](#operationTraitObject). If you're looking to apply traits to a message, see the [Message Trait Object](#messageTraitObject).

##### Fixed Fields

| Field Name | Type | Description |
|---|---|---|
| <a name="channelTraitObjectTitle"></a>title | `string` | A human-friendly title for the channel. |
| <a name="channelTraitObjectSummary"></a>summary | `string` | A short summary of the channel. |
| <a name="channelTraitObjectDescription"></a>description | `string` | An optional description of this channel. [CommonMark syntax](https://spec.commonmark.org/) can be used for rich text representation. |
| <a name="channelTraitObjectServers"></a>servers | [[Reference Object](#referenceObject)] | An array of `$ref` pointers to the definition of the [Servers](#serverObject) in which this channel is available. If the channel is located in the [root Channels Object](#channelsObject), it MUST point to a subset of server definitions located in the [root Servers Object](#serversObject), and MUST NOT point to a subset of server definitions located in the [Components Object](#componentsObject) or anywhere else. If the channel is located in the [Components Object](#componentsObject), it MAY point to a [Server Objects](#serverObject) in any location. If `servers` is absent or empty, this channel MUST be available on all the servers defined in the [Servers Object](#serversObject). |
| <a name="channelTraitObjectParameters"></a>parameters | Map[`string`, [Parameter Object](#parameterObject) &#124; [Reference Object](#referenceObject)] | A map of the parameters included in the channel address. It MUST be present only when the address contains [Channel Address Expressions](#channelAddressExpressions). |
| <a name="channelTraitObjectTags"></a>tags | [Tags Object](#tagsObject) | A list of tags for logical grouping of channels. |
| <a name="channelTraitObjectExternalDocs"></a>externalDocs | [External Documentation Object](#externalDocumentationObject) &#124; [Reference Object](#referenceObject) | Additional external documentation for this channel. |
| <a name="channelTraitObjectBindings"></a>bindings | [Channel Bindings Object](#channelBindingsObject) &#124; [Reference Object](#referenceObject) | A map where the keys describe the name of the protocol and the values describe protocol-specific definitions for the channel. |

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

##### Channel Trait Object Example

​```yaml
bindings:
  kafka:
    partitions: 6
    replicas: 3
​```

Scope decision (resolve in review): the table above is the full mirror (channel minus address/messages/traits). If consensus lands on the minimal set, drop the servers and parameters rows and the corresponding JSON Schema properties. The motivating use case (binding composition) only requires bindings; title/summary/description/tags/externalDocs are kept for parity with Operation/Message Traits.


Edit 3 — Components Object: add channelTraits

In the Components Object fixed-fields table, add this row next to operationTraits and messageTraits:

| <a name="componentsObjectChannelTraits"></a>channelTraits | Map[`string`, [Channel Trait Object](#channelTraitObject) &#124; [Reference Object](#referenceObject)] | An object to hold reusable [Channel Trait Objects](#channelTraitObject). |

If the Components Object has a worked example block, add a channelTraits entry alongside the existing operationTraits/messageTraits examples.


Edit 4 — Full worked example (for the prose / examples directory)

asyncapi: 3.2.0
info:
  title: Account Service
  version: 1.0.0
components:
  channelTraits:
    kafkaReplicated:
      bindings:
        kafka:
          partitions: 6
          replicas: 3
    kafkaCompacted:
      bindings:
        kafka:
          topicConfiguration:
            cleanup.policy: [compact]
  messages:
    UserSignedUp:
      payload:
        type: object
        properties:
          userId:
            type: string
channels:
  userSignedUp:
    address: user.signedup
    traits:
      - $ref: '#/components/channelTraits/kafkaReplicated'
      - $ref: '#/components/channelTraits/kafkaCompacted'
    messages:
      userSignedUp:
        $ref: '#/components/messages/UserSignedUp'

After merge, userSignedUp resolves to a channel with partitions: 6, replicas: 3, and cleanup.policy: [compact] — composed from two orthogonal traits instead of a replicated-compacted channel definition.


Implementation checklist (files per repo)

asyncapi/spec

  • spec/asyncapi.md — Edits 1–4 above (this is the only source-of-truth file).
  • Run markdownlint locally before pushing:
    docker run -v $PWD:/workdir ghcr.io/igorshubovych/markdownlint-cli:v0.35.0 "spec/asyncapi.md"

asyncapi/spec-json-schemas (required to reach Stage 2 Draft)

  • Duplicate definitions/3.1.0/definitions/3.2.0/, then search-replace 3.1.03.2.0 inside the new folder.
  • Duplicate examples/3.1.0/examples/3.2.0/ (same version replace); add a channel-traits example.
  • New file definitions/3.2.0/channelTrait.json (see channelTrait.json attached — but copy the exact sub-schema $ref filenames from the sibling channel.json in the same folder; don't trust the names blindly).
  • Edit definitions/3.2.0/channel.json — add a traits property:
    "traits": {
      "type": "array",
      "items": {
        "oneOf": [
          { "$ref": "http://asyncapi.com/definitions/3.2.0/Reference.json" },
          { "$ref": "http://asyncapi.com/definitions/3.2.0/channelTrait.json" }
        ]
      }
    }
  • Edit definitions/3.2.0/components.json — add a channelTraits map mirroring operationTraits/messageTraits (values: oneOf [Reference, channelTrait]).
  • Edit root index.js and index.d.ts — register 3.2.0 (and the -without-$id variant) exactly as prior versions are registered.
  • Bundled schemas/3.2.0.json and schemas/3.2.0-without-$id.json are generated by tools/bundler — run the bundler, don't hand-edit them.

asyncapi/parser-js (required to reach Stage 2 Draft, fully merged for Stage 3 Accepted)

  • Apply channel traits in the model the same way operation/message traits are applied (same merge util, traits applied in order, Channel Object wins).
  • Add the Channel.traits() accessor / model methods consistent with Operation/Message.
  • Add test fixtures: a doc using channelTraits + inline traits, asserting the merged channel and binding composition.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions