Skip to main content
Web Programming in Clojure
Barry Demchak
CSE294
November 12, 2010
Agenda
• Different REPLs
– Eclipse with Counterclockwise
– Leiningen
• Compojure Web Framework
– Application structure
– Framework execution model
– High level walkthrough
– Addons
• Alternate Frameworks
REPL with Eclipse
• http://www.assembla.com/wiki/show/clojure/Gettin
g_Started_with_Eclipse_and_Counterclockwise
• Install Counterclockwise
– Plugin for Eclipse
– Create and run simple Clojure project
(firstClojureProject)
– Run REPL in console window
• Install the labrepl project (and git/maven)
– Good online tutorial
REPL with Leiningen (“lein”)
• First, install Leiningen – a build tool for Clojure
– http://www.assembla.com/wiki/show/clojure/Get
ting_Started_with_Leiningen
– Installation downloads itself
• Use Lein to create a project
– Create .clj project file
– Use editor to add dependencies
– Use Lein to satisfy dependencies
– Use Lein to start a REPL
https://github.com/weavejester/compojure/wiki/Getting-Started
Agenda
• Different REPLs
– Eclipse with Counterclockwise
– Leiningen
• Compojure Web Framework
– Application structure
– Framework execution model
– High level walkthrough
– Addons
• Alternate Frameworks
Compojure Components
Compojure Web App
Ring
Clout Hiccup
Middleware
«uses»
«call»
«call»
Handler
«call»
«uses»
Abstract HTTP as
{request} and
{response}
Enhance {request}
and route to user-
defined handler
Transform
{request} into
{response}
Compojure component
Application component
DSL for writing
HTML
Compojure Execution Model
What is a “handler”?
• {request} is a map
– :server-port 80
– :server-name “127.0.0.1”
– :remote-addr “127.0.0.1”
– :uri “/”
– :scheme :http
– :headers {}
– :request-method :get
• {response} is a map
– :status 200
– :headers {:X-lang “Clojure” :X-
Framework “Compojure”}
– :body “Hello world”
{request}  handler  {response}
http://groups.google.com/group/compojure/msg/9b9c01a737242b58?
http://efreedom.com/Question/1-3488353/Big-Idea-Behind-Compojure-Routes#3490479
Preview: Simplifying handler construction is Compojure’s key value proposition
The “Ring”
http://www.slideshare.net/mmcgrana/ring-web-apps-in-idiomatic-clojure
• (ns example-app
(:use compojure.server.jetty))
• (defn hello-world [request]
{:status 200
:headers {}
:body "Hello World"})
• (run-server
{:port 8080} "/*"
(servlet hello-world))
A Simple Servlet Using Ring
http://groups.google.com/group/compojure/msg/9b9c01a737242b58?
Getting Started with Compojure
• https://github.com/weavejester/compojure/w
iki/Getting-Started
• Use lien to create a project and dependencies
Agenda
• Different REPLs
– Eclipse with Counterclockwise
– Leiningen
• Compojure Web Framework
– Application structure
– Framework execution model
– High level walkthrough
– Addons
• Alternate Frameworks
A Simple Compojure Web Server
• (ns hello-www.core
(:use compojure.core)
(:require [compojure.route :as route]))
• (defroutes example
(GET "/" [] "<h1>Hello World Wide Web!</h1>")
(route/not-found "Page not found"))
http://weavejester.github.com/compojure/docs/getting-started.html
Clojure Interlude – Useful Macros
• (def hello-world
(-> hello-world
(with-header "X-Lang" "Clojure")
(with-header "X-Framework" "Compojure")))
• (with-header
(with-header
hello-world "X-Lang" "Clojure")
"X-Framework" "Compojure")
• (decorate hello-world
(with-header "X-Lang" "Clojure")
(with-header "X-Framework" "Compojure"))
Compojure Middleware
• (defn with-header[handler header value]
(fn [request]
(let [response (handler request)]
(assoc-in response
[:headers header] value))))
• (decorate hello-world
(with-header "X-Lang" "Clojure")
(with-header "X-Framework" "Compojure"))
handler & args  middleware  handler
http://groups.google.com/group/compojure/msg/9b9c01a737242b58?
Compojure Middleware (cont’d)
• Route Handlers return nil if criteria not met
– (defn index-route [request]
(if (and
(= (:request-method request) :get)
(= (:uri request) "/"))
{:status 200
:headers {}
:body "The index page"))
– (def index-route
(GET “/” “The index page”))
http://groups.google.com/group/compojure/msg/9b9c01a737242b58?
Route Components
Route
HTTP
Method
Response
Function
URI
Pattern
Destructuring
Form
HTTP command
to match
Pattern of URI
to match
Extract attributes
into local values
Generate
response
Index Routes
• (def index-route
(GET "/" "The index page"))
• … (GET "/product/:id"
(str "You chose product: "
(-> request :route-params :id)))
• … (GET #"/product/(d+)"
(str "You chose product: "
((:route-params request) 0)))
http://groups.google.com/group/compojure/msg/9b9c01a737242b58?
Index Routes (cont’d)
• (def echo-typed-url-route
(GET "*"
{:keys [scheme server-name server-port uri]}
(str (name scheme) "://" server-name ":“
server-port uri)))
• (defroutes main-routes
(POST "/save" {form-params :form-params}
(str form-params))
http://efreedom.com/Question/1-3488353/Big-Idea-Behind-Compojure-Routes#3490479
Destructuring and Local Bindings
• Additional functions update namespace local
vars
– with-params (:params)
– with-cookies (:cookies)
– with-multipart
– with-session (:session)
– with-stacktrace
• Many more documented at http://v-182-163-
94-96.ub-freebit.net:8080/docs/api
http://groups.google.com/group/compojure/msg/9b9c01a737242b58?
Response Values
• Base class - {:status 200, :headers {}}
• Modification depends on class of modifier
– Integer sets status code
– String adds to response body
– ISeq, File, and InputStream set response body
– URL opens stream and sets response body
– Map merges into return value map
– Fn produces response from request & response maps
– IPersistentVector updates response map
http://groups.google.com/group/compojure/msg/9b9c01a737242b58?
Response Value Examples
• …(GET “/” “Index page”)
• …(ANY “*” [404 “Page not found”])
• …(GET “/image”
(File. “./public/image.png”))
• …(GET “/new-product”
(if product-released? “Cool!” :next))
• …(GET “/map-example” {:body “Hi there!”})
http://groups.google.com/group/compojure/msg/9b9c01a737242b58?
HTML Compojure (Hiccup)
• [:h1 {:id “title”} “Hello”]
[:h1#id “title” “Hello”]
• [:div (list “Hello” “ Ingolf”)]
• [:div [:span “Hello”]
[:span “ Ingolf”]]
{tag attribute-map content}
• <h1 id=“title”>Hello</h1>
• <div>Hello Ingolf</div>
• <div><span>Hello</span>
<span>Ingolf</span>
</div>
Clojure HTML
http://groups.google.com/group/compojure/msg/9b9c01a737242b58?
Agenda
• Different REPLs
– Eclipse with Counterclockwise
– Leiningen
• Compojure Web Framework
– Application structure
– Framework execution model
– High level walkthrough
– Addons
• Alternate Frameworks
Compojure Addons
• Sandbar
– Session and flash as a global map
– Authorization and authentication (form-based)
– Forms and form validation
https://github.com/brentonashworth/sandbar
Other Web Frameworks
• Enlive
– light weight, non-inference routing
• Webjure
– light weight, provides routing and parsing on top of Java
servlets, Clojure Page Templates
• Conjure
– Rails-like framework for Clojure
• Moustache
– a micro web framework/internal DSL to wire Ring handlers
and middlewares
• Funkyweb
– ring based framework with route inference
https://github.com/cgrand/moustache
https://github.com/tatut/Webjure
http://www.lshift.net/blog/2010/02/27/a-simple-web-application-in-clojure-using-ring-and-enlive
http://groups.google.com/group/clojure/browse_thread/thread/657adc458151e79a/5dfb6362542cf124
Enlive Example
(ns sprout.core)
(defn router [req]
(condp = (:uri req)
"/error" {:status 404
:headers {"Content-Type" "text/html"}
:body (str "Error")}
"/info" {:status 200
:headers {"Content-Type" "text/html"}
:body (str "Ring on " (:server-name req)) }
{:status 200
:headers {"Content-Type" "text/html"}
:body (str "Welcome")}))
(defn app [req] (router req))
http://www.lshift.net/blog/2010/02/27/a-simple-web-application-in-clojure-using-ring-and-enlive
Questions
• Why is Compojure named Compojure?
• What are the requirements of the underlying Java-
based web server to support?
– Scalability
– Extensibility
• How would Compojure participate in web standards?
– Web Services (non-Rest)
– WS-*
• In the long run, does Compojure need Java?
• Does Java need Compojure?
Other References
• Clojure Web Development with Ring
http://mmcgrana.github.com/2010/03/clojure-web-development-ring.html
• Compojure: Clojure Web Framework https://github.com/blog/308-compojure-
clojure-web-framework
• How do you make a web application in Clojure?
http://stackoverflow.com/questions/167262/how-do-you-make-a-web-
application-in-clojure
• Introduction to the Compojure web Framework
http://groups.google.com/group/clojure/browse_frm/thread/448865254f9bd293?
pli=1
• mmcgrana’s ring at master https://github.com/mmcgrana/ring
• weavejester‘s compojure at master https://github.com/weavejester/compojure
• weavejester’s hiccup at master https://github.com/weavejester/hiccup
• WEB DEVELOPMENT – Mature Clojure web frameworks
http://efreedom.com/Question/1-3551805/Mature-Clojure-Web-Frameworks
• arbscht‘s clout at string-keys https://github.com/arbscht/clout/tree/string-keys
• cgrand‘s enlive at master https://github.com/cgrand/enlive