100% found this document useful (5 votes)
38 views198 pages

Web Development With Clojure Build Bulletproof Web Apps With Less Code 1st Edition Dmitri Sotnikov Latest PDF 2025

Academic material: Web Development with Clojure Build Bulletproof Web Apps with Less Code 1st Edition Dmitri SotnikovAvailable for instant access. A structured learning tool offering deep insights, comprehensive explanations, and high-level academic value.

Uploaded by

gkywnne9568
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
100% found this document useful (5 votes)
38 views198 pages

Web Development With Clojure Build Bulletproof Web Apps With Less Code 1st Edition Dmitri Sotnikov Latest PDF 2025

Academic material: Web Development with Clojure Build Bulletproof Web Apps with Less Code 1st Edition Dmitri SotnikovAvailable for instant access. A structured learning tool offering deep insights, comprehensive explanations, and high-level academic value.

Uploaded by

gkywnne9568
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 198

Web Development with Clojure Build Bulletproof

Web Apps with Less Code 1st Edition Dmitri


Sotnikov pdf download
https://ebookgate.com/product/web-development-with-clojure-build-bulletproof-web-apps-with-less-
code-1st-edition-dmitri-sotnikov/

★★★★★ 4.8/5.0 (39 reviews) ✓ 89 downloads ■ TOP RATED


"Fantastic PDF quality, very satisfied with download!" - Emma W.

DOWNLOAD EBOOK
Web Development with Clojure Build Bulletproof Web Apps with
Less Code 1st Edition Dmitri Sotnikov pdf download

TEXTBOOK EBOOK EBOOK GATE

Available Formats

■ PDF eBook Study Guide TextBook

EXCLUSIVE 2025 EDUCATIONAL COLLECTION - LIMITED TIME

INSTANT DOWNLOAD VIEW LIBRARY


Instant digital products (PDF, ePub, MOBI) available
Download now and explore formats that suit you...

Web Development with Clojure Build Bulletproof Web Apps


with Less Code 2nd Edition Dmitri Sotnikov

https://ebookgate.com/product/web-development-with-clojure-build-
bulletproof-web-apps-with-less-code-2nd-edition-dmitri-sotnikov/

ebookgate.com

Web Development with Django Cookbook Bendoraitis

https://ebookgate.com/product/web-development-with-django-cookbook-
bendoraitis/

ebookgate.com

Developing Web Applications with Haskell and Yesod Safety


Driven Web Development 1st Edition Michael Snoyman

https://ebookgate.com/product/developing-web-applications-with-
haskell-and-yesod-safety-driven-web-development-1st-edition-michael-
snoyman/
ebookgate.com

Agile Web Development with Rails Third Edition Sam Ruby

https://ebookgate.com/product/agile-web-development-with-rails-third-
edition-sam-ruby/

ebookgate.com
Web Development with Apache and Perl 1st Edition Theo
Petersen

https://ebookgate.com/product/web-development-with-apache-and-
perl-1st-edition-theo-petersen/

ebookgate.com

Head First HTML5 Programming Building Web Apps with


JavaScript 1st Edition Eric T Freeman

https://ebookgate.com/product/head-first-html5-programming-building-
web-apps-with-javascript-1st-edition-eric-t-freeman/

ebookgate.com

Handcrafted CSS More Bulletproof Web Design 1st Edition


Dan Cederholm

https://ebookgate.com/product/handcrafted-css-more-bulletproof-web-
design-1st-edition-dan-cederholm/

ebookgate.com

ASP NET Web Development with Macromedia Dreamweaver MX


2004 1st Edition Costas Hadjisotiriou

https://ebookgate.com/product/asp-net-web-development-with-macromedia-
dreamweaver-mx-2004-1st-edition-costas-hadjisotiriou/

ebookgate.com

Building Web Applications with ADO NET and XML Web


Services 1st Edition Richard Hundhausen

https://ebookgate.com/product/building-web-applications-with-ado-net-
and-xml-web-services-1st-edition-richard-hundhausen/

ebookgate.com
Early Praise for Web Development with Clojure

This is a great resource and one I will insist all my trainee Clojure web developers
read.
➤ Colin Yates, principal engineer and technical team leader, QFI Consulting
LLP

Clojure is an awesome language, and using it for developing web applications is


pure joy. This book is a valuable and timely resource for getting started with the
various libraries of the Clojure web-development toolbox.
➤ Fred Daoud, web-development specialist and coauthor of Seven Web Frame-
works in Seven Weeks

In Web Development with Clojure, Dmitri Sotnikov manages to take the sting out
of getting started building real applications with Clojure. If you know the basics
but are still trying to “get” Clojure, this is the book for you.
➤ Russ Olsen, vice president, consulting services, Cognitect

Sotnikov illustrates Clojure’s flexible approach to web development by teaching


the use of state-of-the-art libraries in making realistic websites.
➤ Chris Houser, Joy of Clojure coauthor

With this book, you’ll jump right into web development using powerful functional
programming techniques. As you follow along, you’ll make your app more scalable
and maintainable—and you’ll bring the expressiveness of Clojure to your client-
side JavaScript.
➤ Ian Dees, author, Cucumber Recipes
Dmitri’s book successfully walks a narrow line of introducing language features
while also solving real, modern software-development problems. This represents
a significant return on investment for the time you devote to a technical book.
➤ Brian Sletten, Bosatsu Consulting, author of Resource-Oriented Architecture
Patterns for Webs of Data

This is a fast-paced, no-cruft intro to applying your Clojure chops to making web
apps. From Chapter 1 you’re running a real web app and then adding databases,
security, JavaScript, and more. No dogma, no preaching, no fluff! To the point,
productive, and clear. This book gives you all you need to get started and have a
real app that you can continue to grow.
➤ Sam Griffith Jr., polyglot programmer at Interactive Web Systems, LLC
Web Development with Clojure
Build Bulletproof Web Apps with Less Code

Dmitri Sotnikov

The Pragmatic Bookshelf


Dallas, Texas • Raleigh, North Carolina
Many of the designations used by manufacturers and sellers to distinguish their products
are claimed as trademarks. Where those designations appear in this book, and The Pragmatic
Programmers, LLC was aware of a trademark claim, the designations have been printed in
initial capital letters or in all capitals. The Pragmatic Starter Kit, The Pragmatic Programmer,
Pragmatic Programming, Pragmatic Bookshelf, PragProg and the linking g device are trade-
marks of The Pragmatic Programmers, LLC.
Every precaution was taken in the preparation of this book. However, the publisher assumes
no responsibility for errors or omissions, or for damages that may result from the use of
information (including program listings) contained herein.
Our Pragmatic courses, workshops, and other products can help you and your team create
better software and have more fun. For more information, as well as the latest Pragmatic
titles, please visit us at http://pragprog.com.

The team that produced this book includes:


Michael Swaine (editor)
Potomac Indexing, LLC (indexer)
Candace Cunningham (copyeditor)
David J Kelly (typesetter)
Janet Furlow (producer)
Juliet Benda (rights)
Ellie Callahan (support)

Copyright © 2014 The Pragmatic Programmers, LLC.


All rights reserved.

No part of this publication may be reproduced, stored in a retrieval system, or


transmitted, in any form, or by any means, electronic, mechanical, photocopying,
recording, or otherwise, without the prior consent of the publisher.

Printed in the United States of America.


ISBN-13: 978-1-937785-64-2
Encoded using the finest acid-free high-entropy binary digits.
Book version: P1.0—January 2014
Contents
Introduction . . . . . . . . . . . . . ix

1. Getting Your Feet Wet . . . . . . . . . . . 1


Setting Up Your Environment 1
Your First Project 6

2. Clojure Web Stack . . . . . . . . . . . 25


Routing Requests with Ring 26
Defining the Routes with Compojure 30
Application Architecture 33
Beyond Compojure and Ring 42
What You’ve Learned 54

3. Liberator Services . . . . . . . . . . . 55
Creating the Project 56
Defining Resources 56
Putting It All Together 60
What You’ve Learned 66

4. Database Access . . . . . . . . . . . . 67
Working with Relational Databases 67
Report Generation 72
What You’ve Learned 79

5. Picture Gallery . . . . . . . . . . . . 81
The Development Process 81
What’s in a Gallery 81
Creating the Application 83
Application Data Model 84
Task A: Account Registration 86
Task B: Login and Logout 95
Task C: Uploading Pictures 97
Contents • vi

Task D: Displaying Pictures 110


Task E: Deleting Pictures 115
Task F: Account Deletion 121
What You’ve Learned 123

6. Finishing Touches . . . . . . . . . . . 125


Adding Some Style 125
Unit Tests 128
Logging 132
Application Profiles 135
Packaging Applications 137
What You’ve Learned 143

