{"id":28194231,"url":"https://github.com/monkey-projects/nats","last_synced_at":"2026-02-26T18:38:29.824Z","repository":{"id":292373856,"uuid":"980634716","full_name":"monkey-projects/nats","owner":"monkey-projects","description":"Clojure library for NATS messaging","archived":false,"fork":false,"pushed_at":"2025-11-20T08:22:01.000Z","size":46,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-11-20T10:14:17.636Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Clojure","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/monkey-projects.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,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-05-09T13:04:06.000Z","updated_at":"2025-11-20T08:22:05.000Z","dependencies_parsed_at":"2025-05-09T16:27:23.556Z","dependency_job_id":"f8f88859-367f-4d8e-87de-282057321865","html_url":"https://github.com/monkey-projects/nats","commit_stats":null,"previous_names":["monkey-projects/nats"],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/monkey-projects/nats","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/monkey-projects%2Fnats","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/monkey-projects%2Fnats/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/monkey-projects%2Fnats/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/monkey-projects%2Fnats/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/monkey-projects","download_url":"https://codeload.github.com/monkey-projects/nats/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/monkey-projects%2Fnats/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29867572,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-26T18:27:06.972Z","status":"ssl_error","status_checked_at":"2026-02-26T18:26:57.848Z","response_time":89,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":"2025-05-16T13:11:40.757Z","updated_at":"2026-02-26T18:38:29.817Z","avatar_url":"https://github.com/monkey-projects.png","language":"Clojure","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Clojure Nats\n\nClojure library for [NATS messaging](https://nats.io), built on top of the\n[Java Nats implementation](https://github.com/nats-io/nats.java).\n\n# Usage\n\n[![Clojars Project](https://img.shields.io/clojars/v/com.monkeyprojects/nats.svg)](https://clojars.org/com.monkeyprojects/nats)\n\nInclude the library in your project:\n```clojure\n;; Leiningen\n[com.monkeyprojects/nats \"\u003cversion\u003e\"]\n```\nOr, with Clojure CLI:\n```clojure\n;; deps.edn\ncom.monkeyprojects/nats {:mvn/version \"\u003cversion\u003e\"}\n```\n\nAfter that, you can start using it by creating a connection to a remote NATS server.\n```clojure\n(require '[monkey.nats.core :as nc])\n\n(def conn (nc/make-connection {:urls [\"nats-server:1234\"]    ; One or more urls to connect to\n                               :secure? true                 ; Use TLS\n\t\t\t       :token \"very-secure-token\"})) ; See authentication below\n```\n\nThe `monkey.nats.core` namespace provides basic functionality for publishing or\nconsuming messages.\n```clojure\n;; Subscribe to test.subject, and just print the messages\n(def sub (nc/subscribe conn \"test.subject\" println {}))\n\n;; Publish a message\n(nc/publish conn \"test.subject\" {:message \"This is a test\"} {})\n;; =\u003e Will print the message to console\n```\n\n## Serialization\n\nBy default, the messages are serialized into [edn](https://github.com/edn-format/edn).\nYou can customize this by specifying a `serializer` in the `publish` options, and a\nsimilar `dezerializer` when subscribing.  Note that the serializer should create a\n`byte[]` array, wherease the deserializer should handle complete NATS `Message`s.\nThis is because the underlying library disencourages implementing `Messages` but\ninstead provides a bunch of utility function.\n\nFor example, this is how Json serialization could look like, using\n[Cheshire](https://github.com/dakrone/cheshire):\n```clojure\n(require '[cheshire.core :as json])\n\n(defn to-json [msg]\n  (-\u003e (json/generate-string msg)  \n      (.getBytes \"UTF-8)))  ; Must return a byte array\n\n(defn from-json [nats-msg]\n  (-\u003e nats-msg\n      (.getData)\n      (String.)\n      (json/parse-string)))\n\n(def subs (nc/subscribe conn \"test.subject\" println {:deserializer from-json}))\n\n(nc/publish conn \"test.subject\" {:message \"Json message\"} {:serializer to-json})\n```\n\n## Authentication\n\nThis library supports various methods of authentication.\n\n  - Tokens: pass the `:token` property in the connection options\n  - `:credential-path`: points to a path that contains credentials\n  - `:static-creds`: provide credentials from a static string\n  - `:auth-handler`: a custom [AuthHandler](https://javadoc.io/static/io.nats/jnats/2.21.1/io/nats/client/AuthHandler.html)\n\nIt's up to you to decide which suits your needs better.\n\n## Queues\n\nIn order to ensure that one message is only passed to one subscriber, instead of all\nof them, use a [queue group](https://docs.nats.io/nats-concepts/core-nats/queue).  In\norder to do this, pass the `:queue` option when subscribing:\n\n```clojure\n(def sub (nc/subscribe conn \"test.subject\" println {:queue \"my-queue\"}))\n```\n\nMultiple subscribers that use the same queue name, will only process each message once.\n\n## Error Handling\n\nNATS provides a system for reporting errors that occur outside of the normal event\nhandling flow, i.e. within the NATS client itself.  This can be for example a\nconnection problem or some other internal error.  You can listen for these kinds\nof errors by passing an `error-listener` when opening a connection.  The error\nlistener should implement the [ErrorListener](https://javadoc.io/static/io.nats/jnats/2.21.1/io/nats/client/ErrorListener.html)\ninterface.  But to make it more idiomatic, we have provided a utility function\ncalled `-\u003eerror-listener` that wraps a Clojure function in a proxy for the\n`ErrorListener` interface.  Each invocation of one of it's member functions will\ninstead be passed to the wrapped function with the arguments converted into a map,\nwith a `type` property indicating the kind of error.\n\nFor example:\n```clojure\n(defn my-error-handler [args]\n  (println \"We got an error of type\" (:type args)))\n\n(def conn (nc/make-connection {... :error-listener (nc/-\u003eerror-listener my-error-handler)}))\n```\n\n# JetStream\n\nThe above pub/sub pattern has a big drawback: if no subscriptions are listening\non a subject, the messages are lost.  In order to have some persistence, similar to\nKafka topics or JMS durable subscribers, you need to use\n[JetStream](https://docs.nats.io/nats-concepts/jetstream).  It is beyond the scope\nof this documentation to explain what it is, but you can read about it in the [official\nNats documentation](https://docs.nats.io/nats-concepts/jetstream).  We do provide\na wrapper for JetStream.  It consists of two namespaces: one to manage streams\n(`monkey.nats.jetstream.mgmt`) and another on to consume from/publish to streams\n(`monkey.nats.jetstream`).\n\n```clojure\n(require '[monkey.nats.jetstream :as js])\n(require '[monkey.nats.jetstream.mgmt :as mgmt])\n\n(def mgmt-ctx (mgmt/make-management conn)\n\n;; Configure a stream to store messages\n(def stream (mgmt/add-stream {:name \"test-stream\"\n                              :subjects [\"test.subject\"]\n\t\t\t      :storage-type :file}))\n;; Set up a consumer to pull messages\n(def consumer (mgmt/make-consumer mgmt stream {:durable-name \"my-consumer-id\"}))\n\n;; Create jetstream context for further use\n(def js (js/make-jetstream conn))\n;; Create a consumption context and start consuming\n(def ctx (js/consumer-ctx js \"test-stream\" \"my-consumer-id\"))\n(def msg-cons (js/consume ctx println {}))\n\n;; Publish a message\n(js/publish js \"test.subject\" {:message \"Jetstream message\"} {})\n;; =\u003e Will print the message using above consumer\n\n;; Stop consuming\n(js/stop msg-cons)\n(js/close msg-cons)\n\n;; You can also manually fetch messages\n(def fetcher (js/fetch ctx {:expires-in 1000}))\n(js/publish js \"test.subject\" {:message \"Another Jetstream message\"} {})\n;; The fetcher acts as a regular 0-arity function\n(fetcher)\n;; =\u003e {:message \"Another Jetstream message\"}\n\n;; Clean up\n(mgmt/delete-stream stream)\n```\n\nNote that fetchers can only be used once.  If you need to take multiple messages\nin a loop, you can use `take-next`:\n\n```clojure\n(js/take-next ctx {:timeout 1000})\n;; =\u003e Can return `nil` if none are waiting\n;; Try again, without timeout\n(js/take-next ctx {:deserializer nc/from-edn})\n;; =\u003e Returns next pending message when it becomes available\n```\n\nAgain, serialization is done using `edn`.  You can specify your own serializer and\ndeserializer, similar to the basic pub/sub functions.\n\n## Acknowledging Messages\n\nIf you have passed `:ack-policy` `:all` or `:explicit` as an option to\n`mgmt/make-consumer`, you will have to manually acknowledge each message, to\nindicate to the consumer that the message can be removed from the persistent\nstore.  In order to do this, just call `ack` on the message.  Note that your\n`deserializer` will need to pass the entire message to your handler in this\ncase (possibly along with other information).\n\n```clojure\n(defn custom-deserializer [msg]\n  {:orig msg\n   :payload (nc/from-edn msg)})\n\n(handler [msg]\n  (println \"The payload is:\" (:payload msg))\n  (js/ack (:orig msg)))\n\n(def msg-cons (js/consume ctx handler {:deserializer custom-deserializer}))\n```\n\n# License\n\n[MIT License](LICENSE)\n\nCopyright (c) 2025 by [Monkey Projects BV](https://www.monkey-projects.be)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmonkey-projects%2Fnats","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmonkey-projects%2Fnats","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmonkey-projects%2Fnats/lists"}