Skip to content


Server handling of remote queries
Browse files Browse the repository at this point in the history
Server syncing through Om
  • Loading branch information
jraines committed Nov 4, 2015
1 parent f44d516 commit 9e92e22
Show file tree
Hide file tree
Showing 4 changed files with 74 additions and 26 deletions.
16 changes: 15 additions & 1 deletion
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# simoutfit
# Gentle Intro to Web Development in Clojure with Om (Next)

## Starting

Expand Down Expand Up @@ -66,3 +66,17 @@ for writing & reading transit data. Finally we use a library from Google Closur

The next few commits follow the Om quickstart guide

- component
- parameterized component

Now let's let Om manage our state between client and server instead of handling that ourselves with explicit ajax requests and `swap!`ing the `app-state`.

We'll need to provide a function to the `:send` key of the reconciler's parameter map. This will be a function which takes two parameters: the EDN of the query expression fragment that will be passed to the server, and a callback to handle the response. In this case, our function closes over the single remote URL we'll be sending to on the server. Notice that what we *don't* have to do in the callback is update our app-state: Om handles it.

On the server, we have a similar `om/parser` function which takes the app state and a `:read` function.

In the request handler, we respond with a transit-encoded result of parsing the state and the query expression fragment that was sent, which is nested in the `:remote` key of the transit encoded params (these are decoded for us by ring-transit). This is where using transit pays off -- we can pass this piece ofthe request directly into the parser.

In the case of `:description`, the value is sent back to the server, but since there is no `:sender` key in the app state on the server, we send back `:not-found` and let the client handle that.

I also added `ring-reload` so I didn't have to restart the server on each change.
3 changes: 3 additions & 0 deletions project.clj
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@
[org.clojure/clojurescript "1.7.122"]
[compojure "1.4.0"]
[http-kit "2.1.19"]
[ring/ring-core "1.4.0"]
[ring/ring-devel "1.4.0"]
[ring-transit "0.1.4"]
[org.omcljs/om "1.0.0-alpha14"]
[com.cognitect/transit-clj "0.8.285"]
[com.cognitect/transit-cljs "0.8.225"]
Expand Down
46 changes: 25 additions & 21 deletions src/simoutfit/core.cljs
Original file line number Diff line number Diff line change
Expand Up @@ -16,45 +16,49 @@
(let [st @state]
(if-let [[_ value] (find st key)]
{:value value}
{:value :not-found})))
{:remote true})))

(defui HelloWorld
static om/IQuery
(query [this]
'[:message :description :sender])
(render [this]
(dom/div nil (get (om/props this) :message))))
(let [props (om/props this)
msg (:message props)
desc (:description props)
sender (if-not (= (:sender props) :not-found)
(:sender props)
(dom/div nil (str msg ": " desc " -- " sender)))))

(defn transit-post [url]
(fn [edn cb]
(println edn)
(.send XhrIo url
(fn [e]
(this-as this
(println (t/read (t/reader :json)
(.getResponseText this)))
(cb (t/read (t/reader :json) (.getResponseText this)))))
"POST" (t/write (t/writer :json) edn)
#js {"Content-Type" "application/transit+json"})))

(def reconciler
{:state app-state
:parser (om/parser {:read read})}))
:parser (om/parser {:read read})
:send (transit-post "/api")}))

(om/add-root! reconciler
HelloWorld (gdom/getElement "app"))

(def r (t/reader :json))

(defn get-data [url cb]
(XhrIo.send url
(fn [e]
(let [xhr (.-target e)]
(cb (.getResponseText xhr))))))

(get-data "/data"
(fn [res]
(let [resp (t/read r res)
_ (println resp)
msg (:message resp)]
(swap! app-state assoc :message msg))))

(defn on-js-reload []
(println "Reloaded!")
;; optionally touch your app-state to force rerendering depending on
Expand Down
35 changes: 31 additions & 4 deletions src/simoutfit/server.clj
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
(ns simoutfit.server
(:require [compojure.core :refer :all]
[compojure.route :as route]
[ring.middleware.transit :refer [wrap-transit-params]]
[ring.middleware.reload :refer [wrap-reload]]
[cognitect.transit :as t]
[ :as om]
[org.httpkit.server :refer [run-server]])
(:import [ ByteArrayOutputStream]))

Expand All @@ -15,13 +18,37 @@

(defn transit-response [x]
{:headers {"Content-Type" "application/transit+json"}
:body (write x)}
:body (write x)})

(def state (atom {:message "Hello from server"
:description "I am from the server!"} ))

(defmulti readfn (fn [env key params] key))

(defmethod readfn :default
[{:keys [state] :as env} key params]
(let [st @state]
(if-let [[_ value] (find st key)]
{:value value}
{:value :not-found})))

(def parser
(om/parser {:read readfn}))

(defn api [req]
{:state state}
(-> req :params :remote))))

(defroutes app
(route/resources "/")
(GET "/data" [] (transit-response {:message "Hello from server"})))
(POST "/api" params api))

(defn -main []
(run-server app {:port 5000}))
(run-server (-> app
{:port 5000}))

0 comments on commit 9e92e22

Please sign in to comment.