Skip to content

nats

stable

Encode and parse NATS messaging protocol text frames for publish/subscribe communication, including queue groups, headers (NATS 2.2+), and server INFO parsing.

use plugin nats::{encode_connect, encode_pub, encode_pub_with_reply, …}
15 functions Networking
/ filter jk navigate Esc clear
Functions (15)
  1. encode_connect Encode a CONNECT command string
  2. encode_pub Encode a PUB command string
  3. encode_pub_with_reply Encode PUB with a reply-to subject
  4. encode_sub Encode a SUB command string
  5. encode_sub_with_queue Encode SUB with a queue group
  6. encode_unsub Encode an UNSUB command string
  7. encode_unsub_with_max Encode UNSUB with a max-messages limit
  8. encode_ping Encode a PING command string
  9. encode_pong Encode a PONG command string
  10. encode_hpub Encode an HPUB command with headers
  11. parse_msg Parse a raw MSG line into a table
  12. parse_info Parse a server INFO line into a table
  13. parse_ok Check if a raw line is +OK
  14. parse_err Extract error message from a -ERR line
  15. is_op Check if a line starts with a given NATS operation

Overview

nats is a stateless codec for the NATS text protocol: it turns publish/subscribe intentions into the exact wire frames a NATS server expects, and parses the frames the server sends back. It opens no sockets and holds no connection — every function is a pure transformation between Zolo values and protocol strings, so you stay in control of the transport (raw TCP, a socket plugin, a test harness) and feed bytes through these helpers.

The two halves mirror each other. The encode_* functions build client commands (CONNECT, PUB, SUB, UNSUB, PING/PONG, and headered HPUB), each returning a ready-to-send string with the correct byte counts and \r\n terminators. The parse_* and is_op functions decode what comes back: MSG frames into {subject, sid, reply_to, payload, bytes_count} tables, the server INFO line into a flat table, and the simple +OK / -ERR acknowledgements. Reach for it when you are speaking NATS directly and want correct framing without pulling in a full client library.

Common patterns

Open a connection: send CONNECT, then subscribe and publish.

use plugin nats::{encode_connect, encode_sub, encode_pub}

let handshake = encode_connect(false, false, "billing-service")
let sub = encode_sub("orders.*", "1")
let msg = encode_pub("orders.created", '{"id":42}')
print("{handshake}{sub}{msg}")

Read a server frame: branch on the operation, then parse the matching shape.

use plugin nats::{is_op, parse_msg, parse_err}

let frame = "MSG orders.created 1 9\r\n{\"id\":42}\r\n"
if is_op(frame, "MSG") {
  let msg = parse_msg(frame)
  print("got {msg["bytes_count"]} bytes on {msg["subject"]}")
} else if is_op(frame, "-ERR") {
  print("server error: {parse_err(frame)}")
}

Request-reply: publish with a reply inbox and auto-unsubscribe after one answer.

use plugin nats::{encode_sub, encode_unsub_with_max, encode_pub_with_reply}

let inbox = "_INBOX.req1"
let sub = encode_sub(inbox, "9")
let unsub = encode_unsub_with_max("9", 1)
let req = encode_pub_with_reply("rpc.add", inbox, '{"a":1,"b":2}')
print("{sub}{unsub}{req}")

Encode a CONNECT command string

Encodes a NATS CONNECT command with the given client options. The resulting string includes lang set to "zolo" and version to "0.1.0". Send this immediately after the TCP connection is established and the server INFO is received.

use plugin nats::{encode_connect}

let cmd = encode_connect(false, false, "my-service")
print(cmd)

Encode a PUB command string

Encodes a PUB command to publish a message to a subject. The byte count is automatically computed from the payload length.

use plugin nats::{encode_pub}

let cmd = encode_pub("events.user.created", '{"id":42}')
print(cmd)

A subject can be hierarchical, and the payload can be any text — the frame is the same shape regardless of content:

use plugin nats::{encode_pub}

print(encode_pub("metrics.cpu.host1", "load=0.73"))
print(encode_pub("logs.app", "service started"))

Encode PUB with a reply-to subject

Encodes a PUB command with a reply-to subject, enabling request-reply patterns. The subscriber can send a response back to reply_to.

use plugin nats::{encode_pub_with_reply}

let cmd = encode_pub_with_reply("rpc.add", "_INBOX.abc123", '{"a":1,"b":2}')
print(cmd)

Encode a SUB command string

Encodes a SUB command to subscribe to a subject. sid is a client-assigned subscription ID string used to correlate incoming MSG frames.

use plugin nats::{encode_sub, encode_unsub}

