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
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
AI時代に設計が 最大の生産性レバーになる 意図駆動開発とデータを消さない設計|Don't Delete Your Data or Your Intent — Design as the Deepest Lever in the AI Era
tomohisa
1
730
ルールを書いて終わらせないハーネスエンジニアリング
yug1224
4
1.9k
yield再入門 #phpcon
o0h
PRO
0
980
Android CLI
fornewid
0
210
Welcome to the "Parametricity" 🏙️ − Generic だけど Specific な世界 −
guvalif
PRO
1
200
関東Kaggler会_NVIDIA_Nemotron_コンペ_振り返り
rick_ds
0
480
Augmenting AI with the Power of Jakarta EE
ivargrimstad
0
540
型も通る、synthも通る、それでも危ない 〜AIのCDKの権限とコストを機械で検証する〜 / It Passes Type Checks, It Passes Synth Checks, but It’s Still Risky — Automatically Verifying Permissions and Costs in AI’s CDK —
seike460
PRO
1
540
全PRの83%がAIレビューだけでマージできるようになった開発組織はその後どうなったか
athug
1
1.5k
継続モナドとリアクティブプログラミング
yukikurage
3
690
仕様書を書く前にハーネスを作る - Agent Native開発は「探索を速く、判定を固く」
gotalab555
4
1.6k
Apache Hive: Toward a Cloud Native Lakehouse
okumin
0
180
Featured
See All Featured
We Are The Robots
honzajavorek
0
290
Designing Experiences People Love
moore
143
24k
Design of three-dimensional binary manipulators for pick-and-place task avoiding obstacles (IECON2024)
konakalab
0
530
Large-scale JavaScript Application Architecture
addyosmani
515
110k
AI Search: Where Are We & What Can We Do About It?
aleyda
0
7.8k
Public Speaking Without Barfing On Your Shoes - THAT 2023
reverentgeek
1
490
Art, The Web, and Tiny UX
lynnandtonic
304
22k
Testing 201, or: Great Expectations
jmmastey
46
8.2k
Max Prin - Stacking Signals: How International SEO Comes Together (And Falls Apart)
techseoconnect
PRO
0
360
The AI Search Optimization Roadmap by Aleyda Solis
aleyda
1
6k
Building AI with AI
inesmontani
PRO
1
1.1k
The Art of Programming - Codeland 2020
erikaheidi
57
14k
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?