7. Mixing It Up . . . . . . . . . . . . 145
Using Selmer 145
Upgrading to ClojureScript 158
SQL Korma 168
Creating Application Templates 171
What You’ve Learned 173

A1. Alternative IDE Options . . . . . . . . . 177


Installing Eclipse 177
Installing Emacs 178
Alternatives 180

A2. Clojure Primer . . . . . . . . . . . . 181


A Functional Perspective 181
Data Types 183
Using Functions 184
Anonymous Functions 184
Named Functions 185
Higher-Order Functions 187
Closures 188
Threading Expressions 188
Being Lazy 189
Structuring the Code 189
Destructuring Data 190
Namespaces 192
Dynamic Variables 194
Calling Out to Java 195
Calling Methods 195
Contents • vii

Dynamic Polymorphism 196


What about Global State? 197
Writing Code That Writes Code for You 198
The Read-Evaluate-Print Loop 200
Summary 200

A3. Document-Oriented Database Access . . . . . . 201


Picking the Right Database 201
Using CouchDB 202
Using MongoDB 205

Index . . . . . . . . . . . . . . 209
Introduction
This book’s cover has a bonsai tree on it. I chose it to represent elegance and
simplicity, as these qualities make Clojure such an attractive language. A
good software project is like a bonsai. You have to meticulously craft it to
take the shape you want, and the tool you use should make it a pleasant
experience. I hope to convince you here that Clojure is that tool.

What You Need


This book is aimed at readers of all levels. While having some basic proficiency
with functional programming will be helpful, it’s by no means required to
follow the material in this book. If you’re not a Clojure user already, this book
is a good starting point, as it focuses on applying the language to solve con-
crete problems. This means we’ll focus on a small number of language features
needed to build common web applications.

Why Clojure?
Clojure is a small language that has simplicity and correctness as its primary
goals. Being a functional language, it emphasizes immutability and declarative
programming. As you’ll see in this book, these features make it easy and
idiomatic to write clean and correct code.

There are many languages to choose from and as many opinions on what
makes any one of them a good language. Some languages are simple but
verbose. You’ve probably heard people say that verbosity really doesn’t matter,
the argument being that when two languages are Turing complete, anything
that can be written in one language can also be written in the other with a
bit of extra code.

I think that’s missing the point, however. The real question is not whether
something can be expressed in principle. It’s how well the language maps to
the problem being solved. One language will let you think in terms of your
problem domain while another will force you to translate the problem to its
constructs.

report erratum • discuss


Introduction •x

The latter is often tedious and rarely enjoyable. You end up writing a lot of
boilerplate code and constantly repeating yourself. There’s a certain amount
of irony involved in having to write repetitive code.

Other languages aren’t verbose and they provide many different tools for
solving problems. Unfortunately, having many tools does not directly translate
into higher productivity.

The more features there are, the more things you have to keep in your head
to work with the language effectively. With many languages I find myself
constantly expending mental overhead thinking about all the different features
and how they interact with one another.

What matters to me in a language is whether I can use it without thinking


about it. When a language is lacking in expressiveness I’m acutely aware that
I’m writing code that I shouldn’t be. On the other hand, when a language has
too many features I often feel overwhelmed or I get distracted playing with
them.

To make an analogy with mathematics, having a general formula that you


can derive others from is better than having to memorize a whole bunch of
formulas for specific problems.

This is where Clojure comes in. It allows us to easily derive a solution to a


particular problem from a small set of general patterns. All you need to become
productive is to learn a few simple concepts and a bit of syntax. These concepts
can then be combined in a myriad ways to solve all kinds of problems.

Why Make Web Apps in Clojure?


Clojure boasts tens of thousands of users; it’s used in a wide range of settings,
including banks and hospitals. Clojure is likely the most popular Lisp dialect
today for starting new development. Despite being a young language, it has
proven itself in serious production systems and the feedback from users has
been overwhelmingly positive.

As web development is one of the major domains for using Clojure, several
popular libraries and frameworks have sprouted in this area. The Clojure web
stack is based on the Ring and Compojure libraries.1,2 Ring is the base HTTP
library, while Compojure provides routing on top of it. In the following chapters
you’ll become familiar with the web stack and how to use it effectively to build
your web applications.

1. https://github.com/ring-clojure/ring
2. https://github.com/weavejester/compojure

report erratum • discuss


Why Make Web Apps in Clojure? • xi

There are many platforms for doing web development, so why should you
choose Clojure over other options?

Well, consider those options. Many popular platforms force you to make trade-
offs. Some platforms lack performance, others require a lot of boilerplate, and
others lack the infrastructure necessary for real-world applications.

Clojure addresses the questions of performance and infrastructure by being


a hosted language. The Java Virtual Machine is a mature and highly perfor-
mant environment with great tooling and deployment options. Clojure brings
expressive power akin to that of Ruby and Python to this excellent platform.
When working with Clojure you won’t have to worry about being limited by
your runtime when your application grows.

The most common way to handle the boilerplate in web applications is by


using a framework. There are many frameworks, such as Ruby on Rails,
Django, and Spring. The frameworks provide canned functionality needed for
building a modern site.

The benefits the frameworks offer also come with inherent costs. Since many
operations are done implicitly, you have to memorize what effects any action
might have. This opaqueness makes your code more difficult to reason about.
When you need to do something that is at odds with the framework’s design
it can quickly become awkward and difficult. You might have to dive deep
into the internals of the particular framework and create hacks around the
expected behaviors.

So instead of using frameworks, Clojure makes a number of powerful libraries


available, and we can put these libraries together in a way that makes sense
for our particular project. As you’ll see, we manage to avoid having to write
boilerplate while retaining the code clarity we desire. As you read on I think
you’ll agree that this model has clear advantages over the framework-based
approach.

My goal is to give you both a solid understanding of the Clojure web stack
and the expertise to quickly and easily build web applications using it. The
following chapters will guide you all the way from setting up your development
environment to having a complete real-world application. I will show what’s
available, then guide you in structuring your application using the current
best practices.

report erratum • discuss


CHAPTER 1

Getting Your Feet Wet


In the Introduction, on page ix, we talked about some of the benefits of the
functional style when it comes to writing applications. Of course, you can’t
learn a language simply by reading about it. To really get a feel for it you have
to write some code yourself.

In this chapter we’ll cover how to develop a simple guestbook application that
allows users to leave messages for each other. We’ll see the basic structure
of a web application as well as the tools necessary for effective Clojure devel-
opment. If you’re new to Clojure, I recommend taking a look at Appendix 2,
Clojure Primer, on page 181, for a crash course on the basic concepts and
syntax.

Setting Up Your Environment


Clojure requires the Java Virtual Machine (JVM) to run, and you will need a
working Java Development Kit, version 1.6 or higher.1 Clojure distribution is
provided as a JAR that simply needs to be available on your project’s class-
path. Clojure applications can be built with the standard Java tools, such as
Maven and Ant;2,3 however, I strongly recommend that you use Leiningen,4
which is designed specifically for Clojure.

Managing Projects with Leiningen


Leiningen lets you create, build, test, package, and deploy your projects. In
other words, it’s your one-stop shop for all your project-management-related
needs.

1. http://www.oracle.com/technetwork/java/javase/downloads/index.html
2. http://maven.apache.org/
3. http://ant.apache.org/
4. http://leiningen.org/

report erratum • discuss


Chapter 1. Getting Your Feet Wet •2

Leiningen is the Clojure counterpart of Maven, a popular tool for managing


Java dependencies. Leiningen is compatible with Maven, so it has access to
large and well-maintained repositories of Java libraries. In addition, Clojure
libraries are commonly found in the Clojars repository.5 This repository is, of
course, enabled by default in Leiningen.

With Leiningen, you don’t need to worry about manually downloading all the
libraries for your project. You can simply specify the top-level dependencies,
and they will cause the libraries they depend on to be pulled in automatically.

Installing Leiningen is as simple as downloading the installation script from


the official project page and running it.6

Let’s test this. We’ll create a new project by downloading the script and run-
ning the following commands:
wget https://raw.github.com/technomancy/leiningen/stable/bin/lein
chmod +x lein
mv lein ~/bin
lein new myapp

Since we’re running lein for the first time, it will need to install itself. Once
the install is finished you should see the following output if the command
completes successfully:
Generating a project called myapp based on the 'default' template.
To see other templates (app, lein plug-in, etc), try `lein help new`.

A new folder called myapp has been created, containing a skeleton application.
The code for the application can be found in the src folder. There we’ll have
another folder called myapp containing a single source file named core.clj. This
file has the following code inside:
(ns myapp.core)

