{"id":15133006,"url":"https://github.com/carlalbrecht/socket-json-rpc","last_synced_at":"2025-09-29T02:32:17.891Z","repository":{"id":62432987,"uuid":"85021192","full_name":"carlalbrecht/socket-json-rpc","owner":"carlalbrecht","description":"An asynchronous JSON-RPC server and client for Clojure that uses sockets for communication","archived":true,"fork":false,"pushed_at":"2017-03-23T05:39:21.000Z","size":51,"stargazers_count":0,"open_issues_count":1,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-07-05T05:06:59.317Z","etag":null,"topics":["async","clojure","clojure-library","json-rpc","json-rpc-client","json-rpc-server","json-rpc2","socket-io"],"latest_commit_sha":null,"homepage":"","language":"Clojure","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"epl-1.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/carlalbrecht.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","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":"2017-03-15T02:46:15.000Z","updated_at":"2023-07-27T05:48:01.000Z","dependencies_parsed_at":"2022-11-01T21:15:31.908Z","dependency_job_id":null,"html_url":"https://github.com/carlalbrecht/socket-json-rpc","commit_stats":null,"previous_names":["invlpg/socket-json-rpc"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/carlalbrecht/socket-json-rpc","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/carlalbrecht%2Fsocket-json-rpc","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/carlalbrecht%2Fsocket-json-rpc/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/carlalbrecht%2Fsocket-json-rpc/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/carlalbrecht%2Fsocket-json-rpc/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/carlalbrecht","download_url":"https://codeload.github.com/carlalbrecht/socket-json-rpc/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/carlalbrecht%2Fsocket-json-rpc/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":277456678,"owners_count":25821016,"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","status":"online","status_checked_at":"2025-09-29T02:00:09.175Z","response_time":84,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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":["async","clojure","clojure-library","json-rpc","json-rpc-client","json-rpc-server","json-rpc2","socket-io"],"created_at":"2024-09-26T04:42:40.179Z","updated_at":"2025-09-29T02:32:17.556Z","avatar_url":"https://github.com/carlalbrecht.png","language":"Clojure","funding_links":[],"categories":[],"sub_categories":[],"readme":"# socket-json-rpc\n\n[![Build Status](https://travis-ci.org/invlpg/socket-json-rpc.svg?branch=master)](https://travis-ci.org/invlpg/socket-json-rpc)\n[![codecov](https://codecov.io/gh/invlpg/socket-json-rpc/branch/master/graph/badge.svg)](https://codecov.io/gh/invlpg/socket-json-rpc)\n[![Dependencies Status](https://jarkeeper.com/invlpg/socket-json-rpc/status.svg)](https://jarkeeper.com/invlpg/socket-json-rpc)\n\n[![Clojars Project](https://img.shields.io/clojars/v/invlpg/socket-json-rpc.svg)](https://clojars.org/invlpg/socket-json-rpc)\n\nsocket-json-rpc is a Clojure library that simplifies creating async JSON-RPC\nservers and clients that communicate using TCP sockets.\n\n## Server Usage\n\nFirst, require the server:\n\n```clojure\n(require '[socket-json-rpc.server :as server])\n```\n\nProcedures are defined with `defprocedure`, and is used in the form\n\n```clojure\n(server/defprocedure [name] [[named-args]] [body])\n```\n\nThe named-args argument tells the server how to arrange named arguments into a\nvector so that the body can use the arguments in a consistent manner. For\nexample, the following procedure allows both unnamed and named argument usage.\n\n```clojure\n(server/defprocedure subtract\n  [\"minuend\" \"subtrahend\"]\n  (server/respond (- (first args) (second args))))\n```\n\n*Note:* The body automatically receives the variables `args` and `notification`.\n`args` is a vector of supplied arguments, matching the order specified in the\n`named-args` vector supplied when the procedure was defined. `notification` is a\nboolean value that is true when the client does not want to receive a reply with\nthe result of the procedure call. If the procedure does not respect the\n`notification` variable, the server will still not send the result anyway.\n\n*Note:* Normally, the number of unnamed arguments supplied must match the number\nof named arguments supplied in the procedure definition, but to allow for\nvariable arguments, the special named argument `\"...\"` can be used. For example:\n\n```clojure\n(server/defprocedure add\n  [\"a\" \"...\"]\n  (server/respond (reduce + args)))\n```\n\nThe client must still provide at least the number of named arguments other than\n`\"...\"`. In the previous example, at least one number would have to be specified.\n\nThe `subtract` method can be called with either of the following JSON:\n\n```javascript\n// Unnamed arguments\n{\n  \"jsonrpc\": \"2.0\",\n  \"method\": \"subtract\",\n  \"params\": [42, 23],\n  \"id\": 1\n}\n```\n\n```javascript\n// Named arguments\n{\n  \"jsonrpc\": \"2.0\",\n  \"method\": \"subtract\",\n  \"params\": {\n    \"subtrahend\": 23,\n    \"minuend\": 42\n  },\n  \"id\": 1\n}\n```\n\nAnd both would return the same result:\n\n```javascript\n{\n  \"jsonrpc\": \"2.0\",\n  \"result\": \"19\",\n  \"id\": 1\n}\n```\n\nThe server can then be started in one of two ways:\n\n```clojure\n; This version blocks the calling thread, so it won't close.\n(defn -main\n  [\u0026 args]\n  ...\n  (server/start [port] [backlog] [bind-addr]))\n```\n\n```clojure\n; This version allows the calling thread to continue immediately, meaning that\n; if the main thread closes, the server will also be shut down.\n(defn -main\n  [\u0026 args]\n  ...\n  (server/start-async [port] [backlog] [bind-addr])\n  ...)\n```\n\nThe only required argument to either form is `port`. `backlog` specifies how many\npending connections should be buffered, and is 50 by default. `bind-addr`\nspecifies the host address that the server should listen on.\n\n## Client Usage\n\nFirst, require the client:\n\n```clojure\n(require '[socket-json-rpc.client :as client :refer (notify)])\n```\n\nThe client is very simple, only exposing one macro - `with-server`, and is used\nin the form\n\n```clojure\n(client/with-server [host] [port] [body])\n```\n\nThis form allows the client to call functions on the server *almost* as if they\nwere local functions. For example, our `subtract` procedure defined above could\nbe called on a local server running on port `9001` by either:\n\nUsing the ordered argument form:\n\n```clojure\n(client/with-server \"localhost\" 9001\n  (subtract 42 23))\n```\n\nOr, using the named argument form:\n\n```clojure\n(client/with-server \"localhost\" 9001\n  (subtract :subtrahend 23 :minuend 42))\n```\n\nBoth forms would return the same result:\n\n```clojure\n[(false 19)]\n```\n\n`with-server` returns a vector of function results. Each item in the vector is a\nlist containing\n\n```clojure\n'([error] \n   [result] || [code] [message])\n  \n; i.e. successful function call\n'(false 19)\n\n; i.e. error condition\n'(true -32601 \"Method not found\")\n```\n\nA remote procedure call can be wrapped in `notify` if you aren't interested in\nreceiving a reply with the result of the function call.\n\nMultiple functions can be grouped together into a single \"batch\" by calling them\nsuccessively inside the `with-server` block. Note that each function will be\ncalled on the server in-order.\n\n```clojure\n(client/with-server \"localhost\" 9001\n  (subtract 42 23)\n  (add 1 2 3 4 5)\n  (subtract :subtrahend 42 :minuend 23)\n  (notify (add 15 15))\n  (doesntexist true))\n  \n; =\u003e [(false 19)\n;     (false 15)\n;     (false -19)\n;     (true -32601 \"Method not found\")]\n```\n\nNotice that the return values arrive in the same order as the calls were\ndelivered. \n\n## Common Problems\n\n```clojure\nClassCastException java.lang.String cannot be cast to clojure.lang.Associative\n```\n\nThis usually means that you forgot to add `(respond [val])` around your procedure's\nreturn value.\n\n## License\n\nCopyright © 2017 Carl Albrecht\n\nDistributed under the Eclipse Public License version 1.0\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcarlalbrecht%2Fsocket-json-rpc","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcarlalbrecht%2Fsocket-json-rpc","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcarlalbrecht%2Fsocket-json-rpc/lists"}