Liking cljdoc? Tell your friends :D


fulcro websockets

A websocket remote for use with Fulcro 3 applications.

1. Version Notes

Standardized custom type support was added in Fulcro 3.3.5. Newer versions of this library requires a minimum version of Fulcro.

  • Fulcro 3.3.4 and below: Use fulcro-websockets version 3.1.x

  • Fulcro 3.3.6 and above: Use fulcro-websockets version 3.2.0+

2. Usage

Add the proper dependencies to your project. You’ll need sente, some Ring bits, and of course Fulcro 3.

2.1. Server

The server setup is mostly just standard Ring fare.

(ns my-app.websocket-server
    [com.fulcrologic.fulcro.server.api-middleware :refer [not-found-handler]]
    [com.fulcrologic.fulcro.networking.websockets :as fws]
    [immutant.web :as web]
    [ring.middleware.content-type :refer [wrap-content-type]]
    [ring.middleware.not-modified :refer [wrap-not-modified]]
    [ring.middleware.resource :refer [wrap-resource]]
    [ring.middleware.params :refer [wrap-params]]
    [ring.middleware.keyword-params :refer [wrap-keyword-params]]
    [ring.util.response :refer [response file-response resource-response]]
    [taoensso.sente.server-adapters.immutant :refer [get-sch-adapter]]))

(def server (atom nil))

(defn query-parser
  [env query]
  ;; call out to something like a pathom parser. See Fulcro Developers Guide

(defn http-server []
  (let [websockets (fws/start! (fws/make-websockets
                                 {:http-server-adapter (get-sch-adapter)
                                  :parser-accepts-env? true
                                  ;; See Sente for CSRF instructions
                                  :sente-options       {:csrf-token-fn nil}}))
        middleware (-> not-found-handler
                     (fws/wrap-api websockets)
                     (wrap-resource "public")
        result     (web/run middleware {:host ""
                                        :port 3000})]
    (reset! server
      (fn []
        (fws/stop! websockets)
        (web/stop result)))))


  ;; start the server

  ;; stop the server

2.2. Client (Before 3.3)

The client setup is even simpler. Just add the websocket remote as one of your remotes:

(ns my-app.client-main
    [com.fulcrologic.fulcro.networking.websockets :as fws]
    [com.fulcrologic.fulcro.application :as app]))

(defonce app (app/fulcro-app {:remotes {:remote (fws/fulcro-websocket-remote {})}}))

2.3. Client (3.3.0+)

Sente, the underlying websockets library, added CLJ support for clients in version 1.15. This meant it was trivial to add support for WS remotes for use in Fulcro CLJ clients. Granted, there is no React in CLJ, but Fulcro’s internals are usable in a headless mode, or you could plug in CLJ rendering of your own design.

Unfortunately, prior versions of this library put the server-side code in websockets.clj and the client remote in websockets.cljs, meaning we could not just make the client file CLJC. Thus, there is a new, preferred, namespace to use for a Fulcro remote that works in both CLJ and CLJS Fulcro clients.

The only change is in the require:

(ns my-app.client-main
    [com.fulcrologic.fulcro.networking.websockets-remote :as fws]
    [com.fulcrologic.fulcro.application :as app]))

(defonce app (app/fulcro-app {:remotes {:remote (fws/fulcro-websocket-remote {})}}))

The old namespace still exists and still has the 3.2.1 code in it, but will not work in CLJC.

2.4. Connected Clients and Server Push

The client ID management is done by Sente. The websockets component you started above has a few conveniences for you to make monitoring client connections and doing sever pushes a little easier.

To use server push you need to store your started websockets component in an atom or some other globally accessible storage (e.g. mount’s defstate). The websocket component implements a protocol that allows you to listen to client connections, and also to send push messages:

(defprotocol WSListener
  (client-added [this ws-net cid]
    "Listener for dealing with client added events.")
  (client-dropped [this ws-net cid]
    "listener for dealing with client dropped events."))

(defprotocol WSNet
  (add-listener [this ^WSListener listener]
    "Add a `WSListener` listener")
  (remove-listener [this ^WSListener listener]
    "Remove a `WSListener` listener")
  (push [this cid verb edn] "Push from server"))

So, (add-listener websockets my-listener) will add a component that you’ve written that satisfies the WSListener protocol to receive notifications when clients connect/disconnect.

The (push websockets cid :x {:value 1}) call will look up the websocket associated with the client that has cid and send the given top/value message to it. Then env of mutations and resolver (if you enable :parser-accepts-env?) will include a :cid key, so you can find out who is talking to you through normal API interactions.

3. Custom Type Support

Fulcro 3.3.6+ added support for full-stack cross-language (clj/cljs) standardization of data model type extensions. See the version notes at the beginning of this document.

You MUST install your custom types before creating any websocket artifacts on the client or server. The websocket mechanisms have to have a protocol "packer" when they are created, which means we have to read the custom type support when they are created.

See the Fulcro book for more information on defining custom type support.

Can you improve this documentation?Edit on GitHub

cljdoc is a website building & hosting documentation for Clojure/Script libraries

× close