Created
September 6, 2012 03:22
-
-
Save pandeiro/3650678 to your computer and use it in GitHub Desktop.
Experimental ClojureScript XHR API
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(ns please.core | |
(:require [please.help :as help] | |
[cljs.reader :as reader]) | |
(:refer-clojure :exclude [get])) ; please? | |
;; | |
;; Event handler delegation | |
;; | |
(def ^{:doc "If this is nil, no events will be sent. Use please.core/set-request-event-fn! to | |
change this value"} | |
request-event-fn nil) | |
(defn set-request-event-fn! [f] | |
(when (fn? f) (set! request-event-fn f))) | |
;; | |
;; Reserved keywords for HTTP verbs and flags | |
;; | |
(def http-methods | |
{:get "GET", :put! "PUT" :post! "POST" :head "HEAD" :delete! "DELETE"}) | |
(def reserved-keywords | |
(apply conj #{:sync :async :json :html :basicauth} (keys http-methods))) | |
;; | |
;; Functions | |
;; | |
(defn request | |
"Request an HTTP resource as Clojure (or optionally JSON or HTML)" | |
[& args] | |
(let [xml-http-request #(js/XMLHttpRequest.) | |
async? (not (help/to-do-sync? args)) | |
url (help/find-url-str args) | |
method (http-methods (or (some (set (keys http-methods)) args) :get)) | |
data (filter help/looks-like-data? args) | |
events (filter keyword? (remove reserved-keywords args)) | |
callbacks (filter fn? args) | |
content-type ({:json "application/json" | |
:html "text/html"} (some #{:json :html} args) "application/clojure") | |
response-type (cond (= content-type "application/json") "json" | |
(= content-type "text/html") "document" | |
:else "text") | |
as-clj? (= response-type "text") | |
creds (when (help/kw-in-args? :basicauth args) | |
(->> (partition-by #(= :basicauth %) args) | |
(last) | |
(filter string?) | |
(take 2)))] | |
(when url | |
(let [xhr (xml-http-request) | |
func (fn [] | |
(doseq [callback callbacks] | |
(callback (if as-clj? | |
(reader/read-string (.-response xhr)) | |
(.-response xhr))) | |
(when request-event-fn | |
(doseq [event events] | |
(request-event-fn event data)))))] | |
(do | |
(if creds | |
(.open xhr method url async? (first creds) (second creds)) | |
(.open xhr method url async?)) | |
(set! (.-onreadystatechange xhr) #(when (= (.-readyState xhr) 4) (func))) | |
(when async? (set! (.-responseType xhr) response-type)) | |
(.setRequestHeader xhr "Content-Type" content-type) | |
(.send xhr (if (= 1 (count data)) (first data) data)) | |
(or (and async? xhr) | |
(if as-clj? (reader/read-string (.-response xhr)) (.-response xhr)))))))) | |
(def get (partial request :get)) | |
(def post! (partial request :post!)) | |
(def put! (partial request :put!)) | |
(def head (partial request :head)) | |
(def delete! (partial request :delete!)) | |
(comment | |
;; | |
;; Reserved keyword list | |
;; | |
[:get :head :delete :put! :post! :sync :async :basicauth :html :json] | |
;; | |
;; API: example usages | |
;; | |
(request "some/res") ; minimum of 1 string arg | |
; if no fn arg and implicit :get, **synchronous** req | |
(request :html "some/res.html") ; resources assumed clj unless :json/:html present | |
(request :post! :json "some/api" {:a 1}) ; :json converts clj data to json ( "{\"a\": 1}" ) | |
(request :post! "some/res" (or {:a 1 :b 2} "something" 3)) ; :put!/:post! async by default | |
(request :put! "some/res" :sync) ; explicit :sync for put and post | |
(request "some/res" :sync #(fire-some-event! %)) ; explicit sync for get w/ callback | |
(request "some/res" #(get-busy % :busy-event)) ;standard familiar callback patterns | |
(request :post! "some/res" {:a 1 :b 2} #(display-it %)) | |
(request "file:///home/user/some/res"); local is fine | |
(request "some/res" :head) ; args can come in any order | |
(request #(fire-event :x %) "/api" :put! {:a 1}) | |
(request "some/res" :some-event) ; non-reserved keywords are assumed to be events, | |
; which are fired if a default request event fn has | |
; been set. fn is called with event first | |
; plus any string, number, or clojure coll present | |
; in args | |
(set-request-event-fn! dispatch/fire) ; set a request event fn or keywords just get ignored | |
(request "some/res" "other things" "confused!?") ; only first str accepted and used as url | |
(request "some/res" #(do-stuff %) :basicauth "user" "pass") ; if :basicauth, first two strs | |
; after it in args are assumed to be user and pass | |
) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
lol
:require [please.help]