Skip to content

Talking To Servers

Michael Langford edited this page Oct 19, 2018 · 24 revisions

This document is out of date.
A more modern version can be found here

--

This page describes how a re-frame app might "talk" to backend servers.

Let's assume there's a json-returning server endpoint at "http://json.my-endpoint.com/blah". We want to GET from that endpoint and put a processed version of the returned json into app-db.

Making the request

Some user initiated event will normally trigger the process. Perhaps a button click:

(defn request-it-button
  []
  [:div {:class "button-class"
         :on-click  #(dispatch [:request-it])}  ;; get data from the server !!
         "I want it, now!"])

Notice the on-click handler - it does a dispatch to kickstart the process.

The Event Handler

That :request-it event will need an event handler.

We want the handler to:

  1. Initiate the HTTP GET. We'll use cljs-ajax as the HTTP workhorse
  2. Update a flag in app-db which will trigger a modal "Loading ..." message to show in the UI.
(ns my.app.handlers
   (:require [ajax.core :refer [GET POST]]
             [re-frame.core :refer [register-handler]))

(register-handler
  :request-it             ;; <-- the button dispatched this id
  (fn
    [db _]
   
    ;; kick off the GET, making sure to supply a callback for success and failure
    (GET
      "http://json.my-endpoint.com/blah"
      {:handler       #(dispatch [:process-response %1])   ;; further dispatch !!
       :error-handler #(dispatch [:bad-response %1])})     ;; further dispatch !!
      
     ;; update a flag in `app-db` ... presumably to trigger UI changes
     (assoc db :loading? true)))    ;; pure handlers must return a db

Notice that the GET callbacks issue a further dispatch.

Such callbacks should never attempt to close over db themselves, or make any changes to it because, by the time these callbacks happen, the value in app-db may have changed. Whereas, if they dispatch, then the event handlers looking after their dispatch will be given the latest copy of the db.

Successful GET

The GET success handler:

(register-handler               ;; when the GET succeeds 
  :process-response             ;; the GET callback dispatched this event  
  (fn
    [db [_ response]]           ;; extract the response from the dispatch event vector
    (-> db
        (assoc :loading? false) ;; take away that modal 
        (assoc :data (js->clj response))))  ;; fairly lame processing

A normal handler would have more complex processing of the response. But we're just sketching here, so we've left it easy.

There'd also need to be a handler for the GET :bad-response too. Left as an exercise.