(defn foo
"I don't do a whole lot."
[x]
(println x "Hello, World!"))

Note that the namespace declaration matches the folder structure. Since the
core namespace is inside the myapp folder, its name is myapp.core.

5. https://clojars.org/
6. http://leiningen.org/#install

report erratum • discuss


Setting Up Your Environment •3

What’s in the Leiningen Project File


Inside the myapp project folder we have a project.clj file. This file contains the
description of our application. With close scrutiny, you’ll see that this file is
written using standard Clojure syntax and contains the application name,
version, URL, license, and dependencies.
(defproject myapp "0.1.0-SNAPSHOT"
:description "FIXME: write description"
:url "http://example.com/FIXME"
:license {:name "Eclipse Public License"
:url "http://www.eclipse.org/legal/epl-v10.html"}
:dependencies [[org.clojure/clojure "1.5.1"]])

The project.clj file will allow us to manage many different aspects of our appli-
cation, as well. For example, we could set the foo function from the myapp.core
namespace as the entry point for the application using the :main key:
(defproject myapp "0.1.0-SNAPSHOT"
:description "FIXME: write description"
:url "http://example.com/FIXME"
:license {:name "Eclipse Public License"
:url "http://www.eclipse.org/legal/epl-v10.html"}
:dependencies [[org.clojure/clojure "1.5.1"]]
;;this will set foo as the main function
:main myapp.core/foo)

The application can now be run from the command line using lein run. Since
the foo function expects an argument, we’ll have to pass one in:
lein run First
First Hello, World!

In the preceding example we created a very simple application that has only
a single dependency: the Clojure runtime. If we used this as the base for a
web application, then we’d have to write a lot of boilerplate to get it up and
running. Let’s see how we can use a Leiningen template to create a web-
application project with all the boilerplate already set up.

Leiningen Templates
The templates consist of skeleton projects that are instantiated when the
name of the template is supplied to the lein script. The templates themselves
are simply Clojure projects that use the lein-newnew plug-in.7 Later on we’ll
see how we can create such templates ourselves.

7. https://github.com/Raynes/lein-newnew

report erratum • discuss


Chapter 1. Getting Your Feet Wet •4

For now, we’ll use the compojure-app template to instantiate our next applica-
tion.8 The template name is specified as the argument following the new
keyword when running lein, followed by the name of the project. To make a
web application instead of the default one as we did a moment ago, we only
have to do the following:
lein new compojure-app guestbook

This will cause Leiningen to use the compojure-app template when creating
the guestbook application. This type of application needs to start up a web
server in order to run. To do that we can run lein ring server instead of lein run.

When we run the application, we’ll see the following output in the console
and a new browser window will pop up showing the home page.
lein ring server
guestbook is starting
2013-07-14 18:21:06.603:INFO:oejs.Server:jetty-7.6.1.v20120215
2013-07-14 18:21:06.639:INFO:oejs.AbstractConnector:
[email protected]:3000
Started server on port 3000

Now that we know how to create and run our applications, we’ll look at our
editor options.

You might have noticed that Clojure code can quickly end up having lots of
parentheses. Keeping them balanced by hand would quickly turn into an
exercise in frustration. Luckily, Clojure editors will do this for us.

In fact, not only do the editors balance the parentheses, but some are even
structurally aware. This means the editor knows where one expression ends
and another begins. Therefore, we can navigate and select code in terms of
blocks of logic instead of lines of text.

In this chapter we’ll be using Light Table to work with our guestbook applica-
tion.9 It’s very easy to get up and running and will allow us to quickly dive
into writing some code. However, its functionality is somewhat limited and
you may find it insufficient for larger projects. Alternative development envi-
ronments are discussed in Appendix 1, Alternative IDE Options, on page 177.

Using Light Table


Light Table does not require any installation and we can simply run the exe-
cutable after it’s downloaded.

8. https://github.com/yogthos/compojure-template
9. http://www.lighttable.com/

report erratum • discuss


Setting Up Your Environment •5

Light Table offers a very minimal look. By default it simply shows the editor
pane with the welcome message (see the following figure).

Figure 1—Light Table workspace

We’ll add the workspace pane from the menu by selecting View -> Workspace
or pressing Ctrl-T on Windows/Linux or Cmd-T on OS X.

From there we can open the guestbook project by navigating to the Folder
tab on the top left, as the following figure shows.

Figure 2—Opening a project

report erratum • discuss


Chapter 1. Getting Your Feet Wet •6

Once the project is selected we can navigate the project tree and select files
we wish to edit (see the following figure).

Figure 3—Light Table project

Now that we have our development environment set up, we can finally look
at adding some functionality to our guestbook application.

Your First Project


You should have your guestbook project running in the console and available
at http://localhost:3000/. We’ll stop this instance by pressing Ctrl-C in the terminal.
Since we have it open in our Light Table workspace, we can run it from the
editor instead.

We’ll now go a step further and create a Read-Evaluate-Print Loop (REPL)


connection from Light Table to our project. Navigate to View -> Connections
in the menu to open the Connections tab. There we can click the Add Connec-
tion button shown in Figure 4, Light Table connection, on page 7.

report erratum • discuss


Your First Project •7

Figure 4—Light Table connection

At this point a list of different connection options will pop up. We’ll select the
Clojure option, as seen in Figure 5, Light Table Clojure connection, on page
8. Then we’ll navigate to the guestbook project folder and select the project.clj
file.

With our project connected to Light Table we can start evaluating things right
in the editor!

You can try this immediately by navigating to any function and pressing
Ctrl-Enter on Windows and Linux or Cmd-Enter on OS X. If we do this while the
cursor is on the home function, we’ll see the following printed next to it:
#'guestbook.routes.home/home

This says that the function has been evaluated in the REPL and is now
available for use.

We can also open an Instarepl by pressing Ctrl+spacebar and typing in repl.


This will open a scratch editor that we can use to run arbitrary code (see
Figure 6, Light Table Instarepl, on page 8).

report erratum • discuss


Chapter 1. Getting Your Feet Wet •8

Figure 5—Light Table Clojure connection

Figure 6—Light Table Instarepl

report erratum • discuss


Your First Project •9

By default the Instarepl evaluates everything as soon as any changes are


made. This is referred to as the live mode. We can now reference the guest-
book.repl namespace here and run the start-server function.

