clojure and the web

25
Clojure and the Web Nick Bailey

Upload: nickmbailey

Post on 29-Nov-2014

2.499 views

Category:

Technology


0 download

DESCRIPTION

An introduction to the Ring and Compojure libraries for clojure. Presentation from the February meeting of the Austin Clojure Meetup.

TRANSCRIPT

Page 1: Clojure and the Web

Clojure and the WebNick Bailey

Page 2: Clojure and the Web

Who is this guy?

Nick Bailey

[email protected]

@nickmbailey

Page 3: Clojure and the Web

Clojure at DataStax

OpsCenter - Monitoring tool for Apache Cassandra

Server agents written in clojure

Agent communication done using http ( Ring and Compojure)

Page 4: Clojure and the Web

What is Compojure?

https://github.com/weavejester/compojure/wiki

“Compojure is a small web framework for the Clojure programming language. It uses a concise DSL to generate Ring handler functions.”

Page 5: Clojure and the Web

Ok, What is Ring?

https://github.com/mmcgrana/ring

“Ring is a Clojure web applications library inspired by Python's WSGI and Ruby's Rack. By abstracting the details of HTTP into a simple, unified API, Ring allows web applications to be constructed of modular components that can be shared among a variety of applications, web servers, and web frameworks.”

Page 6: Clojure and the Web

Ring Architecture

Adapters

Handlers

Middleware

Request Map

Response Map

Page 7: Clojure and the Web

Adapters

Responsible for implementing the HTTP protocol.

Basically, the server.

Don’t worry, you don’t need to write your own

Ring uses Jetty

Page 8: Clojure and the Web

Handlers

Your application

Process request, return a response

Page 9: Clojure and the Web

Middleware

Augment the functionality of a Handler.

Can:

Modify Requests

Modify Responses

Page 10: Clojure and the Web

Code or GTFO(ns compojure-talk.core (:use ring.adapter.jetty)) ; Middleware (defn wrap-upcase [app] (fn [req] (let [orig-resp (app req)] (assoc orig-resp :body (.toUpperCase (:body orig-resp)))))) ; Handler (defn app [req] {:status 200 :headers {"Content-Type" "text/html"} :body "Hello World from Ring"}) (def upcase-app (wrap-upcase app)) ; Run the adapter (run-jetty upcase-app {:port 8080})

Uppercase the response from the handler

Basic, ‘Hello World’ Handler

Run our adapter

Page 11: Clojure and the Web

But Wait, There’s More

See: ring.middleware

Serve static files -- ring.middleware.file

Browser cookies -- ring.middleware.cookies

User sessions -- ring.middleware.session

And much more: https://github.com/mmcgrana/ring

Page 12: Clojure and the Web

Note for Developing

ring.middleware.reload

Automatically reload handler before each request.

Allows for easy testing

Page 13: Clojure and the Web

Ok, What about Compojure

From earlier: “It uses a concise DSL to generate Ring handler functions.”

An easy an concise way to generate the handler part of your ring application.

Page 14: Clojure and the Web

The Compojure DSL

defroutes

Macro taking a sequence of routes and the code to process requests that match those routes.

(defroutes app (<route>) (<route>) (<route>)

Page 15: Clojure and the Web

Anatomy of a Route

Each route has 4 components

(<HTTP method> <URI> <Req. Destructuring> <response>)

Page 16: Clojure and the Web

HTTP Method

One of the http method types defined by compojure

GET, POST, PUT, DELETE, HEAD, ANY

(GET <URI> <Req. Destructuring> <response>)

Page 17: Clojure and the Web

URI

Simple the URI this route should match

(GET “/hello” <Req. Destructuring> <response>)

Page 18: Clojure and the Web

Request Destructuring

Dynamic URIs, URL Params, POST bodies

We’ll come back to this

(GET “/hello” [] <response>)

Page 19: Clojure and the Web

Response

How we want to handle the request

(GET “/hello” [] “Hello World from Compojure”)

Page 20: Clojure and the Web

Hello World, Revisited (ns compojure-talk.core (:use ring.adapter.jetty)) ; Middleware (defn wrap-upcase [app] (fn [req] (let [orig-resp (app req)] (assoc orig-resp :body (.toUpperCase (:body orig-resp)))))) ; Handler (defroutes app (GET "/hello" [] "Hello World from Compojure")) (def upcase-app (wrap-upcase app)) ; Run the adapter (run-jetty upcase-app {:port 8080})

Note we still have ourcustom middleware

We use defroutes tocreate a handler

Page 21: Clojure and the Web

Back to Destructuring

Access to URI parameters and request body

In the basic form, bind parameter maps and body value to local vars

(GET “/test” {params :params} (println params))

Take full advantage of clojure destructuring

(GET “/hello” {{user :user} :params} (str “Hello” user “!”))

Page 22: Clojure and the Web

URI Destrcturing

Match dynamic URIs

(GET “/hello/:user” [user] (str “Hello” user “!”))

Note: the destructuring syntax above is short for “{{user :user} :params}”

Also allows for advanced pattern matching in the URI

Page 23: Clojure and the Web

Our Final Hello

(ns compojure-talk.compojure (:use compojure.core, ring.adapter.jetty, compojure.handler)) (defroutes app (GET "/hello/:user" [user] (str "Hello " user "!")) (GET "/hello" {{user :user} :params} (if user (str "Hello " user "!") "Hello from Compojure!"))) ; Run the adapter (run-jetty (site app) {:port 8080})

Page 25: Clojure and the Web

QUESTIONS?