let sub = encode_sub("events.>", "1")
let unsub = encode_unsub("1")

Encode SUB with a queue group

Encodes a SUB command with a queue group name. Messages to the subject are load-balanced across all subscribers in the same queue group.

use plugin nats::{encode_sub_with_queue}

let cmd = encode_sub_with_queue("jobs.process", "workers", "2")
print(cmd)

Encode an UNSUB command string

Encodes an UNSUB command to cancel a subscription by its ID.

use plugin nats::{encode_unsub}

let cmd = encode_unsub("1")
print(cmd)

Encode UNSUB with a max-messages limit

Encodes an UNSUB command that automatically unsubscribes after receiving max_msgs messages. Useful for one-shot request-reply patterns.

use plugin nats::{encode_sub, encode_unsub_with_max}

let sub = encode_sub("_INBOX.abc123", "3")
let unsub = encode_unsub_with_max("3", 1)

Encode a PING command string

Returns the PING\r\n command string for keep-alive health checks.

use plugin nats::{encode_ping, encode_pong, is_op}

let ping = encode_ping()
let pong = encode_pong()
print(is_op(ping, "PING"))

Encode a PONG command string

Returns the PONG\r\n response string. Send this when the server sends a PING to keep the connection alive.

use plugin nats::{encode_pong}

let pong = encode_pong()
print(pong)

Encode an HPUB command with headers

Encodes an HPUB command (NATS 2.2+) with HTTP-style message headers. headers is a table of key-value string pairs. The header block starts with NATS/1.0\r\n.

use plugin nats::{encode_hpub}

let cmd = encode_hpub(
  "events.order",
  #{"Nats-Msg-Id": "msg-001", "Content-Type": "application/json"},
  '{"order_id":99}'
)
print(cmd)

Parse a raw MSG line into a table

Parses a raw NATS MSG frame string into {subject, sid, reply_to, payload, bytes_count}. reply_to is nil if the message has no reply subject.

use plugin nats::{parse_msg}

let raw = "MSG events.user 1 18\r\n{\"id\":42,\"name\":\"Alice\"}\r\n"
let msg = parse_msg(raw)
print(msg["subject"])
print(msg["payload"])
print(msg["reply_to"])

When a MSG carries a reply-to subject (the four-token header form), it surfaces in reply_to so you can answer the request:

use plugin nats::{parse_msg, encode_pub}

let raw = "MSG rpc.add 7 _INBOX.r1 11\r\n{\"a\":1,\"b\":2}\r\n"
let msg = parse_msg(raw)
let answer = encode_pub(msg["reply_to"], '{"sum":3}')
print(answer)

Parse a server INFO line into a table

Parses the server INFO line sent on connection into a flat table of key-value pairs. Handles string, integer, float, bool, and null JSON values.

use plugin nats::{parse_info}

let raw = 'INFO {"server_id":"abc","version":"2.9.0","max_payload":1048576,"proto":1}\r\n'
let info = parse_info(raw)
print(info["version"])
print(info["max_payload"])

Boolean and null fields come through as their native Zolo values, which makes capability checks straightforward:

use plugin nats::{parse_info}

let info = parse_info('INFO {"headers":true,"auth_required":false,"nonce":null}')
if info["headers"] {
  print("server supports HPUB headers")
}

Check if a raw line is +OK

Returns true if the raw line is exactly +OK (trimmed). The NATS server sends +OK to acknowledge certain commands when verbose mode is enabled.

use plugin nats::{parse_ok, parse_err}

print(parse_ok("+OK\r\n"))
print(parse_ok("-ERR 'Unknown Protocol Operation'\r\n"))

Extract error message from a -ERR line

Extracts the error message text from a -ERR line, stripping the leading tag and surrounding single quotes. Returns nil if the line is not a -ERR response.

use plugin nats::{parse_err}

let msg = parse_err("-ERR 'Authorization Violation'\r\n")
print(msg)

let none = parse_err("+OK\r\n")
print(none)

Check if a line starts with a given NATS operation

Checks whether a raw NATS protocol line starts with the given operation string (e.g. "MSG", "PING", "+OK", "-ERR"). The check is prefix-based and handles line endings.

use plugin nats::{is_op}

let line = "MSG events.user 1 5\r\nhello\r\n"
print(is_op(line, "MSG"))
print(is_op(line, "PING"))

Because the match is whole-token, it distinguishes control frames cleanly and is the natural first step in a read loop that dispatches each incoming frame:

use plugin nats::{is_op, encode_pong}

let frame = "PING\r\n"
if is_op(frame, "PING") {
  print(encode_pong())
}
enespt-br