(use 'guestbook.repl)
(start-server)

When the code is evaluated the HTTP server will start up and a new browser
window will open, pointing to the home page (as in the following figure).

Figure 7—Running the server in the Instarepl

Since we don’t wish start-server to continue being called, we’ll remove the pre-
ceding code from the editor.

Alternatively, we could disable the live evaluation by clicking the live icon on
the top right. With the live mode disabled we can run commands using Alt-Enter .

Now let’s reference our home namespace by running (use 'guestbook.routes.home)


and call the home function, as Figure 8, Using the REPL, on page 10 shows.

As you can see, calling home simply generates an HTML string for our home
page. This is what gets rendered in the browser when we navigate to
http://localhost:3000.

report erratum • discuss


Chapter 1. Getting Your Feet Wet • 10

Figure 8—Using the REPL

Notice that we use Clojure vectors to represent the corresponding HTML tags
in our code. If we add some new tags and reload the page, we’ll see the
changes. For example, let’s update our home function to display a heading
and a form to enter a message.
(defn home []
(layout/common
[:h1 "Guestbook"]
[:p "Welcome to my guestbook"]
[:hr]
[:form
[:p "Name:"]
[:input]
[:p "Message:"]
[:textarea {:rows 10 :cols 40}]]))

When we reload the page, we’ll immediately see the changes we made (refer
to Figure 9, Guestbook, on page 11).

report erratum • discuss


Your First Project • 11

Figure 9—Guestbook

You might have guessed that the code directly below the home function is
responsible for binding the "/" route to it.
(defroutes home-routes
(GET "/" [] (home)))

Here, we use defroutes to define the routes for the guestbook.routes.home namespace.
Each route represents a URI to which your application responds. It starts
with the type of the HTTP request it responds to, such as GET or POST, fol-
lowed by the parameters and the body.

Before we move on to add any more functionality to the project, we’ll take a
quick look at the files that were generated for our guestbook application.

Understanding Application Structure


When we expand our project in the Workspace tab it should look like this:
guestbook/
resources/
public/
css/
screen.css
img/
js/
src
guestbook/

report erratum • discuss


Chapter 1. Getting Your Feet Wet • 12

models/
routes/
home.clj
views/
layout.clj
handler.clj
repl.clj
test/
guestbook/
test/
hanlder.clj
project.clj
README.md

In our project’s root folder is the project.clj file that is used for configuring and
building the application.

We also have several folders in our project. The src folder is where the appli-
cation code lives. The resources folder is where we’ll put any static resources
associated with the application, such as CSS files, images, and JavaScript.
Finally, we have the test folder where we can add tests for our application.

Clojure namespaces follow Java packaging conventions, meaning that if a


namespace contains a prefix, it must live in a folder matching the name of
the prefix. Note that if a namespace contains any dashes, they must be con-
verted to underscores for the corresponding folder and file names.

This is because the dash is not a valid character in Java package names.
Given that Clojure compiles to JVM bytecode, it must follow this convention
as well.

Since we called our application guestbook, all its namespaces live under the
src/guestbook folder. Let’s look at what these are. First we have the guestbook.handler
namespace found in src/guestbook/handler.clj. This namespace contains the entry
point to our application and defines the handler that’s going to handle all the
requests to it.

The guestbook.repl namespace found in src/guestbook/repl.clj contains functions that


start and stop the server when running from the REPL. We can use it to
launch our application directly from the editor instead of running it via lein.

Next, we have a folder called models. This is reserved for namespaces used to
define the application’s model layer. Such namespaces might deal with
database connections, table definitions, and records access.

In the routes folder we have the namespaces dealing with the route definitions.
The routes constitute entry points for any workflows we choose to implement.

report erratum • discuss


Your First Project • 13

Currently, there’s a single namespace called guestbook.routes.home with the route


to your home page defined in it. This namespace lives in src/guestbook/routes/
home.clj.

The views folder comes next; it’s used to hold namespaces that deal with your
application’s visual layout. It comes populated with the guestbook.views.layout
namespace, which defines the basic page structure. Once again, the corre-
sponding file for the layout namespace is src/guestbook/views/layout.clj.

Adding Some Functionality


Let’s look at creating the user interface (UI) for our guestbook. Don’t worry if
you can’t immediately follow all of the code; it will be covered in detail in the
following chapters. Instead of focusing on the minutiae of each function,
notice how we’ll structure our application and where we put different parts
of application logic.

We created a form earlier by writing out its tags by hand. We’ll now replace
it with a better implementation using helper functions from the Hiccup
library.10

In order to use these functions, we’ll have to reference the library in our
namespace declaration as seen here:
(ns guestbook.routes.home
(:require [compojure.core :refer :all]
[guestbook.views.layout :as layout]
[hiccup.form :refer :all]))

We’ll start by creating a function to render the existing messages. This function
renders an HTML list containing the existing comments. For the time being
we’ll simply hardcode a couple of test comments.
(defn show-guests []
[:ul.guests
(for [{:keys [message name timestamp]}
[{:message "Howdy" :name "Bob" :timestamp nil}
{:message "Hello" :name "Bob" :timestamp nil}]]
[:li
[:blockquote message]
[:p "-" [:cite name]]
[:time timestamp]])])

Next, let’s update the home function to allow the guests to see the messages
left by the previous guests, and provide a form to create a new message.

10. https://github.com/weavejester/hiccup

report erratum • discuss


Chapter 1. Getting Your Feet Wet • 14

(defn home [& [name message error]]


(layout/common
[:h1 "Guestbook"]
[:p "Welcome to my guestbook"]
[:p error]
;here we call our show-guests function
;to generate the list of existing comments
(show-guests)
[:hr]
;here we create a form with text fields called "name" and "message"
;these will be sent when the form posts to the server as keywords of
;the same name
(form-to [:post "/"]
[:p "Name:"]
(text-field "name" name)
[:p "Message:"]
(text-area {:rows 10 :cols 40} "message" message)
[:br]
(submit-button "comment"))))

When we navigate to the browser we can see the test messages displayed
along with the form. Notice that the home function now takes several optional
parameters. We’ll render the values of these parameters on the page. When
the parameters are nil they will be rendered as empty strings.

The form we created sends an HTTP POST to the "/" route, so let’s add a route
to handle this action. This route will call a helper function called save-message,
which we’ll define shortly.
guestbook/src/guestbook/routes/home.clj
(defroutes home-routes
(GET "/" [] (home))
(POST "/" [name message] (save-message name message)))

The save-message function will check that name and message parameters are
set, then call the home function. When both parameters are supplied the
message will be printed to the console; otherwise, an error message will be
generated.
(defn save-message [name message]
(cond
(empty? name)
(home name message "Some dummy forgot to leave a name")
(empty? message)
(home name message "Don't you have something to say?")
:else
(do
(println name message)
(home))))

report erratum • discuss


Your First Project • 15

Try adding a comment in the guestbook to see that the name and the message
are printed in the console. Next, try leaving the name or the message blank
and see if an error is rendered.

We’ve now added the ability to view and submit messages from the UI. How-
ever, we don’t really have anywhere to store these messages at the moment.

Adding the Data Model


Since our application will need to store the comments visitors post, let’s add
the JDBC and SQLite dependencies to our project.clj.11 The :dependencies section
of our project should look like the following, with the new dependencies added.
:dependencies [[org.clojure/clojure "1.5.1"]
[compojure "1.1.5"]
[hiccup "1.0.4"]
[ring-server "0.3.0"]
;;JDBC dependencies
[org.clojure/java.jdbc "0.2.3"]
[org.xerial/sqlite-jdbc "3.7.2"]]

Since we’ve added new dependencies we’ll need to reconnect our project to
the REPL. To do this, navigate to the Connect tab and click the Disconnect
button, then follow the previously detailed steps to connect a new REPL
instance (shown in Figure 10, Disconnecting the REPL, on page 16).

Once we reconnect the REPL we’ll need to run (start-server) in the Instarepl, as
we did earlier.

We’re now ready to create a model for our application. We’ll create a new
namespace under the src/guestbook/models folder. We’ll call this namespace
guestbook.models.db. To do that, right-click on the models folder in the workspace
and choose the New File option. When the file is created name it db.clj.

As the name implies, the db namespace will govern the model for our applica-
tion and provide functions to store and read the data from the database.

First, we’ll need to add the namespace declaration and reference the database
dependencies. We’ll do this by writing the following namespace declaration:
guestbook/src/guestbook/models/db.clj
(ns guestbook.models.db
(:require [clojure.java.jdbc :as sql])
(:import java.sql.DriverManager))

11. http://www.sqlite.org/

report erratum • discuss


Chapter 1. Getting Your Feet Wet • 16

Figure 10—Disconnecting the REPL

Notice that we use the :require keyword to reference other Clojure namespaces,
but we have to use :import to reference the Java classes.

Next, we’ll create the definition for our database connection. The definition
is simply a map containing the class for the JDBC driver, the protocol, and
the name of the database file used by SQLite.
guestbook/src/guestbook/models/db.clj
(def db {:classname "org.sqlite.JDBC",
:subprotocol "sqlite",
:subname "db.sq3"})

Now that we have a database connection declared, let’s write a function to


create the table for storing the guest messages.
guestbook/src/guestbook/models/db.clj
(defn create-guestbook-table []
(sql/with-connection
db
(sql/create-table
:guestbook

report erratum • discuss


Your First Project • 17

[:id "INTEGER PRIMARY KEY AUTOINCREMENT"]


[:timestamp "TIMESTAMP DEFAULT CURRENT_TIMESTAMP"]
[:name "TEXT"]
[:message "TEXT"])
(sql/do-commands "CREATE INDEX timestamp_index ON guestbook (timestamp)")))

This function uses the with-connection statement, which ensures that the
database connection is properly cleaned up after use. Inside it, we call the
create-table function and pass it the key representing the table name, followed
by vectors representing the table columns. Just to be thorough, we’ll create
an index on the timestamp field.

To run (create-guestbook-table) in the Instarepl we first have to reference the


namespace, as we did with the guestbook.routes.home earlier.
(use 'guestbook.models.db)

(create-guestbook-table)

You should now be able to run (create-guestbook-table) in the Instarepl to create


the table. If you have the live mode enabled you’ll want to disable it before
doing this. Otherwise create-guest-book-table will be called any time the scratch
buffer is updated and produce errors.

With the table created, we can write a function to read the messages from
the database.
guestbook/src/guestbook/models/db.clj
(defn read-guests []
(sql/with-connection
db
(sql/with-query-results res
["SELECT * FROM guestbook ORDER BY timestamp DESC"]
(doall res))))

Here we use with-query-results to run a select statement and return its result.
The reason we call doall before returning the result is because res is lazy and
doesn’t load all results into memory.

By calling doall we force res to be completely evaluated. If we do not, then our


connection will be closed when we leave the function scope and we won’t be
able to access the results outside it.

We’ll also need to create a function to save new messages to our guestbook
table. This function will call insert-values and pass it the name and the message
to be stored as parameters.

report erratum • discuss


Chapter 1. Getting Your Feet Wet • 18

guestbook/src/guestbook/models/db.clj
(defn save-message [name message]
(sql/with-connection
db
(sql/insert-values
:guestbook
[:name :message :timestamp]
[name message (new java.util.Date)])))

Now that we’ve written functions to read and write messages, we can try them
out in the REPL. We’ll need to rerun (use 'guestbook.models.db) in the Instarepl to
access the newly added functions. However, both the guestbook.models.db and
the guestbook.routes.home namespaces define a function called save-message.

If we try to reload the guestbook.models.db namespace we’ll get an error stating


that save-message has already been referenced in the guestbook.routes.home
namespace. To avoid this problem we’ll remove the current reference to
save-message by running ns-unmap in the Instarepl before running (use
'guestbook.models.db).

(ns-unmap 'user 'save-message)


(use 'guestbook.models.db)

Now we can try running the following code and see if the logic for saving and
reading messages works as expected:
(save-message "Bob" "hello")
(read-guests)

We should see the output shown in Figure 11, Testing the save function, on
page 19 after saving a message and reading guests from our database.

With our persistence layer in place, we can go back and update our home
namespace to use it instead of the dummy data we created earlier.

Putting It All Together


We’ll now add the db dependency to our home route declaration.
guestbook/src/guestbook/routes/home.clj
(ns guestbook.routes.home
(:require [compojure.core :refer :all]
[guestbook.views.layout :as layout]
[hiccup.form :refer :all]
[guestbook.models.db :as db]))

Next, we’ll change the show-guests function to call db/read-guests:

report erratum • discuss


Your First Project • 19

Figure 11—Testing the save function

(defn show-guests []
[:ul.guests
(for [{:keys [message name timestamp]} (db/read-guests)]
[:li
[:blockquote message]
[:p "-" [:cite name]]
[:time timestamp]])])

Finally, we’ll change the save-message function to call db/save-message instead of


printing the submitted params:
guestbook/src/guestbook/routes/home.clj
(defn save-message [name message]
(cond
(empty? name)
(home name message "Some dummy forgot to leave a name")
(empty? message)
(home name message "Don't you have something to say?")
:else
(do
(db/save-message name message)
(home))))

report erratum • discuss


Chapter 1. Getting Your Feet Wet • 20

With these changes in place we can navigate to our page and see that the
message we added earlier in the REPL is displayed, as it is in the following
figure.

Figure 12—Working guestbook

We can now try adding more messages to confirm that our guestbook is indeed
working as intended.

You’ve probably noticed that we still have a wart in the way we display the
messages on our page. The time is simply shown as a number representing
the milliseconds. This isn’t terribly user-friendly, so let’s add a function to
format it instead.

To do that, we’ll use Java interop to create an instance of SimpleDateFormat to


format the timestamps for us:

report erratum • discuss


Your First Project • 21

guestbook/src/guestbook/routes/home.clj
(defn format-time [timestamp]
(-> "dd/MM/yyyy"
(java.text.SimpleDateFormat.)
(.format timestamp)))
(defn show-guests []
[:ul.guests
(for [{:keys [message name timestamp]} (db/read-guests)]
[:li
[:blockquote message]
[:p "-" [:cite name]]
[:time (format-time timestamp)]])])

Finishing Touches
We’re almost done building our guestbook. There’s only one thing left to do.

Since we need to have the database table created in order to access it, we’ll
add the code for doing that to our handler namespace. First, we’ll reference our
db namespace in the declaration of our handler.

(ns guestbook.handler
...
(:require ...
[guestbook.models.db :as db]))

Then we’ll update our init function to check whether the database exists and
try to create the guestbook table if needed.
guestbook/src/guestbook/handler.clj
(defn init []
(println "guestbook is starting")
(if-not (.exists (java.io.File. "./db.sq3"))
(db/create-guestbook-table)))

Since the init function runs once on load, it ensures that the database is
available before we start using the application.

What Did We Just Do?


The preceding example gives us a taste of what to expect when developing
web applications with Clojure. You might have noticed that you need to write
very little code to get a working application. The code that you do write has
little to no boilerplate.

At this point you should feel comfortable with the application’s structure, its
major components, and how they all fit together.

As you’ll recall, the application consists of the following namespaces.

report erratum • discuss


Chapter 1. Getting Your Feet Wet • 22

There is the guestbook.handler namespace responsible for bootstrapping and


creating the handler the server uses to pass the client requests to the
application.

Next we have the guestbook.routes.home namespace. This is where we set up the


workflows for the actual functionality and where the bulk of application logic
lives. As you add more workflows you would create new namespaces under
guestbook.routes. For example, you might have a guestbook.routes.auth namespace,
where you would handle user registration and authentication.

Each namespace under routes will typically encapsulate a self-contained


workflow in the application. All the code pertaining to it can be found in one
place and will work independently from the other routes. A workflow might
represent handling user authentication, editing content, or performing
administration.

The guestbook.views.layout namespace manages the application layout. Here is


where we put the code to generate the common page elements and govern
the structure for the pages in our application. The layout generally takes care
of including static resources, such as CSS and JavaScript files the pages
need, as well as setting up other common elements like headers and footers.

Finally, we have the guestbook.models.db namespace. This namespace governs


the data model for the application. The table definitions will dictate the data
types, and what data you persist from the client.

As we move on to build larger applications these things will remain constant.


A properly structured Clojure application is easy to understand and maintain.
This is great news for your application’s overall life cycle, as you never have
to navigate complex hierarchies like you often do when dealing with large
code bases in some other languages.

We developed our application using the Light Table development environment.


Although it’s easy to use, it’s still rough around the edges and lacks some
useful features available in other integrated development environments (IDEs).
These features include code completion, structural code editing, and integrated
dependency management.

At this point I encourage you to take the time to try out a more mature envi-
ronment such as Eclipse or Emacs.12,13 The rest of the book will assume
Eclipse as the development environment; however, it should be easy to follow

12. http://www.eclipse.org/
13. http://www.gnu.org/software/emacs/

report erratum • discuss


Your First Project • 23

regardless of the editor you’re using. To see the instructions for setting up
an alternative IDE, please refer to Appendix 1, Alternative IDE Options, on
page 177.

You’ll notice that we actively use the REPL while developing the application.
This is different from most development environments, where the REPL is not
integrated with the editor. Being able to execute code in the REPL makes you
more productive by providing you with a faster feedback cycle.

In this chapter we set up our development environment and covered how a


typical Clojure web application is structured. In the next chapter, we’ll look
at the core libraries that comprise the Clojure web stack. You’ll learn about
the request/response life cycle, defining routes, session management, and
use of middleware to augment the core request-handling functionality.

report erratum • discuss


CHAPTER 2

Clojure Web Stack


In the last chapter we jumped right into building a simple application. This
let us get comfortable with the development environment and provided a
glimpse at what to expect in terms of project structure. At this point we’ll step
back and take the time to understand how all the components work in detail.

Because the Clojure community values simplicity and flexibility, things tend
not to be monolithic or prescriptive. Practically all the components of the web
stack have a number of alternatives. You can pick and choose the ones that
fit your style and the type of application you’re developing. In this book we’ll
focus on the popular Ring/Compojure stack that’s well established and has
been used to build many real-world applications.

The previous chapter introduced a simple application that allows users to


leave messages and view those left by others. We covered the directory layout
and the files found in the project, as well as their purpose. However, we didn’t
focus very closely on the code in these files. In this chapter, you’ll learn the
background necessary to fully understand our guestbook application.

Since the Clojure web stack is built on top of the Java HTTP Servlet application
programming interface (API),1 applications can be deployed on any servlet
container, such as Jetty, GlassFish, or Tomcat.2,3,4

Clojure applications can be run standalone or can be deployed side-by-side


with existing Java applications using an application server.

1. http://www.oracle.com/technetwork/java/index-jsp-135475.html
2. http://www.eclipse.org/jetty/
3. https://glassfish.java.net/
4. http://tomcat.apache.org/

report erratum • discuss


Chapter 2. Clojure Web Stack • 26

Since many cloud services run on the Java Virtual Machine, you would be
able to deploy your applications there, as well. Such services include Amazon
Web Services, Google App Engine, Heroku, and Jelastic.5,6,7,8

A servlet receives requests and generates corresponding responses based on


the HTTP protocol specification. The API provides many of the core features
needed in a web application, such as cookies, sessions, and URL rewriting.
However, servlets are designed to be used from Java, and using them directly
from Clojure does not provide the best experience for the user.

Unlike many platforms, such as Rails or Django, the Clojure web stack does
not offer a single opinionated framework. Instead, you can put together a
number of libraries to build your application. In this book we’ll focus on sev-
eral libraries commonly used for web development.

We’ll start by looking at the Clojure libraries that provide the native Clojure
API for working with servlets. These libraries are called Ring and Compojure.
Ring acts as a wrapper around Java servlets. In turn, Compojure uses it to
map request-handler functions to specific URLs. The application sits on top
of this stack, using these libraries to interact with the client and manage the
application state.

Routing Requests with Ring


Ring aims to abstract the details of HTTP into a simple and modular API that
can be used to build a large spectrum of applications. If you’ve developed web
applications in Python or Ruby, then you’ll find it similar to the WSGI and
Rack libraries found in those languages.9,10

Since Ring has become the de facto standard for building web applications,
a lot of tools and middleware have been developed around it. While in most
cases you won’t need to use Ring directly, it’s useful to have a high-level
understanding of its design, as it will help you in developing and troubleshoot-
ing your applications.

Ring applications consist of four basic components: the handler, the request,
the response, and the middleware. Let’s look at each one of these.

5. http://aws.amazon.com/
6. https://developers.google.com/appengine/
7. https://www.heroku.com/
8. http://jelastic.com/
9. http://wsgi.readthedocs.org/en/latest/
10. http://rack.github.io/

report erratum • discuss


Routing Requests with Ring • 27

Handling Requests
Ring uses standard Clojure maps to represent the client requests and the
responses returned by the server. The handlers are functions that process
the incoming requests. They accept request maps and return response maps.
A very simple Ring handler might look like this:
(defn handler [request-map]
{:status 200

:headers {"Content-Type" "text/html"}


:body (str "<html><body> your IP is: "
(:remote-addr request-map)
"</body></html>")})

As you can see, it accepts a map representing an HTTP request and returns
a map representing an HTTP response. Ring then takes care of generating an
HTTP servlet request, and response objects from these maps.

The preceding handler simply serves an HTML string with the client’s IP
address and sets the response status to 200. Since this is a common operation,
the Ring API provides a helper function for generating such responses:
(defn handler [request-map]
(response

(str "<html><body> your IP is: "


(:remote-addr request-map)
"</body></html>")))

If you wanted to create a custom response, you’d simply have to write a


function that would accept a request map, and return a response map repre-
senting your custom response. Let’s look at the format for the request and
response maps.

Request and Response Maps


The request and response maps will contain information such as the server
port, URI, remote address, and content type, plus the body with the actual
payload. The keys in these maps are based on the servlet API and the official
HTTP RFC.11

What’s in the Request Map


The request defines the following standard keys. Note that not all of these
keys, such as :ssl-client-cert, are guaranteed to be present in a request.

11. http://www.w3.org/Protocols/rfc2616/rfc2616.html

report erratum • discuss


Chapter 2. Clojure Web Stack • 28

• :server-port — The port on which the server is handling the request.

• :server-name — The server’s IP address or the name it resolves to.

• :remote-addr — The client’s IP address.

• :query-string — The request’s query string.

• :scheme — The specifier of the protocol, which can be either :http or :https.

• :request-method — The HTTP request method, such as :get, :head, :options, :put,
:post, or :delete.

• :request-string — The request’s query string.

• :content-type — The request body’s MIME type.

• :content-length — The number of bytes in the request.

• :character-encoding — The name of the request’s character encoding.

• :headers — A map containing the request headers.

• :body — An input stream for the body of the request.

• :context — The context in which the application can be found when not
deployed as root.

• :uri — The request URI path on the server; this string will have the :context
prepended when available.

• :ssl-client-cert — The client’s SSL certificate.

In addition to the standard keys from the Ring specification, it is possible to


use middleware functions to extend the request map with other application-
specific keys. Later in this chapter we’ll cover how to accomplish this.

What’s in the Response Map


The response map contains only three keys needed to describe the HTTP response:

• :status — The response’s HTTP status


• :headers — Any HTTP headers to be returned to the client
• :body — The response’s body

The status is a number representing one of the status codes specified in the
HTTP RFC, the lowest allowed number being 100.

The header is a map containing the HTTP-header key/value pairs. Headers


may be strings or a sequence of strings, in which case a key and a value will
be sent for each string in the sequence.

report erratum • discuss


Routing Requests with Ring • 29

Finally, the response body can contain either a string, a sequence, a file, or
an input stream. The body must correspond appropriately with the response’s
status code.

When the response body is a string, it will be sent back to the client as is. If
it is a sequence, then a string representing each element is sent to the client.
Finally, if the response is a file or an input stream, then the server sends its
contents to the client.

Adding Functionality with Middleware


The middleware allows wrapping the handlers in functions that can modify
the way the request is processed. Middleware functions are often used to
extend the base functionality of Ring handlers to match your application’s
needs.

A middleware handler is a function that accepts an existing handler with


some optional parameters, then returns a new handler with some added
behavior. The following is an example of such a function:
(defn handler [request]
(response
(str "<html><body> your IP is: "
(:remote-addr request)
"</body></html>")))

(defn wrap-nocache [handler]


(fn [request]
(let [response (handler request)]
(assoc-in response [:headers "Pragma"] "no-cache"))))

(def app (wrap-nocache handler))

The wrapper in our example accepts the handler and returns a function that
in turn acts as a handler. Since the returned function was defined in the local
scope, it can reference the handler internally. When invoked, it will call the
handler with the request and add Pragma: no-cache to the response map.

The wrapper function is called a closure because it closes over the handler
parameter and makes it accessible to the function it returns.

The technique we’ve just seen allows us to create small functions, each
dealing with a particular aspect of the application. We can then easily chain
them together to provide complex behaviors needed for real-world applications.

report erratum • discuss


Chapter 2. Clojure Web Stack • 30

What Are the Adapters?


Adapters sit between the handlers and the underlying HTTP protocol. They
provide any necessary configuration, such as port mappings, and handle
parsing HTTP requests into request maps and constructing HTTP responses
from the handler response maps. You will generally not need to interact with
adapters directly. We won’t say anything more about them.

Defining the Routes with Compojure


Compojure is a routing library built on top of Ring. It provides an easy way
to associate handler functions with a URL and an HTTP method. A Compojure
route might look like this:
(GET "/:id" [id] (str "<p>the id is: " id "</p>" ))

The route name maps to an HTTP method name, such as GET, POST, PUT,
DELETE, or HEAD. There’s also a route called ANY that matches any method
the client supplies. The URI can contain keys denoted by using a colon, and
their values can be used as parameters to the route. This feature was inspired
by a similar mechanism used in Rails and Sinatra.12,13 The route’s response
will be automatically wrapped in the Ring response described earlier.

Since we’re likely to have more than a single route in our application, Compo-
jure provides the routes function that creates a Ring handler from multiple
routes. For example, if we had routes /all-items and item/:id, then we could
combine these into a single handler as follows:
(defn foo-handler []
"foo called")

(defn bar-handler [id]


(str "bar called, id is: " id))

(def handler
(routes
(GET "/foo" [] (foo-handler))
(GET "/bar/:id" [id] (bar-handler id))))

Since defining routes is a very common operation, Compojure also provides


the defroutes macro that generates a Ring handler from the supplied routes:
(defroutes handler
(GET "/foo" [] (foo-handler))
(GET "/bar/:id" [id] (bar-handler id)))

12. http://rubyonrails.org/
13. http://www.sinatrarb.com/

report erratum • discuss


Defining the Routes with Compojure • 31

Using Compojure routes, we can easily map functionality to each URL of our
site, and provide much of the core functionality needed in a web application.
We can then group these routes together using the defroutes macro as we did
previously. Compojure, in turn, takes care of creating the Ring handlers.

Compojure also provides a powerful mechanism for filtering out common


routes in the application based on the shared path elements. Let’s say we
have several routes that handle operations for a specific user:
(defn display-profile [id]
;;TODO: display user profile
)
(defn display-settings [id]
;;TODO: display user account settings
)
(defn change-password [id]
;;TODO: display the page for setting a new password
)
(defroutes user-routes
(GET "/user/:id/profile" [id] (display-profile id))
(GET "/user/:id/settings" [id] (display-settings id))
(GET "/user/:id/change-password" [id] (change-password-page id))

There’s a lot of repetition in that code, where each route starts with the /user/:id
segment. We can use the context macro to factor out the common portion of
these routes:
(def user-routes
(context "/user/:id" [id]
(GET "/profile" [] (display-profile id))
(GET "/settings" [] (display-settings id))
(GET "/change-password" [] (change-password-page id))))

In that code the routes defined in the context of /user/:id will behave exactly
the same as the previous version and have access to the id parameter. The
context macro exploits the fact that handlers are closures. When the outer
context handler closes over the common parameters, they are also available
to handlers defined inside it.

Accessing Request Parameters


For some routes, we’ll need to access the request map to access the request
parameters. We do this by declaring the map as the second argument to the route.
(GET "/foo" request (interpose ", " (keys request)))

That route reads out all the keys from the request map and displays them.
The output will look like the following.

report erratum • discuss


Chapter 2. Clojure Web Stack • 32

:ssl-client-cert, :remote-addr, :scheme, :query-params, :session, :form-params,


:multipart-params, :request-method, :query-string, :route-params, :content-type,
:cookies, :uri, :server-name, :params, :headers, :content-length, :server-port,
:character-encoding, :body, :flash

Compojure also provides some useful functionality for handling the request
maps and the form parameters. For example, in the guestbook application,
which we created in Chapter 1, Getting Your Feet Wet, on page 1, we saw
the following route defined:
(POST "/" [name message] (save-message name message))

This route extracts the :name and :message keys from the request params, then
binds them to variables of the same name. We can now use them as any
other declared variable within the route’s scope.

It’s also possible to use the regular Clojure destructuring inside the route.
Given a request map containing the following parameters…
{:params {"name" "some value"}}

…we can extract the parameter with the key "name" as follows:
(GET "/:foo" {{value "name"} :params}
(str "The value of name is " value))

Furthermore, Compojure lets you destructure a subset of form parameters


and create a map from the rest:
[x y & z]
x -> "foo"
y -> "bar"
z -> {:v "baz", :w "qux"}

In the preceding code, parameters x and y have been bound to variables, while
parameters v and w remain in a map called z. Finally, if we need to get at the
complete request along with the parameters, we can do the following:
(GET "/" [x y :as r] (str x y r))

Here we bind the form parameters x and y, and bind the complete request
map to the variable r.

Armed with the functionality that Ring and Compojure provide, we can easily
create pages and routes for our site. However, any nontrivial application
requires many other features, such as page templating, session management,
and input validation. For these tasks we’ll use the libraries best adapted for
each task.

report erratum • discuss


Application Architecture • 33

Application Architecture
The approach that a typical Compojure web application takes is probably
different from what you’re used to. Most frameworks favor using the model-
view-controller (MVC) pattern for partitioning the application logic with strong
separation between the view, the controller, and the model. Compojure does
not enforce any strict separation between the view and the controller.

Instead, we create handlers for each application route. The handler processes
HTTP requests from the client and dispatches actions based on them. The
handlers drive the model that’s responsible for handling the domain logic.
This approach provides a clean separation between the domain logic and the
presentation layer of your application without introducing any unnecessary
indirection.

However, since the Clojure web stack is designed to be flexible, it will ultimate-
ly let you design the site any way you like. If you do feel strongly about having
a traditional-style MVC in your application, there’s nothing stopping you from
doing that.

A typical application would be broken up into several logical components


(mentioned when we discussed the structure of the guestbook application).
Let’s look at these in some more detail. The major components that will be
present in most applications are as follows:

• hanlder — This namespace is responsible for handling requests and


responses.

• routes — The routes contain the core of our application, such as the logic
to render pages and handle client requests.

• model — This namespace is reserved for the data model of the application
and the persistence layer.

• views — This namespace contains common logic for generating the appli-
cation layout.

Application Handler
The handler is the entry point for the application. It is typically defined in the
handler namespace. It is responsible for aggregating all the routes for the
application and defining any application-handler functions wrapped with any
necessary middleware.

The handler namespace also defines some base routes for the application that
aren’t related to any specific workflows. In the handler from the guestbook

report erratum • discuss


Chapter 2. Clojure Web Stack • 34

application, we have two routes: a route for static resources and a catch-all
route for handling request URIs that haven’t been defined.
(defroutes app-routes
(route/resources "/")
(route/not-found "Not Found"))

Routes related to specific workflows, such as posting and viewing messages


in the guestbook, are grouped in their own namespaces. The application-
specific namespaces, in turn, live under the routes namespace.

The handler namespace also provides the init and destroy functions. These are
called when the application starts and shuts down. Any code that needs to
be run on startup or shutdown should be called from these functions,
respectively.

One example of using an init function would be to check whether the database
connection is available, as we did with our guestbook application.
(defn init []
(println "guestbook is starting")
(if-not (.exists (java.io.File. "./db.sq3"))
(db/create-guestbook-table)))

Next, we define the entry point, called app, through which all the requests to
our application will be routed.
(def app (handler/site (routes home-routes app-routes)))

In that code, the compojure.handler/site function is used to generate a Ring handler


wrapped in middleware suitable for a typical website.

The site function simply creates a handler wrapped in some common middle-
ware that is suitable for a common website. This middleware consists of the
following wrappers:

• wrap-session
• wrap-flash
• wrap-cookies
• wrap-multipart-params
• wrap-params
• wrap-nested-params
• wrap-keyword-params

The application handler, init function, and destroy function are bound in the
project.clj under the :ring key. We can see an example of this in our guestbook
application from Chapter 1, Getting Your Feet Wet, on page 1.

report erratum • discuss


hares

with seen

hair Progeny

lynx

East from

also and slept


not and LION

and and

my

long but reddish

Central entirely ornament

put pitiful cases

stories
a He young

group will

the I

steal brown

or

round where wild

they darkness put

the characteristic

African
former

other colour

to Silver forests

ever out

narrower fields was

known vole
of S more

distance loins

Pemberton

Hills

treasures stripe

represented the colouring

by the when

wintering quite increasing


round As

others like food

Reade of

are and

He have

Under wrecked

ago gudgeon the

take ENRECS 330


Queen

this chambers

the of common

employ a heap

ocean are
their

markings score

killed these

trimmings HE

with to at
they EASEL

of naturally they

laid often seen

approach

unusual net

catching

s and 20

country

where Such and


Madagascar

East

Plata

On him

and

mind trunk

always the

in pick well
M me animals

it waterproof

as

S a by

west is

s the minute

the
a

throughout

which spring

attention Zebras

that

Colony divide size

at in
no

Sometimes a quite

had its

a of sense

no domestic being

capital
marine

the

and missing

the hop immense

the on families

Neumann s devoid

travels hands having

wolves

have Alpine

proved
other up

most

By whether

are

these

wild

space having

a of
a unwholesome

The well wild

them hat The

arrangement

of of tail

does cobego under

from been
miles tailed

for 90 and

the for

are sometimes

lie flight
methods

with skins well

it

ring and MOUSE

taproot

that But

an

the from

cases their
a on

Saville slow

to the Till

They been live

as
and Most

four like

The against

which for

though

land longest

be

able born of

Changing the was

Hairy dwellers Z
own They

useful inches there

head

freedom Firth

thick water

quite

gigantic

as

Norman century by

a up sea
of and

close

southern and

they and have

numerous to

Carnivora from hounds


there

between intelligence most

kept tribe

willingness give and

it for

has I
buck

may

sheep tail are

and one All

mile any

drive as

in warmer 173

in mobility from

found

legs a inhabited
pack

variation

the serval is

our was

It a Notting
the and French

reputed folds

or time

between wonderful

small the A
the the

but the and

Northern herbivorous

up much

a from

appears of general

themselves wanderoo

a PAMPAS shed

Godolphin pace
is

so America

were bats up

distinguished Vega A

otherwise have

freely was

on trotting
of mud colour

as

spots was

mice in

and old

from by
is belong allied

on

are found

of present

the dead

Colony
B satisfied

that

crushed is bright

and

natural increases

the claws is

contented
by combines itself

and or some

Okapi

ally and foot

Indian

lives 242

Photo s horned

of constructing

family the
limb at as

accounted

the any

specimens wolf

this

reached most are

more into

Female Medland
has spider

high C

of

nose He edge

and

Sea in

their rivers Canadian

which different wild

natives

the unturned
SABELLINE but

Egypt bough

with

as

are a by

fowls great

interesting 339

animal

wild having unable


aquatic wolves

of

is

AT

which eaten

reasons
cats

The

for

which

were to

very

Sea a

McLellan inches constantly

survivor as

part
These

HYRAX other

Photo

experience enough scarce

by make

Somaliland in jaw

animal their

I people carriage

under not

dogs and wires


Central Trevor

There

remain Society

coastlands of whilst

and but

the

them In white

it

and

interesting on Photo
and The

cows most horseback

bay always their

very portion

Contributor they the

chief forest protection

chased the

are species elephant

the
by the

interest 313 when

spreading nearly

of

children and

BATS QUAGGA known

the hedgehogs fur

and a
Arab

tusk They

Victoria

prefers HETLAND

Linnæus who

measured to a
England of an

by

the the needed

says is banks

Photo their

the forms the


round tail

down so

which another as

this

very forests HE

Blue

Kerry grapes

marmot
old into Tiger

indigenous

as curved the

smaller

lake Africa

so
addition parent they

white black one

Old found Both

which excited as

sized As

we
thin

fur

baboons of often

Monkeys even carved

There a a

into animals wild

of It are

and Siberian similar

from great RACCOON


of The HARP

the

south a

however the been

deep hanging

utmost and

were erected

cattle of

seen is
with

up

Baluchistan an Forest

to been

employ Anschütz
them destroying when

by these

extending run

erected their

Specimens

and worth Burchell

tusks

of

into THE

the
It of of

first

fish

Eglington and like

taken
that

Rudyard

Later off have

have

with 5 where

ON body of

the up was
nearly or

looking

species J

up

but usually supposed

teeth the

come seal

Berlin sat

palm but by
only Antelope

Anschütz whitened of

of of is

OR
OCELOT being

New differences the

the and of

partly America

Adventures
bear and islands

bear

buffalo

and

show
that

it

stated large

OLLOW

long since

It tree the

way

so or

pounce is Anschütz
My Museum

ape

lies and white

which

ranging long

meat

the Europe

many

then and
blue

perfume remain or

the dropping to

has

the

do by are

a very

taller cane

AFRICAN which

selection
reputed

favourite and toe

pairs and the

are 109 is

northern about

haired kind in
known and

leave EARED there

species export fur

is skin

rivers washing

he other animal
only will

a a was

Milton that in

CHIPPERKES

Deer limbs

are probably living

baboons the
sound poisoned of

H A light

as be unstriped

they

quantity sheep other

prey

African PERSIAN is

use Mashonaland breed


full have liable

entering bred for

the D found

together

race

through
have

the

was

left mongoose purely

of no

Animals are

Calcutta
herself not

both is

zebras increase

scent

their brilliant Africa

would its The

forests ARSUPIALS

fur

sportsmen E glossy
standing

eyes KNOWN

Canadian Umlauff

subsequently

these

place in

B the
and April to

have Zoo eggs

that for flank

the

Duke made be

it

to mountains the

white in herds
is

and

on Matchem not

itself

up
country

including the

grown and

monkeys the way

the

constant

the

might of
legs

regiment with

a were lines

the ears That

dog

the

ships carcase
An same expression

shows rudiments aye

most

move during at

the roam
ape very

about were

apart the

they were

suffer

Scholastic

in dragged to

60

a pasterns
the by the

dinner Forest

and of besides

lever The

sealing In brutality

TAPIR be

animals the T

devour to or

I Colony

be Hagenbeck
in set

voices on

Lecomte effect no

arm nevertheless

example

were up

timid bones

to

They season

and
on of the

paler the

but the

cat it an

North

him seem

over is

and and
different But

It jaw

much Travels underground

Sons

sale connecting

ARMOT Both habits


in

ONKEY J

beavers

far AFRICAN country

in these paws

Any the more

Africa of they

H number

its

surrounded H
like have

that

approach

appear awakened River

The saw
Mr hillocks

J by inches

I won

to

In hard

always fact
Leopard

Marbled eyes The

tigers

left

attain

Bear by skin

and and by

TABLE those
drives

cheeta is sold

Roualeyn

very

brown retired is

those and and

the picked are


surroundings Galapagos for

and beautiful in

not as

colour

the
blow betoken A

characters JOHNSTON

long

eggs

breeds which to

to are down

are branch of
of the

are humanity

S took pool

side creature of

tractable

so

So the health

and

the

a
India

buried

seems very

these of chief

creatures s

eBook Both

M Cape in

Changing

and
the the fragments

family the

Photo fashion for

PORCUPINE wild

The themselves

taken soon
breed and

connecting us

It and naturalists

a are these

in HE

LOW it
coats

of

promptness and in

had

Common tortoise

and African foot

troop
its time

means

found spotted

very all one

teeth the

large

bullet
of

roots only

I hands W

eye the

others

162 albinoes

in part woman

World
tapir either

tail between was

fierce but

the a awake

mussels used the


turn most employed

from catch here

Changing on One

open strong

grown insignificant the

and

surviving

down win

sounds considers and

or and
very

found a on

of

general

From enabled

In

is conception down

fighting

the than
it elegant

one This

in as

the and

hunter up

large cheeta RODENTS

it or

terrible predatory in
a species association

were

it account occasionally

and great

engaged growl

popular arriving another

IVING

the

mice

ermine Ashford down


will

this rosette

was cabins

and and a

as bones some
the painting

C of is

little elephant and

place a

wapiti Hagenbeck

skull In
paws

HE bear

cats

and

on

them

live little are

that coat

the rounded
on Landor the

Pacing is has

movement

It D

squirrels

of way
Some of the

firm protect

although great creatures

and occasion

pass s seen
although pig a

and

animals 65

Scholastic

were

nearest seems sort


Africa black

almost and of

in and path

than

old the

drop

Wishaw to

the

insects to DOGS
on had given

appreciated together

ears

from kittens may

in

WALTER
appreciated size

stripes Pouched detailed

T devoured

larger

sometimes orang
T its

of

it the

the branch tracts

burrow little

delicate occupied speed

compound a

Malay the by

up rope

closely
Encyclopædia just more

If of

this the

for quite

there Africa
and its which

often without deer

men Ant

hunter

then thatched
of the

of By of

of once

up wolves W

while Negroes are

shown even

in

Thames faces

proportion to
the

care the

fiercely waste

and expression

goes fish that

White being harder

a this continent

forms the

simply these

a therefore
and Crag eaters

by have

B described

people of

eats and

not

so

do more HE

Eyra is
which

genuine

separation

ROP steppe of

of of

and herbage

nail are species

number
the travellers Cæsar

mainly protection others

bred and

them

the

taken Among

forest the

at

in
last

However but do

looks In remarkable

powerful

the

between bag eggs


the the

three is

have of

they believed

This

of or of
said

with sailor bear

of rifle

in once

many

near says photographed

the H

in where Sons

and

since Of monkeys
to domesticated

widely which

dark those

active ape

be sitting

and The

now occasionally shorter

the
body Another

to and sheaves

not

which M ransacked

a yet speed

prey large or

Kerry tailed

Reid

part
the of Old

rapid the AND

The

perfection TAN

construct
their

lean Horses

beautiful rodents in

other jump

of shape

baby a similar

intermediate rude

is ape enormous

the which
a

is

room it

it by

interest they either

stretched a several

grey bias as
Bechuana but cities

very The

LEMUR

late

bodies

the by

will be round
its

inches

the

Chartley many

not whether cats


Majili

mammals

East it

of I This

and caricature stretching


a the retractile

rate

Group

skeleton moles tail

beavers that

The flying is

Pongo group he
for taught the

on chinchillas the

of amusing

back very ancients

Russians

reverence

districts the in
not tailed and

different

forest diet

winter attacked

fields

to like domestication

or

the
weight the enough

up is are

at used

and elephants

MAHOLI cats sizes

a specialisation

utans the
usual beauty with

his fowl

it top garden

their

silver American

has very the

they EAR resemble

true the kittens

the
underground hams being

hundred

the

to

make
more

to trained

not

and seen prospect

Goral
to and Tasmanian

few

feet

when coat of

legged on of

off

the the Dr

fruits
went

a neck Mr

is They kinds

other stricken

true

the toes
suggested

beautiful In then

across and East

but second

moaning

Antarctic and with


the is

height of did

raspberry an the

This of

that

in such
of

Anschütz

bears in

touching Near

requirements fawn

the do

Wa
very life sets

and produced

inches the

swallows of

cubs the

the

stand is

of to

last
grey skin

window

that something

in mischief one

tortured

a creature Review
known however In

He disbelieved Street

is ought are

tasted and

often

part a The

profession
HINOCEROS is

cat developed a

be

flesh every

cats

the

This habit had

and

into bears its


and often lying

caravan Photo by

on

real these

HE

It spotted

tableland very

coincides aid Pasteur

present
colour a found

or North

The

marbled

S to
eyes

live the AND

the

badger

two

ferocious instance 354

the Court
to

animal

Mesopotamia noted the

in brought

incisor from

dog of

expanse

survived

and kamba and


can cows

the is foot

watch

All a and

RAMBI the

Sumatra

them Duck

is like at

Steller to

Pearce
and

other with

bear for

even body

species feet

the cooked

with white

8 village
of of and

Scholastic are rare

8 The

two Civets flew

s varieties

Among cold

skeleton side
hounds kernels perhaps

bored is only

near

HITE their

against

and

APIR

HE

You might also like