clojure and the web

Post on 29-Nov-2014

2.500 Views

Category:

Technology

0 Downloads

Preview:

Click to see full reader

DESCRIPTION

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

TRANSCRIPT

Clojure and the WebNick Bailey

Who is this guy?

Nick Bailey

nick@datastax.com

@nickmbailey

Clojure at DataStax

OpsCenter - Monitoring tool for Apache Cassandra

Server agents written in clojure

Agent communication done using http ( Ring and Compojure)

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.”

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.”

Ring Architecture

Adapters

Handlers

Middleware

Request Map

Response Map

Adapters

Responsible for implementing the HTTP protocol.

Basically, the server.

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

Ring uses Jetty

Handlers

Your application

Process request, return a response

Middleware

Augment the functionality of a Handler.

Can:

Modify Requests

Modify Responses

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

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

Note for Developing

ring.middleware.reload

Automatically reload handler before each request.

Allows for easy testing

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.

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

Anatomy of a Route

Each route has 4 components

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

HTTP Method

One of the http method types defined by compojure

GET, POST, PUT, DELETE, HEAD, ANY

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

URI

Simple the URI this route should match

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

Request Destructuring

Dynamic URIs, URL Params, POST bodies

We’ll come back to this

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

Response

How we want to handle the request

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

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

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 “!”))

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

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

QUESTIONS?

top related