JulianBirch.cljs-ajax

https://github.com/JulianBirch/cljs-ajax.git

git clone 'https://github.com/JulianBirch/cljs-ajax.git'

(ql:quickload :JulianBirch.cljs-ajax)
529

cljs-ajax

simple Ajax client for ClojureScript and Clojure

Build Status

cljs-ajax exposes the same interface (where useful) in both Clojure and ClojureScript. On ClojureScript it operates as a wrapper around goog.net.XhrIo or js/XmlHttpRequest, while on the JVM it's a wrapper around the Apache HttpAsyncClient library.

In addition to this document, there's an FAQ, a change log and a contribution document. Furthermore, there is detailed documentation on specific features and design advice in the docs folder.

Usage

Leiningen/Boot: [cljs-ajax "0.7.5"]

Leiningen version

The client provides an easy way to send Ajax requests to the server using GET, POST, and PUT functions. It also provides a simple way using ajax-request. All requests are asynchronous, accepting callback functions for response and error handling.

There are four formats currently supported for communicating with the server: :transit, :json, :text and :raw. (:text will send parameters up using normal form submission and return the raw text. :raw does the same, but on the JVM it returns the body's java.io.InputStream and doesn't close it.)

For advice on how to set up the server side in Clojure to work with cljs-ajax, please see the page on handling responses on the server.

GET/POST/PUT

The GET, POST, and PUT helpers accept a URI followed by a map of options:

Note that you can override default-handler and default-error-handler, but they are global to your application/page.

JSON specific settings

The following settings affect the interpretation of JSON responses: (You must specify :response-format as :json to use these.)

GET specific settings

The :vec-strategy setting affects how sequences are written out. A :vec-strategy of :java will render {:a [1 2]} as a=1&a=2. A :vec-strategy of :rails will render {:a [1 2]} as a[]=1&a[]=2. This is also the correct setting for working with HTTP.

GET/POST examples

(ns foo
  (:require [ajax.core :refer [GET POST]]))

(defn handler [response]
  (.log js/console (str response)))

(defn error-handler [{:keys [status status-text]}]
  (.log js/console (str "something bad happened: " status " " status-text)))

(GET "/hello")

(GET "/hello" {:params {:foo "foo"}})

(GET "/hello" {:params {:a 0
                        :b [1 2]
                        :c {:d 3 :e 4}
                        "f" 5}})
;;; writes "a=0&b=1&b=2&c[d]=3&c[e]=4&f=5"

(GET "/hello" {:params {:a 0
                        :b [1 2]
                        :c {:d 3 :e 4}
                        "f" 5}
               :vec-strategy :rails})
;;; writes "a=0&b[]=1&b[]=2&c[d]=3&c[e]=4&f=5"


(GET "/hello" {:handler handler
               :error-handler error-handler})

(POST "/hello")

; Post a transit format message
(POST "/send-message"
        {:params {:message "Hello World"
                  :user    "Bob"}
         :handler handler
         :error-handler error-handler})


; Will send file inputs that are in the form
(POST "/send-form-modern" {:body (js/FormData. form-element)})

; Send file explicitly, ClojureScript specific
(let [form-data (doto
                    (js/FormData.)
                  (.append "id" "10")
                  (.append "file" js-file-value "filename.txt"))]
  (POST "/send-file" {:body form-data
                      :response-format (raw-response-format)
                      :timeout 100}))

; Send multiple files explicitly, ClojureScript specific
; input-element is an html element of file type.
(let [form-data (let [f-d (js/FormData.)
                      files (.-files input-element)
                      name (.-name input-element)]
                  (doseq [file-key (.keys js/Object files)]
                    (.append f-d name (aget files file-key)))
                  f-d)]
  (POST "/send-files" {:body form-data
                       :response-format (raw-response-format)
                       :timeout 100}))
                      
(POST "/send-message"
        {:params {:message "Hello World"
                  :user    "Bob"}
         :handler handler
         :error-handler error-handler
         :response-format :json
         :keywords? true})
         
(PUT "/add-item"
     {:params {:id 1 :name "mystery item"}})
     
(GET {:url "/generate.png" ; Request a PNG and get it back as a js/ArrayBuffer
      :response-format {:content-type "image/png" :description "PNG image" :read -body :type :arraybuffer})

FormData support

Note that js/FormData is not supported before IE10, so if you need to support those browsers, don't use it. cljs-ajax doesn't have any other support for file uploads (although pull requests are welcome). Also note that you must include ring.middleware.multipart-params/wrap-multipart-params in your ring handlers as js/FormData always submits as multipart even if you don't use it to submit files.

Error Responses

An error response is a map with the following keys passed to it:

If the failure had a valid response, it will be stored in the :response key.

If the error is :parse then the raw text of the response will be stored in :original-text.

Finally, if the server returned an error, and that then failed to parse, it will return the error map, but add a key :parse-error that contains the parse failure.

The error-handler for GET, POST, and PUT is passed one parameter which is an error response. Note that in all cases either handler or error-handler will be called. You should never get an exception returned by GET, POST etcetera.

ajax-request

The ajax-request is the simple interface. It differs from the GET and POST API as follows:

It has a single parameter, which is a map with the following members: The parameters are: * :uri * :method - (:get, "GET", :post or "POST" etcetera)
* :format and :response-format, documented in the formats documentation * :handler - A function that takes a single argument [ok result]. The result will be the response if true and the error response if false.

The following parameters are the same as in the GET/POST easy api: * :params - the parameters that will be sent with the request, format dependent: :transit and :edn can send anything, :json and :raw need to be given a map. GET will add params onto the query string, POST will put the params in the body * :timeout - the ajax call's timeout. 30 seconds if left blank * :headers - a map of the HTTP headers to set with the request * :cookie-policy - a keyword for the cookie management specification. Only available in Java. Optional. One of :none, :default, :netscape, :standard, :standard-strict. * :with-credentials - a boolean, whether to set the withCredentials flag on the XHR object. * :interceptors - the interceptors to run for this request. If not set, runs contents of the default-interceptors global atom. This is an empty vector by default. For more information, visit the interceptors page.

ajax-request examples

(defn handler2 [[ok response]]
  (if ok
    (.log js/console (str response))
    (.error js/console (str response))))

(ajax-request
        {:uri "/send-message"
         :method :post
         :params {:message "Hello World"
                  :user    "Bob"}
         :handler handler2
         :format (json-request-format)
         :response-format (json-response-format {:keywords? true})})

(ajax-request
        {:uri "/send-message"
         :method :post
         :params {:message "Hello World"
                  :user    "Bob"}
         :handler handler2
         :format (url-request-format) 
         :response-format (json-response-format {:keywords? true})})

These examples will use the Google Closure library XhrIo API. If you want to use XMLHttpRequest API directly, add :api (js/XMLHttpRequest.) to the map.

License

Distributed under the Eclipse Public License, the same as Clojure.