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
フロントエンドのパフォーマンスチューニング
koukimiura
5
2k
GPUを計算資源として使おう!
primenumber
1
250
PHP 8.4の新機能「プロパティフック」から学ぶオブジェクト指向設計とリスコフの置換原則
kentaroutakeda
2
1k
코딩 에이전트 체크리스트: Claude Code ver.
nacyot
0
930
React は次の10年を生き残れるか:3つのトレンドから考える
oukayuka
7
2.4k
明示と暗黙 ー PHPとGoの インターフェイスの違いを知る
shimabox
2
620
LT 2025-06-30: プロダクトエンジニアの役割
yamamotok
0
870
ペアプロ × 生成AI 現場での実践と課題について / generative-ai-in-pair-programming
codmoninc
2
21k
おやつのお供はお決まりですか?@WWDC25 Recap -Japan-\(region).swift
shingangan
0
140
Google Agent Development Kit でLINE Botを作ってみた
ymd65536
2
260
DMMを支える決済基盤の技術的負債にどう立ち向かうか / Addressing Technical Debt in Payment Infrastructure
yoshiyoshifujii
3
410
Python型ヒント完全ガイド 初心者でも分かる、現代的で実践的な使い方
mickey_kubo
1
240
Featured
See All Featured
Building a Scalable Design System with Sketch
lauravandoore
462
33k
Statistics for Hackers
jakevdp
799
220k
Connecting the Dots Between Site Speed, User Experience & Your Business [WebExpo 2025]
tammyeverts
8
340
How to Create Impact in a Changing Tech Landscape [PerfNow 2023]
tammyeverts
53
2.9k
GraphQLの誤解/rethinking-graphql
sonatard
71
11k
Sharpening the Axe: The Primacy of Toolmaking
bcantrill
44
2.4k
Fantastic passwords and where to find them - at NoRuKo
philnash
51
3.3k
Fight the Zombie Pattern Library - RWD Summit 2016
marcelosomers
233
17k
[RailsConf 2023 Opening Keynote] The Magic of Rails
eileencodes
29
9.6k
CoffeeScript is Beautiful & I Never Want to Write Plain JavaScript Again
sstephenson
161
15k
The Illustrated Children's Guide to Kubernetes
chrisshort
48
50k
Building Better People: How to give real-time feedback that sticks.
wjessup
367
19k
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?