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
weavejester
July 04, 2012
Programming
12
1.7k
Functional Web Architecture
Designing web applications with Ring and Compojure
weavejester
July 04, 2012
Tweet
Share
Other Decks in Programming
See All in Programming
LLMとPlaywright/reg-suitを活用した jQueryリファクタリングの実際
kinocoboy2
4
670
複雑化したリポジトリをなんとかした話 pipenvからuvによるモノレポ構成への移行
satoshi256kbyte
1
760
タスクの特性や不確実性に応じた最適な作業スタイルの選択(ペアプロ・モブプロ・ソロプロ)と実践 / Optimal Work Style Selection: Pair, Mob, or Solo Programming.
honyanya
3
140
GraphQL×Railsアプリのデータベース負荷分散 - 月間3,000万人利用サービスを無停止で
koxya
1
1.1k
エンジニアとして高みを目指す、 利益を生み出す設計の考え方 / design-for-profit
minodriven
23
12k
Model Pollution
hschwentner
1
180
プログラミングどうやる? ~テスト駆動開発から学ぶ達人の型~
a_okui
0
190
CSC509 Lecture 01
javiergs
PRO
1
430
ABEMAモバイルアプリが Kotlin Multiplatformと歩んだ5年 ─ 導入と運用、成功と課題 / iOSDC 2025
akkyie
0
320
Conquering Massive Traffic Spikes in Ruby Applications with Pitchfork
riseshia
0
150
iOSアプリの信頼性を向上させる取り組み/ios-app-improve-reliability
shino8rayu9
0
150
2025年版 サーバーレス Web アプリケーションの作り方
hayatow
23
25k
Featured
See All Featured
実際に使うSQLの書き方 徹底解説 / pgcon21j-tutorial
soudai
PRO
188
55k
Raft: Consensus for Rubyists
vanstee
139
7.1k
The Art of Delivering Value - GDevCon NA Keynote
reverentgeek
15
1.7k
Bootstrapping a Software Product
garrettdimon
PRO
307
110k
Building Better People: How to give real-time feedback that sticks.
wjessup
368
20k
Fight the Zombie Pattern Library - RWD Summit 2016
marcelosomers
234
17k
BBQ
matthewcrist
89
9.8k
The MySQL Ecosystem @ GitHub 2015
samlambert
251
13k
The World Runs on Bad Software
bkeepers
PRO
71
11k
How to Ace a Technical Interview
jacobian
280
23k
We Have a Design System, Now What?
morganepeng
53
7.8k
Understanding Cognitive Biases in Performance Measurement
bluesmoon
29
2.6k
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?