Mapping to NATS
Every message an MQTT or AMQP client sends is an ordinary NATS message on a subject. MQTT, AMQP and NATS clients that use the same subject see each other's messages. This page shows how topics and addresses become subjects and how message metadata becomes NATS headers. It also shows how a NATS client exchanges messages with MQTT and AMQP clients.
The examples below use these names for one subject:
| Client | Name |
|---|---|
| MQTT | topic orders/eu |
| AMQP | address orders.eu |
| NATS | subject orders.eu |
MQTT topics
The gateway converts each topic level to a subject token. It uses the same conversion as the MQTT server in nats-server.
| MQTT | NATS | Rule |
|---|---|---|
plant/line1/temp | plant.line1.temp | / becomes . |
spBv1.0/G1 | spBv1//0.G1 | . becomes // |
plant/+/temp | plant.*.temp | + becomes * |
plant/# | plant.> and plant | # becomes >, plus the parent level |
# | > | |
/plant | /.plant | An empty first level becomes / |
plant/ | plant./ | An empty last level becomes / |
plant//temp | plant./.temp | An empty middle level becomes / |
$share/g1/plant/+ | plant.*, queue group g1 | A shared subscription is a NATS queue subscription |
A subject converts back to a topic by the reverse rules. * and > in a
subject that a NATS client published stay as they are in the topic.
Rules:
- The gateway refuses a topic or filter that contains whitespace or DEL.
- The gateway refuses a filter with a level of only
*or>, because NATS reads that level as a wildcard. - A filter that starts with
+or#does not match topics that start with$. - The gateway does not deliver a message to MQTT clients if its subject
holds
+or#. No MQTT topic can hold these characters. - Your NATS permissions decide whether a client can reach a
$subject, such as$JS.>or$SYS.>. The gateway does not treat them differently.
AMQP addresses
An AMQP address is the NATS subject, with no conversion.
| AMQP | NATS |
|---|---|
Target orders.eu | Publishes to orders.eu |
Target orders/eu | Publishes to the one-token subject orders/eu, which no MQTT topic reaches |
Source orders.* or orders.> | Reads with the wildcard |
| Null target (anonymous relay) | Publishes to the to of each message |
| Dynamic source or target | A new inbox subject, for replies |
Source orders.eu::billing | Reads from the stream consumer billing, which an operator made |
Rules:
- A target cannot contain wildcards, empty tokens or whitespace.
- An unsettled receiver on a wildcard source needs one binding that covers the whole source. The gateway refuses a source that spans streams, or that mixes stored and unstored subjects, unless the receiver asks for presettled delivery.
- An operator queue (
<address>::<queue>) must be a pull consumer with explicit acks and nomax_bytes, on the stream that stores the address. Its filter subjects must match the address. Otherwise the gateway refuses the receiver:amqp:not-foundwhen the queue does not exist, andamqp:not-implementedoramqp:precondition-failedwhen it does not fit. - The gateway refuses sends to, and receivers on, its admin subjects
under
$MQGW.admin.>.
Routes
A route puts message properties in the subject. With mqtt.routes or
amqp.routes, a send to the route's subject goes to a subject that the
route's template builds. MQTT v5 User Properties and AMQP application
properties fill the template. The gateway does not route MQTT 3.1.1
publishes.
| Template | Send to | Property | NATS subject |
|---|---|---|---|
orders.{region} | orders | region=eu | orders.eu |
orders.{region} | orders | region=eu west | orders.eu%20west |
orders.{region} | orders | None | The gateway refuses the message |
Rules:
- The gateway percent-encodes
.,%,/,+,#, whitespace and control characters in a value. An empty value becomes%, and a value of*or>becomes%2Aor%3E. - MQTT subscribers see the encoded value in the topic, such as
orders/eu%20west. - If a property that the template names is missing, the gateway refuses a QoS 1 or 2 or unsettled message. It drops a QoS 0 or presettled message. Errors lists the codes.
- A send to a subject that the template makes, such as
orders.eu, must agree with its properties. The gateway handles a message toorders.euwithregion=usthe same as a message without the property.
Message bodies
The MQTT payload is the NATS payload, byte for byte.
An AMQP body of one data section becomes the NATS payload. The gateway
publishes any other body, such as an amqp-value string, in its AMQP
encoding, with the header Mqgw-Amqp-Body: sections. MQTT and NATS
clients then read AMQP bytes:
| AMQP body | NATS payload |
|---|---|
data hello | hello |
amqp-value "hello" | 00 53 77 a1 05 68 65 6c 6c 6f |
Send AMQP bodies as one data section when MQTT or NATS clients read
them. Many AMQP clients, Qpid JMS among them, send a string as an
amqp-value by default.
A message from MQTT or NATS reaches an AMQP receiver as one data
section.
Headers
The gateway puts message metadata in NATS headers named Mqgw-*. A field
that both protocols have uses one shared header, so a NATS service reads
one set of headers from either protocol. A field that only one protocol
has uses a header with that protocol's name in it.
| Header | Set by | Meaning |
|---|---|---|
Mqgw-QoS | MQTT, AMQP | 0, 1 or 2. AMQP sets 0 for presettled and 1 for unsettled. No header means 0 |
Mqgw-Content-Type | MQTT v5, AMQP | Content Type, or content-type |
Mqgw-Correlation-Id | MQTT v5, AMQP | Correlation Data, or correlation-id |
Mqgw-Reply-To | MQTT v5, AMQP | The reply subject: a Response Topic as a subject, or reply-to |
Mqgw-Expires | MQTT v5, AMQP | When the message expires, in Unix milliseconds |
Mqgw-Prop-<key> | MQTT v5, AMQP | One User Property or application property. A repeated key has one value for each |
Mqgw-Mqtt-Retain | MQTT | true when the publish set RETAIN |
Mqgw-Mqtt-Client-Id | MQTT | The client ID of the publisher |
Mqgw-Mqtt-Payload-Format | MQTT v5 | Payload Format Indicator, 0 or 1 |
Mqgw-Mqtt-Props-Order | MQTT v5 | The order of User Properties with different keys |
Mqgw-Amqp-Message-Id | AMQP | message-id |
Mqgw-Amqp-Subject | AMQP | The subject property (JMSType), not the NATS subject |
Mqgw-Amqp-Container-Id | AMQP | The container-id of the sender |
Mqgw-Amqp-Head, Mqgw-Amqp-Body, Mqgw-Amqp-Footer | AMQP | The sender's own sections, which AMQP receivers get unchanged |
Rules:
- A key or value that a header cannot hold is percent-encoded, and so is
%. The User Propertywith spaceis the headerMqgw-Prop-with%20space. - An AMQP application property becomes text. A number is decimal, a
boolean is
trueorfalse, a timestamp is Unix milliseconds, a uuid is its canonical form and binary is base64. The gateway dropsnull,decimal, lists and maps. - A core NATS message with a reply subject also has it as its NATS reply
subject. A stored message keeps it only in
Mqgw-Reply-To. - An MQTT 3.1.1 client sends and receives no properties.
- On a message that an AMQP client sent, AMQP receivers get the sender's
own sections. A NATS service that forwards it and changes
Mqgw-Prop-*,Mqgw-Content-TypeorMqgw-Correlation-Idchanges what MQTT and NATS receivers see, not what AMQP receivers see.
What a crossing loses
- An AMQP receiver gets only the first value of a repeated User Property key.
- An MQTT client gets AMQP application properties as text.
- A Content Type that is not ASCII does not reach AMQP.
- A value that MQTT cannot carry does not reach MQTT clients. Examples are text that is not valid UTF-8 and values longer than 65,535 bytes.
- MQTT and AMQP clients do not get NATS headers outside the table above,
such as a service's own
Trace-Id. - Each protocol's own headers reach only that protocol and NATS clients.
NATS clients
Read messages from MQTT and AMQP clients
Subscribe to the subject. Every message is on core NATS, stored or not, with the headers above. To read the stored messages, consume from the stream that the binding names.
Publish to MQTT and AMQP clients
A plain NATS publish reaches MQTT clients at QoS 0, not retained, with no
properties. It reaches AMQP receivers as one data section, with to set
to the subject.
Set headers to give MQTT v5 and AMQP clients the matching fields:
nats pub orders.eu '{"id": 42}' \
-H 'Mqgw-Content-Type:application/json' \
-H 'Mqgw-Prop-region:eu'
On a subject that a binding stores:
- An AMQP queue on the address delivers every message that the stream holds.
- An MQTT QoS 1 or 2 subscription gets the message from the stream only
when
Mqgw-QoSis1or2. Without it, the subscriber gets the message at QoS 0, and only when connected.
Request and reply
A NATS request reaches MQTT v5 clients with its reply subject as the
Response Topic, and AMQP clients with it as reply-to. Usually no binding
stores a reply subject, so these clients reply at QoS 0 or presettled.
A NATS service that answers MQTT or AMQP requests sends the reply to
Mqgw-Reply-To when the request has it, else to the message's reply
subject. The
reply needs Mqgw-Correlation-Id from the request when the requester
matches replies by correlation ID.
Shared subscriptions
An MQTT client subscribed to $share/g1/orders/+ is a member of the NATS
queue group g1 on orders.*. A NATS queue subscriber in g1 on that
subject joins the group, and gets a share of the QoS 0 messages.
Trust
These headers are only as trustworthy as the publisher. A NATS client can
set or omit any of them. For example, a forged Mqgw-Mqtt-Client-Id
changes which MQTT No Local subscribers get the message.