Top Banner
Clojure and the Web Nick Bailey
25

Clojure and the Web

Nov 29, 2014

Download

Technology

nickmbailey

An introduction to the Ring and Compojure libraries for clojure. Presentation from the February meeting of the Austin Clojure Meetup.
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
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?