{"id":16389605,"url":"https://github.com/yuce/nats_msg","last_synced_at":"2025-10-26T13:30:38.698Z","repository":{"id":62429982,"uuid":"51208820","full_name":"yuce/nats_msg","owner":"yuce","description":"NATS Protocol Message Encoder/Decoder","archived":false,"fork":false,"pushed_at":"2016-03-23T20:39:51.000Z","size":34,"stargazers_count":3,"open_issues_count":0,"forks_count":3,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-01-31T19:09:17.571Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Erlang","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/yuce.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-02-06T15:54:57.000Z","updated_at":"2023-02-24T01:21:04.000Z","dependencies_parsed_at":"2022-11-01T20:09:49.878Z","dependency_job_id":null,"html_url":"https://github.com/yuce/nats_msg","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yuce%2Fnats_msg","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yuce%2Fnats_msg/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yuce%2Fnats_msg/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yuce%2Fnats_msg/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/yuce","download_url":"https://codeload.github.com/yuce/nats_msg/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":238328493,"owners_count":19453833,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-11T04:33:45.275Z","updated_at":"2025-10-26T13:30:38.393Z","avatar_url":"https://github.com/yuce.png","language":"Erlang","funding_links":[],"categories":[],"sub_categories":[],"readme":"# nats_msg\n\n\n**nats_msg** is a pure Erlang NATS message encoder/decoder library for\n[NATS](http://nats.io/) high performance messaging platform.\nFor details about NATS protocol, see:\n[NATS Protocol](http://nats.io/documentation/internals/nats-protocol). It doesn't\nhave any dependency other than Erlang/OTP (16+ *should* be OK) and optionally\n[rebar3](http://www.rebar3.org/).\n\n## News\n\n* **Version 0.4.1** (*2016-03-23*):\n    * This version is incompatible with previous versions of the library.\n    * Decoding is lazy, in the sense that, only a single message is decoded whenever\n    the decode is called. You can use `nats_msg:decode_all/1` to simulate the old behaviour.\n    * HUGE performance improvements (2x - 100x).\n    * The parser is much more stricter now.\n    * Encoding functions return iodata instead of binary.\n    * You can use iodata anywhere a binary is expected.\n\n\n## Install\n\n**nats_msg** uses [rebar3](http://www.rebar3.org/) to build and tests and\nit is available on [hex.pm](https://hex.pm/). Just include the following\nin your `rebar.config`:\n\n```erlang\n{deps, [nats_msg]}.\n```\n\n## Tests\n\nRun the tests using:\n\n    $ rebar3 eunit\n\n## Build\n\n    $ rebar3 compile\n\n## Usage\n\n\u003e IMPORTANT!\n\u003e\n\u003e Before running any decoding functions, `nats_msg:init/0` must be called once.\n\nBinaries and iodata are used exclusively throughout the library.\n\nCurrently, no error handling is performed during encoding/decoding. You can protect\nagainst crashes by wrapping library functions between `try...catch`.\n\n`INFO` and `CONNECT` messages have a JSON object as their parameter; but in order to\nnot introduce a dependency, **nats_msg** does not encode/decode JSON objects. These parameters\nare kept or returned as binaries. You can use [jsx](https://github.com/talentdeficit/jsx) or [jiffy](https://github.com/davisp/jiffy)\nto deal with JSON. See the **INFO** and **CONNECT** sections in this document for examples.\n\n### Encoding\n\nEncoding a message produces an IO list. `nats_msg:encode/1` takes an atom as the name of the\nmessage or a tuple which contains the name, parameters and payload of the message.\n\nThe general form of `nats_msg:encode/1` parameters is:\n\n* `Name :: atom()`: For messages taking no parameters,\n* `{Name :: atom(), Parameters :: {iodata() | int(), ...}}` for messages taking parameters but\nnot a payload,\n* `{Name :: atom(), Parameters :: {iodata() | int(), ...}, Payload :: iodata()}` for messages\ntaking parameters and a payload.\n\nMessages of the same type always have the same structure, even if some of the values are\n`undefined`. Some examples:\n\n* `nats_msg:encode(ping)` produces a `PING` message,\n* `nats_msg:encode({sub, {\u003c\u003c\"INBOX\"\u003e\u003e, undefined, \u003c\u003c\"2\"\u003e\u003e}}` produces a `SUB` message with\nsubject `\u003c\u003c\"INBOX\"\u003e\u003e` and SID `\u003c\u003c\"2\"\u003e\u003e`. This particular message has no *queue group*, so\nthat field is set to `undefined`.\n* `nats_msg:encode({pub, {\u003c\u003c\"FOO\"\u003e\u003e, undefined, 11}, \u003c\u003c\"Hello NATS!\"\u003e\u003e}` produces a `PUB` message\nwith subject `\u003c\u003c\"FOO\"\u003e\u003e` and payload `\u003c\u003c\"Hello NATS!\"\u003e\u003e` of size `11` and no *reply to* subject.\n\nThe library has convenience functions for all messages, like `nats_msg:ping/0`, which are\ndiscussed later in this document.\n\n### Decoding\n\nDecoding a binary/iodata produces a `{Message, RemainingBinary}` tuple.\n`Message` is either `[]` if the data is not sufficient to decode the message, or the a term for the message,\nand `RemainingBinary` is the part of the input which\nwasn't decoded and returned. The latter is very useful when dealing with streams, where\nthe input is chunked and appending chunks is required to be able to decode messages.\nIn those situations, just prepend `RemainingBinary` to the next binary chunk before attempting\nto decode it.\n\nThe `Message`  be used as an input to `nats_msg:encode`, like:\n\n```erlang\nSomeBinary = ...\n{Msg, Remaining} = nats_msg:decode(SomeBinary),\nReEncodedBinary = nats_msg:encode(Msg),\n% ReEncodedBinary = SomeBinary\n```\n\n### INFO Message\n\n[NATS Spec](http://nats.io/documentation/internals/nats-protocol/#INFO)\n\n#### Encode\n\n```erlang\nServerInfo = #{\u003c\u003c\"auth_required\"\u003e\u003e =\u003e true, \u003c\u003c\"server_id\"\u003e\u003e =\u003e \u003c\u003c\"0001-SERVER\"\u003e\u003e},\nBinaryInfo = jsx:encode(ServerInfo),\nBinaryMsg = nats_msg:info(BinaryInfo).\n```\n\n#### Decode\n\n```erlang\nChunk = \u003c\u003c\"INFO {\\\"auth_required\\\":true,\\\"server_id\\\":\\\"0001-SERVER\\\"}\\r\\n\"\u003e\u003e,\n{Msg, _} = nats_msg:decode(Chunk),\n{info, BinaryInfo} = Msg,\nServerInfo = jsx:decode(BinaryInfo, [return_maps]).\n```\n\n### CONNECT Message\n\n[NATS Spec](http://nats.io/documentation/internals/nats-protocol/#CONNECT)\n\n#### Encode\n\n```erlang\nConnectInfo = #{\u003c\u003c\"auth_required\"\u003e\u003e =\u003e true, \u003c\u003c\"server_id\"\u003e\u003e =\u003e \u003c\u003c\"0001-SERVER\"\u003e\u003e},\nBinaryInfo = jsx:encode(ServerInfo),\nBinaryMsg = nats_msg:connect(BinaryInfo).\n```\n\n#### Decode\n\n```erlang\nChunk = \u003c\u003c\"CONNECT {\\\"verbose\\\":true,\\\"name\\\":\\\"the_client\\\"}\\r\\n\"\u003e\u003e,\n{Msg, _} = nats_msg:decode(Chunk),\n{connect, BinaryInfo} = Msg,\nClientInfo = jsx:decode(BinaryInfo, [return_maps]).\n```\n\n### PUB Message\n\n[NATS Spec](http://nats.io/documentation/internals/nats-protocol/#PUB)\n\n#### Encode\n\nNotify subscribers of a subject:\n\n```erlang\nBinaryMsg = nats_msg:pub(\u003c\u003c\"NOTIFY.INBOX\"\u003e\u003e).\n```\n\nSend some data (*payload*) to subscribers, providing a *reply* subject:\n\n```erlang\nBinaryMsg = nats_msg:pub(\u003c\u003c\"FOOBAR\"\u003e\u003e, \u003c\u003c\"REPRAP\"\u003e\u003e, \u003c\u003c\"Hello, World!\"\u003e\u003e).\n```\n\nSend some data (*payload*) to subscribers (*without a reply subject*):\n\n```erlang\nBinaryMsg = nats_msg:pub(\u003c\u003c\"FOOBAR\"\u003e\u003e, undefined, \u003c\u003c\"Hello, World!\"\u003e\u003e).\n```\n\n### Decode\n\nPublish notification:\n\n```erlang\nChunk = \u003c\u003c\"PUB NOTIFY 0\\r\\n\\r\\n\"\u003e\u003e,\n{Msg, _} = nats_msg:decode(Chunk),\n{pub, {Subject, ReplyTo, Payload}} = Msg,\n% Subject = \u003c\u003c\"NOTIFY\"\u003e\u003e,\n% ReplyTo = undefined,\n% Payload = \u003c\u003c\u003e\u003e.\n```\n\nPublish message with subject, replier and payload:\n\n```erlang\nChunk = \u003c\u003c\"PUB FRONT.DOOR INBOX.22 11\\r\\nKnock Knock\\r\\n\"\u003e\u003e,\n{Msg, _} = nats_msg:decode(Chunk),\n{pub, {Subject, ReplyTo, Payload}} = Msg,\n% Subject = \u003c\u003c\"FRONT.DOOR\"\u003e\u003e,\n% ReplyTo = \u003c\u003c\"INBOX.22\"\u003e\u003e,\n% Payload = \u003c\u003c\"Knock Knock\"\u003e\u003e.\n```\n\n### SUB Message\n\n[NATS Spec](http://nats.io/documentation/internals/nats-protocol/#SUB)\n\n#### Encode\n\nSubscribe message with subject and SID:\n\n```erlang\nBinaryMsg = nats_msg:sub(\u003c\u003c\"FOO\"\u003e\u003e, \u003c\u003c\"1\"\u003e\u003e).\n```\n\nSubscribe message with subject, group queue and SID:\n\n```erlang\nBinaryMsg = nats_msg:sub(\u003c\u003c\"BAR\"\u003e\u003e, \u003c\u003c\"G1\"\u003e\u003e, \u003c\u003c\"44\"\u003e\u003e)\n```\n\n#### Decode\n\n```erlang\nChunk = \u003c\u003c\"SUB FOO 1\\r\\n\"\u003e\u003e,\n{Msg, _} = nats_msg:decode(Chunk),\n{sub, {Subject, GroupQueue, Sid}} = Msg,\n% Subject = \u003c\u003c\"FOO\"\u003e\u003e,\n% GroupQueue = undefined,\n% Sid = \u003c\u003c\"1\"\u003e\u003e.\n```\n\n### UNSUB Message\n\n[NATS Spec](http://nats.io/documentation/internals/nats-protocol/#UNSUB)\n\n#### Encode\n\nUnsubscribe message with SID:\n\n```erlang\nBinaryMsg = nats_msg:unsub(\u003c\u003c\"1\"\u003e\u003e).\n```\n\nUnsubscribe message with SID and *max messages*:\n\n```erlang\nBinaryMsg = nats_msg:unsub(\u003c\u003c\"1\"\u003e\u003e, 10).\n```\n\n#### Decode\n\n```erlang\nChunk = \u003c\u003c\"UNSUB 1 10\\r\\n\"\u003e\u003e,\n{Msg, _} = nats_msg:decode(Chunk),\n{unsub, {Sid, MaxMessages}} = Msg,\n% Sid = \u003c\u003c\"1\"\u003e\u003e,\n% MaxMessages = 10\n```\n\n### MSG Message\n\n[NATS Spec](http://nats.io/documentation/internals/nats-protocol/#MSG)\n\n#### Encode\n\nMessage with subject and SID:\n\n```erlang\nBinaryMsg = nats_msg:msg(\u003c\u003c\"FOO\"\u003e\u003e, \u003c\u003c\"5\"\u003e\u003e).\n```\n\nMessage with subject, sid, *reply to subject* and payload:\n\n```erlang\nBinaryMsg = nats_msg:msg(\u003c\u003c\"FOO\"\u003e\u003e, \u003c\u003c\"5\"\u003e\u003e, \u003c\u003c\"INBOX\"\u003e\u003e, \u003c\u003c\"Hello!\"\u003e\u003e).\n```\n\nMessage with subject, sid and payload:\n\n```erlang\nBinaryMsg = nats_msg:msg(\u003c\u003c\"FOO\"\u003e\u003e, \u003c\u003c\"5\"\u003e\u003e, undefined, \u003c\u003c\"Hello!\"\u003e\u003e).\n```\n\n#### Decode\n\nMessage with subject, sid and payload:\n\n```erlang\nChunk = \u003c\u003c\"MSG FOO.BAR 9 13\\r\\nHello, World!\\r\\n\"\u003e\u003e,\n{Msg, _} = nats_msg:decode(Chunk),\n{msg, {Subject, Sid, ReplyTo, Payload}} = Msg,\n% Subject = \u003c\u003c\"FOO.BAR\"\u003e\u003e,\n% Sid = \u003c\u003c\"9\"\u003e\u003e,\n% ReplyTo = undefined,\n% Payload = \u003c\u003c\"Hello, World!\"\u003e\u003e.\n```\n\n### PING Message\n\n[NATS Spec](http://nats.io/documentation/internals/nats-protocol/#PING)\n\n#### Encode\n\n```erlang\nBinaryMsg = nats_msg:ping().\n```\n\n#### Decode\n\n```erlang\n{Msg, _} = nats_msg:decode(\u003c\u003c\"PING\\r\\n\"\u003e\u003e),\n% Msg = ping\n```\n\n### PONG Message\n\n[NATS Spec](http://nats.io/documentation/internals/nats-protocol/#PONG)\n\n#### Encode\n\n```erlang\nBinaryMsg = nats_msg:pong().\n```\n\n#### Decode\n\n```erlang\n{Msg, _} = nats_msg:decode(\u003c\u003c\"PONG\\r\\n\"\u003e\u003e),\n% Msg = pong\n```\n\n### +OK Message\n\n[NATS Spec](http://nats.io/documentation/internals/nats-protocol/#OKERR)\n\n#### Encode\n\n```erlang\nBinaryMsg = nats_msg:ok().\n```\n\n#### Decode\n\n```erlang\n{Msg, _} = nats_msg:decode(\u003c\u003c\"+OK\\r\\n\"\u003e\u003e),\n% Msg = ok\n```\n\n### -ERR Message\n\n[NATS Spec](http://nats.io/documentation/internals/nats-protocol/#OKERR)\n\nThe spec defines a predefined set of error messages, so **nats_msg** encodes/decodes these\nto/from atoms as:\n\n* `'Unknown Protocol Operation'` =\u003e `unknown_operation`\n* `'Authorization Violation'` =\u003e `auth_violation`\n* `'Authorization Timeout'` =\u003e `auth_timeout`\n* `'Parser Error'` =\u003e `parser_error`\n* `'Stale Connection'` =\u003e `stale_connection`\n* `'Slow Consumer'` =\u003e `slow_consumer`\n* `'Maximum Payload Exceeded'` =\u003e `max_payload`\n* `'Invalid Subject'` =\u003e `invalid_subject`\n* Other errors are converted to `unknown_error` during decoding and kept as is during encoding.\n\n#### Encode\n\n```erlang\nBinaryMsg = nats_msg:err(auth_violation).\n```\n\n#### Decode\n\n```erlang\nChunk = \u003c\u003c\"-ERR 'Authorization Timeout'\\r\\n\"\u003e\u003e,\n{Msg, _} = nats_msg:decode(Chunk),\n{ok, Error} = Msg,\n% Error = auth_timeout\n```\n\n## License\n\n```\nCopyright (c) 2016, Yuce Tekol \u003cyucetekol@gmail.com\u003e.\nAll rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are\nmet:\n\n* Redistributions of source code must retain the above copyright\n  notice, this list of conditions and the following disclaimer.\n\n* Redistributions in binary form must reproduce the above copyright\n  notice, this list of conditions and the following disclaimer in the\n  documentation and/or other materials provided with the distribution.\n\n* The names of its contributors may not be used to endorse or promote\n  products derived from this software without specific prior written\n  permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\nLIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\nA PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\nOWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\nSPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\nLIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\nTHEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\nOF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyuce%2Fnats_msg","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fyuce%2Fnats_msg","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyuce%2Fnats_msg/lists"}