Wire contracts are AsyncAPI β 2.x and 3.x are both read. A wire spec is an
<name>.asyncapi.yaml (or
.yml) in a directory named
contracts/,
asyncapi/ or
*-contracts. The version decides only
where the route is written, and wiregraph reads it in the right place for the version it declares. In
3.x the route is
channels.<key>.address and the channel
key is an arbitrary id that is deliberately
not a token (naming a 3.x channel
submit-order mints nothing on its own); direction comes from the top-level
operations: map. In
2.x there is no
address: field: the channel
key is the address and is read as the token, rooted (
/alerts/{id}/escalate) or unrooted (
smartylighting/streetlights/event/measured, the idiomatic 2.x spelling), and both forms match the route as your source writes it,
{param} segments included; direction comes from each channel's own
publish /
subscribe. Payload field names under
properties: are tokens in both versions. A version that is neither 2 nor 3 is
warned about by file and by version β a 1.x or 4.x doc is read with the 3.x rules, which may find nothing, and the build logs
β <file>: asyncapi <version> β wiregraph reads AsyncAPI 2.x and 3.x only. A spec with no
asyncapi: line at all is treated as 3.x-shaped. Separately, a spec that ends up with
zero matchable tokens gets its own named warning (
β <file>: β¦ this spec defines NO matchable tokens) β that, not the version, is the line to look for when a contract loads and governs nothing.
asyncapi: '3.0.0' # 2.x is read too β see the 2.x example below
info:
title: Terminal Wire # the contract id β UNIQUE across all specs
version: 0.1.0
channels:
submit-order:
address: /orders/{id}/items # matched token, kept parameterized
x-wiregraph-producers: [terminal] # COMPARTMENT names that call it
x-wiregraph-consumers: [orders_api] # COMPARTMENT names that serve it
messages:
request:
payload:
type: object
properties:
order_id: { type: string } # payload fields are tokens too
operations:
receive-submit-order:
action: receive # server receives β client-to-server
channel: { $ref: '#/channels/submit-order' }
messages: [{ $ref: '#/channels/submit-order/messages/request' }]
The same contract in 2.x, where the channel key carries the route and the channel's own publish/subscribe carries the direction:
asyncapi: '2.6.0'
info:
title: Terminal Wire # the contract id β UNIQUE across all specs
version: 0.1.0
channels:
/orders/{id}/items: # 2.x: the KEY is the address = the token
x-wiregraph-producers: [terminal]
x-wiregraph-consumers: [orders_api]
publish: # 2.x: published INTO the app β client-to-server
message:
payload:
type: object
properties:
order_id: { type: string } # payload fields are tokens too
info.title is the id. It must be unique across every spec in the project, in both formats β two specs sharing a title merge into one contract node.
- Two kinds of token are matched against your code: every channel address (3.x
address:, 2.x the channel key), and every key under any properties: map. An address starting with / is matched as a route, with each {param} segment matching however the source writes it (:id, ${id}, {id}, or a concrete value); an address that does not start with / is matched literally, which is how topics, 2.x channel keys, routing keys and env-var names work.
- Tokens must be distinctive or they are dropped: a route needs 5+ characters and must not be a generic endpoint (
/health, /metrics, /api, /status, /versionβ¦); a non-route needs a dotted/colon key, an underscore with 6+ characters, or a 10+ character camelCase name. Generic words (id, type, state, messageβ¦) and ubiquitous env vars (DATABASE_URL, PORT, LOG_LEVELβ¦) are always dropped β a generic token would match every file and manufacture phantom seams.
x-wiregraph-producers / x-wiregraph-consumers are what make the edge directed. They are arrays of compartment names on the channel β the names graph_status reports. Omit them and you still get references, but a weaker seam.
- Direction is read wherever the version keeps the operations, server-perspective either way. In 3.x that is the top-level
operations: map: action: receive tags that operation's fields clientβserver, action: send tags them serverβclient, and an operation's reply.messages get the opposite. In 2.x it is the channel's own members: publish is published into the app (clientβserver) and subscribe is what the app publishes out (serverβclient). A /-leading token with no operation on either shape defaults to clientβserver.