Web programming in clojure

Post on 12-Apr-2017

925 views 1 download

Transcript of Web programming in clojure

Web Programming in Clojure

Barry DemchakCSE294

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/Getting_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/Ge

tting_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 ComponentsCompojure 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/wiki/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

HTTPMethod

ResponseFunction

URIPattern

DestructuringForm

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)))

Method macro

(GET, PUT, POST …)

Variable capture

Regular

expression matching

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

defroutes wraps wrap-params,

wrap-cookies around handler

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 inferencehttps://github.com/cgrand/moustache

https://github.com/tatut/Webjurehttp://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