Permalink
Browse files

Server handling of remote queries

Server syncing through Om
  • Loading branch information...
jraines committed Nov 4, 2015
1 parent f44d516 commit 9e92e22307db3e3086a7b5404b78424625ad6407
Showing with 74 additions and 26 deletions.
  1. +15 −1 README.md
  2. +3 −0 project.clj
  3. +25 −21 src/simoutfit/core.cljs
  4. +31 −4 src/simoutfit/server.clj
View
@@ -1,4 +1,4 @@
-# simoutfit
+# Gentle Intro to Web Development in Clojure with Om (Next)
## Starting
@@ -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.
View
@@ -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"]
View
@@ -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])
+ '[:message :description :sender])
Object
(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)
+ "Unknown")]
+ (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
(om/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
View
@@ -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]
+ [om.next.server :as om]
[org.httpkit.server :refer [run-server]])
(:import [java.io ByteArrayOutputStream]))
@@ -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]
+ (transit-response
+ (parser
+ {: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
+ wrap-transit-params
+ wrap-reload)
+ {:port 5000}))

0 comments on commit 9e92e22

Please sign in to comment.