Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Functional Web Architecture
Search
Sponsored
·
SiteGround - Reliable hosting with speed, security, and support you can count on.
→
weavejester
July 04, 2012
Programming
1.8k
12
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Functional Web Architecture
Designing web applications with Ring and Compojure
weavejester
July 04, 2012
Other Decks in Programming
See All in Programming
JAWS-UG横浜 #102 AWSサ終供養LT会 成仏できない AWS サービスたち 〜本日、三体供養します〜
maroon1st
0
120
音楽のための関数型プログラミング言語mimiumにおける多段階計算の活用
tomoyanonymous
1
310
どこまでゆるくて許されるのか
tk3fftk
0
480
Mujeres en SEO Summit 2026 - Greatest Disaster Hits en Web Performance
guaca
0
240
20260623_Loop Engineeringで自分の分身の問い合わせBotを作る
ryugen04
0
200
気圧・高度・GPSを記録&可視化するアプリ「Koudo」を作った話
hjmkth
1
350
Honoでのサプライチェーン侵害対策 〜 3つのライブラリに学ぶ
yusukebe
7
1.8k
えっ!!コードを読まずに開発を!?
hananouchi
0
190
Performance Engineering for Everyone
elenatanasoiu
0
270
Signal Forms: Details & Live Coding @enterJS 2026 in Mannheim
manfredsteyer
PRO
0
230
【やさしく解説 設計編・中級 #1】一つの車に、運転手は一人 ~ある倉庫システムの事例から~
panda728
PRO
0
170
霧の中の代数的エフェクト
funnyycat
1
350
Featured
See All Featured
Neural Spatial Audio Processing for Sound Field Analysis and Control
skoyamalab
0
370
Designing Powerful Visuals for Engaging Learning
tmiket
1
450
Joys of Absence: A Defence of Solitary Play
codingconduct
1
410
Art, The Web, and Tiny UX
lynnandtonic
304
22k
The Invisible Side of Design
smashingmag
301
52k
Ten Tips & Tricks for a 🌱 transition
stuffmc
0
150
[SF Ruby Conf 2025] Rails X
palkan
2
1.2k
What’s in a name? Adding method to the madness
productmarketing
PRO
24
4.1k
Organizational Design Perspectives: An Ontology of Organizational Design Elements
kimpetersen
PRO
1
760
Jess Joyce - The Pitfalls of Following Frameworks
techseoconnect
PRO
1
190
Dominate Local Search Results - an insider guide to GBP, reviews, and Local SEO
greggifford
PRO
0
210
Typedesign – Prime Four
hannesfritz
42
3.1k
Transcript
Functional Web Architecture Designing web applications with Ring and Compojure
twitter: @weavejester code: github.com/weavejester
Ring. What is it?
An abstraction over HTTP
What's HTTP?
A request / response protocol
HTTP Request Server Response
Ring user=> (server request) response
Ring user=> (handler request) response
HTTP Request GET /resource HTTP/1.1 Host: www.example.com
HTTP Request GET /resource HTTP/1.1 Host: www.example.com method URI headers
Request Map {:request-method :get :uri "/resource" :headers {"host" "www.example.com"}}
HTTP Response HTTP/1.1 200 OK Content-Type: text/plain Hello World
HTTP Response HTTP/1.1 200 OK Content-Type: text/plain Hello World status
body headers
Response Map {:status 200 :headers {"Content-Type" "text/plain"} :body "Hello World"}
Ring Map Function Map
No other abstractions
HTTP Request Server Response Ring Map Function Map
HTTP Request Server Response Ring Map Function Map Adapter
Example (defn handler [request] {:status 200 :headers {"Content-Type" "text/plain"} :body
"Hello World"})
Example (use 'ring.util.response) (defn handler [request] (-> (response "Hello World")
(content-type "text/plain")))
Example (use 'ring.util.response 'ring.adapter.jetty) (defn handler [request] (-> (response "Hello
World") (content-type "text/plain"))) (run-jetty handler {:port 3000})
Why abstract at all?
Power
Power to leverage Clojure
Middleware
Not a new abstraction Just higher order functions
Handler Middleware Handler Map Handler Map
Handler Request Response
Middleware Handler Request Response
Middleware Handler Request Response
Identity (defn wrap-identity [handler] (fn [request] (handler request)))
Caching (defn wrap-cache [handler] (fn [request] (or (get-cache request) (let
[response (handler request)] (put-cache! request response) response))))
Content Types (defn wrap-content-type [handler] (fn [request] (let [ext (get-ext
(:uri request)) type (ext-types ext)] (-> (handler request) (content-type type)))))
Parameters (defn wrap-params [handler] (fn [request] (let [query (:query-string request)
params (parse-params query)] (handler (assoc request :params params)))))
Ring core middleware • Query and form parameters • Multipart
file uploads • Cookies • Sessions • Content-types • Static resources
Routing Multiple resources from the same handler
Basic Routing (use 'ring.util.response) (defn handler [request] (case (:uri request)
"/hello" (response "Hello") "/world" (response "World") :else (not-found "Page not found")))
Compojure
Compojure (use 'compojure.core) (def hello-route (GET "/hello" request "hello"))
Compojure ; (GET "/hello" request "hello") (def hello-route (fn [request]
(if (and (= (:request-method request) :get) (= (:uri request) "/hello")) "hello" nil))))
Compojure ; (GET "/hello" request "hello") (def hello-route (fn [request]
(if (and (= (:request-method request) :get) (= (:uri request) "/hello")) "hello" nil))))
Compojure ; (GET "/hello" request "hello") (def hello-route (fn [request]
(if (and (= (:request-method request) :get) (= (:uri request) "/hello")) "hello" nil))))
Compojure ; (GET "/hello" request "hello") (def hello-route (fn [request]
(if (and (= (:request-method request) :get) (= (:uri request) "/hello")) "hello" nil))))
Compojure ; (GET "/hello" request "hello") (def hello-route (fn [request]
(if (and (= (:request-method request) :get) (= (:uri request) "/hello")) "hello" nil))))
Compojure (use 'compojure.core) (def handler (routes (GET "/hello" _ "hello")
(GET "/world" _ "world")))
Compojure (use 'compojure.core) (defroutes handler (GET "/hello" _ "hello") (GET
"/world" _ "world"))
GET /hello GET /world Routes Request Response
GET /hello GET /world Routes nil Request Response
GET /hello GET /world Routes nil Request nil
Compojure (use 'compojure.core) (require '[compojure.route :as route]) (defroutes handler (GET
"/hello" _ "hello") (GET "/world" _ "world") (route/not-found "Page Not Found"))
GET /hello route/not-found GET /world Routes nil Request Response nil
Compojure (use 'compojure.core) (require '[compojure.route :as route]) (defroutes handler (GET
"/hello" _ "hello") (GET "/world" _ "world") (route/not-found "Page Not Found"))
Compojure (use 'compojure.core) (require '[compojure.route :as route]) (defroutes handler (GET
"/:word" request (-> request :params :word)) (route/not-found "Page Not Found"))
Compojure (use 'compojure.core) (require '[compojure.route :as route]) (defroutes handler (GET
"/:word" {{word :word} :params} word) (route/not-found "Page Not Found"))
Compojure (use 'compojure.core) (require '[compojure.route :as route]) (defroutes handler (GET
"/:word" [word] word) (route/not-found "Page Not Found"))
Compojure (use 'compojure.core) (require '[compojure.route :as route] '[clojure.string :as str])
(defroutes handler (GET "/:word" [word] word) (GET "/:word/shout" [word] (str/upper-case word)) (route/not-found "Page Not Found"))
Compojure (use 'compojure.core) (require '[compojure.route :as route] '[clojure.string :as str])
(defroutes handler (context "/:word" [word] (GET "/" word) (GET "/shout" (str/upper-case word))) (route/not-found "Page Not Found"))
Compojure • Create handlers (GET, POST...) • Cascade handlers (routes)
• Nest handlers (context)
Compojure (wrap-authorize (context "/user/:uid" [uid] (let [user (get-user uid)] (routes
(GET "/" [] @user) (PUT "/" [& data] (put! user data)) (DELETE "/" [] (delete! user))))))
Compojure (defn rest-routes [model] (routes (GET "/" [] @model) (PUT
"/" [& data] (put! model data)) (DELETE "/" [] (delete! user))) (wrap-authorize (context "/user/:uid" [uid] (rest-routes (get-user uid))
What's the big idea?
Complex handlers can be a composition of smaller handlers
Function Orientated Architecture
What next? Content negotiation Finite State Machines REST abstractions Clojurescript
integration
Fin. Questions?