Priyatam Mudivarti
Principal, Facjure LLC
Abstract HTTP
Write idiomatic code
Run on any web server
Bare Metal
Easy to Test
Live Coding
(def a-vector [1 2 3 4 5])
(def a-nested-map
{:customer-id 1e6
:preferences {:nickname "Bob"
:avatar "http://en.gravatar.com/userimage/0/0.jpg"}
:services {:alerts {:daily true}}})
(def complex-map
{[1 2] :one-two
[3 4] :three-four})
(def a-set
#{:cat :dog :bird})
;; Unlike JavaScript there is no hoisting in ClojureScript. ClojureScript has lexical scoping.
(def some-x 1)
(let [some-x 2]
some-x)
;; functions parameters
(let [fns (loop [i 0 ret []]
(if (< i 10)
(recur (inc i)
(conj ret (fn [] i)))
ret))]
(map #(%) fns))
;; destructuring
(def point {:x 5 :y 7})
(let [{:keys [x y] :as the-point} point]
(println "x:" x "y:" y "point:" the-point))
; simple function
(defn add [a b]
(+ a b))
;; function with multiple args and default values
(defn another-function
([x] (defaults x :default))
([x y] [x y]))
;; closure
(let [a 1e3]
(defn foo []
(* a a))
(defn bar []
(+ (foo) a)))
;; higher order functions
(map inc [0 1 2 3 4 5 6 7 8 9])
(filter even? (range 10))
(reduce + (range 100))
(partition 2 [:a 1 :b 2 :c 3 :d 4 :e 5])
;; loops
(for [x (range 1 10)
y (range 1 10)
:when (and (zero? (rem x y))
(even? (quot x y)))]
[x y])
;; handler
(defn my-ip [request]
{:status 200
:headers {"Content-Type" "text/plain"}
:body (:remote-addr request)})
;; middleware
(defn wrap-content-type [handler content-type]
(fn [request]
(let [response (handler request)]
(assoc-in response [:headers "Content-Type"] content-type))))
(defn wrap-content-type [handler content-type]
(fn [request]
(let [response (handler request)]
(assoc-in response [:headers "Content-Type"] content-type))))
(defn json-response [data & [status]]
{:status (or status 200)
:headers {"Content-Type" "application/edn"}
:body (pr-str data)})
(def app
(wrap-content-type my-ip "text/html"))
(defn serve [request]
(app request))
;; Routes
(defroutes routes
(GET "/" [] (str "Server is running"))
(GET "/ws" [] handle-websocket)
(context
"/api" []
(GET "/languages" []
(let [prog (get-in db/data [:languages])]
(when prog
(edn-response prog))))
(GET "/languages/:id/:type" [id type]
(let [stats (filter #(and
(= (:id %) id) (= (:type %) type))
(get-in db/data [:stats]))]
(when stats
(response stats)))))))
(def app
(->
(handler/site router/routes)
(wrap-json-body)
(wrap-json-response)
(wrap-edn-params)
(wrap-defaults api-defaults)
(wrap-cors
:access-control-allow-origin #".+"
:access-control-allow-methods [:get :post :put :delete :head]
:access-control-allow-headers ["Content-Type" "X-Requested-With"])))
(defn -main [& _]
(let [port (Integer. (or (System/getenv "SERVER_PORT") 8000))]
(server/run-server app {:port port :join? false})
(log/info "Server started and listening at port..." port)))
(defresource list-resource
:available-media-types ["application/json"]
:allowed-methods [:get :post]
:known-content-type? #(check-content-type % ["application/json"])
:malformed? #(parse-json % ::data)
:post! #(let [id (str (inc (rand-int 100000)))]
(dosync (alter entries assoc id (::data %)))
{::id id})
:post-redirect? true
:location #(build-entry-url (get % :request) (get % ::id))
:handle-ok #(map (fn [id] (str (build-entry-url (get % :request) id)))
(keys @entries)))
https://github.com/priyatam/ring-micro