I have a ClojureScript application and I want to make RPC calls to the server which would look like normal function core.async calls on the client side.
In order to do this for the moment I wrote the code below based on cljx. In the RPC definitions section I would have to add all the server-side functions which I want to expose as RPC to the client side.
Note: the send function is taken from here: https://dimagog.github.io/blog/clojure/clojurescript/2013/07/12/making-http-requests-from-clojurescript-with-core.async/
Is there a way to do this nicer without the boilerplate code?
Thinking about how to improve it the only idea that I have is to write a leiningen plugin which generates server side and client side code needed for RPC i.e. the part that I do at this moment using cljx. Is there a better way?
(ns myapp.shared.rpc
(:require
#+cljs [myapp.tools :refer [send log]]
#+cljs [cljs.reader :as reader]
#+clj [clojure.tools.logging :as log]
#+clj [noir.response :refer [edn]]
#+clj [myapp.rpc :as rpc]
))
#+cljs (defn rpc-client [function params]
#+cljs (log "RPC call: (" function params ")")
#+cljs (send "POST" "/api"
#+cljs (str "rpc=" (pr-str {:fun function :params params}))
#+cljs (fn [x]
#+cljs (log "RPC response:'" x "'")
#+cljs (:response (reader/read-string x)))))
#+clj (defmulti rpc-impl #(:fun %))
#+clj (defn rpc-server [{rpc :rpc}]
#+clj (log/info "RPC call received:" rpc)
#+clj (let [response (-> rpc read-string rpc-impl)]
#+clj (log/info "RPC response sent: '" response "'")
#+clj (edn {:response response})))
;;;;; RPC definitions
#+cljs (defn demo [ & p] (rpc-client :demo p))
#+clj (defmethod rpc-impl :demo [{p :params}] (apply rpc/demo p))
Here are three libraries I've seen that handle RPC. I don't have significant experience with any of them, so take my comments with a large grain of salt.