100% found this document useful (3 votes)
26 views111 pages

(Ebook) Web Development With Clojure: Build Bulletproof Web Apps With Less Code by Dmitri Sotnikov ISBN 9781680500820, 1680500821 PDF Download

The document provides information about the ebook 'Web Development with Clojure: Build Bulletproof Web Apps with Less Code' by Dmitri Sotnikov, including its ISBN numbers and download links. It highlights the book's positive reviews and mentions various related titles and editions. Additionally, it notes that the book is currently in beta and may contain errors as it is not fully edited.

Uploaded by

akontabeki
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 (3 votes)
26 views111 pages

(Ebook) Web Development With Clojure: Build Bulletproof Web Apps With Less Code by Dmitri Sotnikov ISBN 9781680500820, 1680500821 PDF Download

The document provides information about the ebook 'Web Development with Clojure: Build Bulletproof Web Apps with Less Code' by Dmitri Sotnikov, including its ISBN numbers and download links. It highlights the book's positive reviews and mentions various related titles and editions. Additionally, it notes that the book is currently in beta and may contain errors as it is not fully edited.

Uploaded by

akontabeki
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/ 111

(Ebook) Web Development with Clojure: Build Bulletproof

Web Apps with Less Code by Dmitri Sotnikov ISBN


9781680500820, 1680500821 Pdf Download

https://ebooknice.com/product/web-development-with-clojure-build-
bulletproof-web-apps-with-less-code-5767486

★★★★★
4.6 out of 5.0 (90 reviews )

DOWNLOAD PDF

ebooknice.com
(Ebook) Web Development with Clojure: Build Bulletproof Web
Apps with Less Code by Dmitri Sotnikov ISBN 9781680500820,
1680500821 Pdf Download

EBOOK

Available Formats

■ PDF eBook Study Guide Ebook

EXCLUSIVE 2025 EDUCATIONAL COLLECTION - LIMITED TIME

INSTANT DOWNLOAD VIEW LIBRARY


We have selected some products that you may be interested in
Click the link to download now or visit ebooknice.com
for more options!.

(Ebook) Web Development with Clojure: Build Bulletproof Web Apps


with Less Code by Dmitri Sotnikov ISBN 9781937785642, 1937785645

https://ebooknice.com/product/web-development-with-clojure-build-
bulletproof-web-apps-with-less-code-4727458

(Ebook) Web Development with Clojure: Build Bulletproof Web Apps


with Less Code, 3rd Edition by Dmitri Sotnikov; Scot Brown ISBN
9781680506822, 9781680508833, 168050682X, 1680508830

https://ebooknice.com/product/web-development-with-clojure-build-
bulletproof-web-apps-with-less-code-3rd-edition-34790336

(Ebook) Web Development with Clojure: Build Large, Maintainable


Web Applications Interactively by Dmitri Sotnikov, Scot Brown
ISBN 9781680506822, 168050682X

https://ebooknice.com/product/web-development-with-clojure-build-large-
maintainable-web-applications-interactively-23668992

(Ebook) Web Development with Clojure: Build Large, Maintainable


Web Applications Interactively, 3rd Edition by Sotnikov, Dmitri,
Brown, Scot ISBN 9781680506822, 168050682X

https://ebooknice.com/product/web-development-with-clojure-build-large-
maintainable-web-applications-interactively-3rd-edition-37295682
(Ebook) Web Development with Clojure, 3rd Edition by Dmitri
Sotnikov; Scot Brown ISBN 9781680506822, 168050682X

https://ebooknice.com/product/web-development-with-clojure-3rd-
edition-23919040

(Ebook) Async JavaScript: Build More Responsive Apps with Less


Code by Trevor Burnham ISBN 9781937785277, 1937785270

https://ebooknice.com/product/async-javascript-build-more-responsive-apps-
with-less-code-2624244

(Ebook) Async JavaScript: Build More Responsive Apps with Less


Code by Trevor Burnham ISBN 9781937785277, 1937785270

https://ebooknice.com/product/async-javascript-build-more-responsive-apps-
with-less-code-43297896

(Ebook) Build Websites with Hugo: Fast Web Development with


Markdown by Brian P. Hogan ISBN 9781680507263, 1680507265

https://ebooknice.com/product/build-websites-with-hugo-fast-web-
development-with-markdown-22615372

(Ebook) Web App Development and Real-Time Web Analytics with


Python: Develop and Integrate Machine Learning Algorithms into
Web Apps by Nokeri, Tshepo Chris ISBN 9781484277829, 1484277821

https://ebooknice.com/product/web-app-development-and-real-time-web-
analytics-with-python-develop-and-integrate-machine-learning-algorithms-
into-web-apps-36127710
P
repa
redexc
lus
ive
lyfo
rBobE
rb www
.a
ll
itebook
s.com
*
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
*

ß
UnderCon s
truction: Theboo kyou’rereadingiss t
il
lunde r
deve
lopm ent
.Asp a
rtofourBet
aboo kprogram,w e’rerel
e a
sing
th
iscop ywellbe foreano rma
lboo kwou ldbere leased.That
wayyou’reabletoge tth
iscontentacoupleo f monthsbefore
it

sa va
i
lableinfinishedform,andwe ’
llgetfeedb a
c kto make
thebooke venbe tter
.Theideaisthateveryonew ins
!

Bewa rned: Theboo kh asnoth ada fu


lltechnicaledit
,so i
tw il
lcon t
ainerror
s.
Ithasnotbeencop yedited,soitwil
lbe ful
lo ftypos,spel
lingm istakes,andthe
occa
sionalcreat
ivep ieceofg ramm ar.Andthe re’sbeennoe f
fortspen tdoing
layout
,soyou ’
llfindb adp ageb reaks
,o ver
-longcode lines,incorre c
th yphen-
at
ion,andalltheo the ruglythingsthatyouwou ldn ’
texpe c
ttosee ina fini
shed
book
. I
talsodoe sn'th avean inde x
. Wec an’
tbehe ldl
iableifyouu sethisbook
totrytocreateasp iffyapp l
i c
ationandyousomehowendupw ithas trangel
y
shapedfarm imp lemen tinstead.Despi
tea l
lthis,wethin kyou ’
llen joyit
!

DownloadUpdates
: Throughoutthisprocessyou’
l
lbeab letogetupda
ted
ebooksf
romyouraccoun
tatpragprog
.com t. Wh
/my_accoun enthebooki
scom-
p
lete
,you’l
lgetthef
ina
lvers
ion(andsub sequentupda
tes
)fromthesamead-
dre
ss
.

Sendusyour
feedback
:In theme an
time,we’
dapp re c
i a
teyousend
ingusyou
r
feedbac
konthi
sbookatpragprog
.com
/t
it
les
/dswdc
loj2 ta,o
/erra rbyus
ingthe
lin
ks
atthebot
tomofeachpage .

Th
ankyoufo
rbe
ingp
arto
ftheP
ragm
ati
ccommun
ity
!

Da
ve&And
y

*
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***

P
repa
redexc
lus
ive
lyfo
rBobE
rb www
.a
ll
itebook
s.com
*
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
*

Web Deve
lopmen
twi
th C
lojure
,
2nd Edi
tion
Bu
ild Bu
lle
tproo
f WebApps w
ithLess Code

Dm
it
riSo
tni
kov

TheP
ragma
tic Bookshe
lf
*
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
**
D*
*
a
l*
l*
*
a
s*
,*
*
T*
e*
x
as•R
ale
igh
,No
rthC
aro
l
ina

P
repa
redexc
lus
ive
lyfo
rBobE
rb www
.a
ll
itebook
s.com
*
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
*

Manyo fthedes ignat


ionsusedby manu fac
tu rersandse l
lerstod is
tinguishthei
rp roduc ts
arecla
imedast radema rks
. Wherethosedes
igna tionsappearinthisbook ,andTheP ragma tic
Programme rs
,LLC wasawa reofat rademarkc laim,thedesignationshavebeenp rintedin
init
ialcapi
tallettersorinallcapi
tals.ThePragma t
icSta
rterKit
,TheP ragmat
icP rogramme r
,
Pragma t
icProg ramm ing,PragmaticBookshelf,P ragP
rogandthel inkingg devicea retrade-
markso fTheP ragma t
icP rogramme rs,LLC
.
Everyprecautionwastakenintheprepa ra
tiono
fthisbook. However
,thepub
lishe
rassumes
norespons ib
ili
tyforer
rorso romissions,orfo
rdamagestha t mayresu
ltf
romthe useof
information(includ
ingprograml
istings)conta
inedherein
.
OurP ragma t
iccourses
, wo rkshops ,andotherproduc
tscanhelpyouandyourteamc rea
te
bette
rso ftwareand have mo refun .Fo r mo
reinfo
rmation
,as we
llasthela
tes
tP ragmatic
ti
tles,pleasevis
itusa thttps://pragprog
.com.

Fo
rin
terna
tiona
lrigh
ts,p
leasecon
tac
trigh
ts@pragprog .
.com

Cop
yrigh
t©2016TheP
ragm
ati
cProg
ramme
rs
,LLC
.
A
l
lrigh
tsre
ser
ved
.

Nopar
tofth
ispubl
icat
ion ma
yberep roduced
,sto
redinaret
rieva
ls y
stem,ort
ran
smi
tted,
inanyfo
rm,o
rb yan
yme ans
,ele
ctron
i c
,me ch
anic
al
,photo
cop y
ing,reco
rding
,oro
the
rwise
,
w
ithou
tthepr
iorconsen
tofthepubli
sher.

Pr
intedintheUn i
tedState
sofAmer
ica
.
ISBN-13
:978-1-68050-082
-0
Encodedu s
ingthefinesta
cid
-f
reeh
igh-en
trop
ybin
aryd
igi
ts
.
Bookvers
ion:B2.0—Feb ru
ary14
,2016

*
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***

P
repa
redexc
lus
ive
lyfo
rBobE
rb www
.a
ll
itebook
s.com
*
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
*

Contents

ChangesintheBe
taRe
leases . . . . . . . . v
ii

In
troduc
tion. . . . . . . . . . . . . ix

1
. Ge
ttingYourFeet Wet. . . . . . . . . . . 1
Se
t UpYou r Env
ironmen
t 1
Bui
ldYourF i
rst WebApp 3
Re
fineYourApp 8
WhatYou’veLearned 23

2
. C
lojure WebS tack . . . . . . . . . . . 25
Route Requests w
ith R
ing 26
Extend Ring 32
De
finethe Rou tes w
ith Compo
jure 35
WhatYou’ veLea rned 39

3
. LuminusArchitecture . . . . . . . . . . 41
ManagetheProject 41
ThinkinTermso fApplica
tion Componen
ts 43
HTMLTemp lat
ingus ingSelmer 51
WhatYou’veLea rned 58

4
. AddClojureSc ript . . . . . . . . . . . 61
Understand Cloju reScr
ipt 61
Conf
igu re Clo
ju reScrip
tSuppo
rt 63
Add ClojureScriptSuppo rt 63
Bui
ldthe U Iw ith Reagent 66
WhatYou’ veLea rned 79

*
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***

P
repa
redexc
lus
ive
lyfo
rBobE
rb www
.a
ll
itebook
s.com
*
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
* Con
ten
ts•
iv

5
. Rea
l-time Messaging W
ith Websocke ts . . . . . . 81
Set Up WebsocketsontheSe rve
r 81
Make Websocketsfrom Clo
jureScrip
t 85
Websockets Us
ingSente 89

6
. Wr
itingRESTfu
l WebServ
ices . . . . . . . . 97
Use Compo
jure
-API 97
WhatYou’veLearned 113

7
. DatabaseAccess . . . . . . . . . . . 115
Work with Re
lat
ional Da
tabases 115
UseYesq l 121
Generate Repor
ts 124
WhatYou’ veLearned 136

8
. P
ictu re Ga
llery . . . . . . . . . . . . 137
The Developmen tP rocess 137
What’ sina Ga l
lery 138
CreatetheApp lication 140
Conf
igu rethe Da tabase 141
TaskA :Accoun t Reg ist ration 143
Task B:Log inandLogou t 162
Task C: UploadingP ictu res 171
Task D :DisplayingP ictu res 180
Task E: Delet
ingP ic tu res 192
TaskF :Accoun t De le t
ion 195
AddingSome Co lor 199

9
. F
inishingTouches . . . . . . . . . . . 205
Uni
tTests 205
PackagetheApplica
tion 211
WhatYou’ veLea
rned 221

A1
. C
lo ju
reP rimer . . . . . . . . . . . . 223
AFunc tiona
lPe rspective 223
DataTypes 225
UsingFunc t
ions 226
AnonymousFunc t
ions 227
NamedFunc t
ions 227
Higher-OrderFunc tions 229
Closures 230
Threading Expressions 231
*
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***

P
repa
redexc
lus
ive
lyfo
rBobE
rb www
.a
ll
itebook
s.com
*
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
* Con
ten
ts•
v

BeingLa zy 232
Structuringthe Code 232
Destructuring Data 233
Namespaces 235
Dynam icVa riables 237
Polymo rphism 237
Whatabou tG lobalState? 240
Wr
iting CodeTha tW ri
tes Codefo
rYou 241
The Read -Eva lua
te-Pr
in tLoop 243
Call
ing Ou ttoJava 243
Call
ing Me thods 244
Summa ry 244

A2
. Authent
icat
ion wi
th OAu
th . . . . . . . . . 247
Why Use OAuth 247

A3
. Documen t-O
rien
ted Da
tabaseAccess . . . . . . 253
Pick
ingthe Righ
t Da
tabase 253
Using CouchDB 254
Using MongoDB 257

A4
. Wr
itingREST ful WebServ
ices W
ithL
ibe
rato
r . . . . 261
Us
ingL iberato
r 261
Def
in ing Resources 262
PuttingItA l
lToge the
r 267

A5
. Le
iningenTemp
lates . . . . . . . . . . 273
What’sinaTempla
te 273

*
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***

P
repa
redexc
lus
ive
lyfo
rBobE
rb www
.a
ll
itebook
s.com
*
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
*

ChangesintheBetaRe
leases
Be
ta2
,Feb
rua
ry14
•Exampleshavebeenupdatedtothelates
tvers
iono
ftheLuminustemp
late
.
Thesourcepathshavebeenchanged ,andtheSwagge
rexamplesnowuse
thela
testvers
ionofcompo jure
-api.

•Fixedtypos andimp
roved ph
ras
ing based on e
rra
ta and be
tareade
r
feedback
.

•Add
itiona
lexp
lana
tions have been addedfo
rsec
tionstha
t we
refound
con
fusing.

•Newappend
ixonus
ing OAu
th w
ithTw
itte
r.

Be
ta1
,Feb
rua
ry3

*
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***

P
repa
redexc
lus
ive
lyfo
rBobE
rb www
.a
ll
itebook
s.com repo
rte
rra
tum• d
iscu
ss
*
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
*

Introduct
ion
Thisbook’
scove rhasabonsa itreeonit
.Ichosei ttorepresenteleganceand
simpl
ici
ty,asthesequa l
ities make Clo
juresuchana t
tractivelanguage.A
goodsoftware p
rojec
tislikea bonsai. You haveto meticulouslycraf
titto
taketheshapeyou wan t,andthetoo lyou useshou ld makei ta pleasan
t
exper
ience
.Ihopetoconv inceyouhe rethatC lojureisthattool.

Wha
tYouNeed
Thisbookisaimeda treadersofallleve
ls. Whi
lehavingsomebas icpro
fic
iency
wi
thfunc t
ionalp rogramm ing wi
ll be help
ful
,it’s by no meansrequiredto
fol
lowthe materialinthisbook.Ifyou’renotaC lo
jureuseralready
,thisbook
isagoods tart
ingpo int,asitfocusesonapp lyingthelanguagetosolvecon -
cretep
roblems.Th is meanswe’l
lfocusonasma llnumbe ro
flanguagefeatures
neededtobuildcommon webapp licat
ions.

WhyC
loju
re?
Clo
ju reisasma lllanguagethathass implic
ityandcorrectnessasi
tsprimary
goals
.Be ingafunct
ionallanguage,itemphas i
zesimmu tabi
li
tyanddeclara
tive
programm ing
. Asyou’ l
lseeinth is book,thesefea
tu res makeiteasy and
idioma ticto wr
itecleanandco rrectcode.

Therea re manylanguagestochoosefromandas manyop inionson wha t


makes anyoneo fthem agoodlanguage . Somelanguages ares imple but
verbose.You’
veprobab
lyhea rdpeop
lesaythatverbosi
tyreal
lydoesn ’
t matte
r,
thea rgumentbeingthat whentwolanguagesareTu ringcomplete,anything
thatcanbe w ri
tteninonelanguagecana lsobe w r
ittenintheo therwitha
bi
to fextracode
.

Ithinkthat
’sm
iss
ingthepo in
t, however
.Therealquest
ionis not whe
ther
someth
ingcanbeexpressedinpr
inciple
.It’
show we
llthelanguage mapsto
theproblembe
ingso
lved. Onelanguage wi
llle
tyouthinkintermso fyour

*
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***

P
repa
redexc
lus
ive
lyfo
rBobE
rb www
.a
ll
itebook
s.com repo
rte
rra
tum• d
iscu
ss
*
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
* In
trodu
ction•
x

prob
lemdomain wh
ileano
the
rwi
llfo
rceyoutot
rans
latethep
rob
lemtoi
ts
const
ruc
ts.

Thelatterisof
tented
iousandra re
lyenjoyab
le.Youend up w
rit
ingaloto
f
boi
lerpla
tecodeandcons tan
tlyrepeat
ingyoursel
f.The
re’
sace r
tainamoun
t
ofironyinvo
lvedinhavingto wr
iterepet
it
ivecode.

Otherlanguages a
ren’tverbose andthey p rov
ide many di
ffe
renttoo
lsfo r
solv
ingproblems
.Un for
tunate
ly,having manytoolsdoesno
tdirect
lyt
ransla
te
intohigherproduct
ivi
ty.

The morefeatu
resthereare
,the morethingsyouhavetokeepinyou rhead
to work wi
ththelanguagee f
fect
ively
. With manylanguagesIf ind mysel
f
cons
tantlyexpend
ing menta
loverheadthink
ingabouta
llthedif
ferentfea
tures
andhowtheyin terac
twithoneano ther
.

What mat
tersto meinalanguageis whetherIcan useitw i
thoutthinking
abouti
t. Whenalanguageislack
inginexpress
ivenessI’
macu te
lyawarethat
I’
mwrit
ingcodethatIshouldn’tbe. Ontheotherhand, whenalanguagehas
too manyfeatu
resIoftenfeeloverwhelmedorIge tdis
tractedplay
ing with
them.

To makeanana logy w
ith mathemat
ics
, hav
ingageneralfo
rmulatha
tyou
canderiveothe
rsfromisbe t
terthanhavingto memo
rizea who
lebuncho
f
formulasfo
rspecif
icprob
lems .

Thisis where C
lojurecomesin.Itallows ustoeasi
lyde r
iveasolut
iontoa
part
icu
larp rob
lemf romasmallsetofgeneralpa
tte
rns.Allyouneedtobecome
produc
tiveistolearnafews
imp leconceptsandabitofsyntax
.Theseconcep
ts
canthenbecomb inedina myriad waystosolveal
lk indsofprob
lems.

Why Make WebApp


sinC
loju
re?
Clo
jureboas tstensofthousandsofusers;i
t’susedinawiderangeo
fsett
ings,
includingbanksandhosp ita
ls.Clo
jureislike
lythe mos
tpopularL
ispdialec
t
todayfo rstart
ingnewdeve lopment. Despi
tebeingayounglanguage
,ithas
provenitse
lfinse r
iousp roduct
ionsystemsandthefeedbackfromusershas
beenove rwhelminglyposit
ive.

As webdevelopmentisoneofthe majordoma insfo r us


ing Clo
jure
,several
popularl
ibrar
iesandframeworkshavesproutedinthisa rea
.TheC lo
jure web
stackisbasedontheR ingand Compoju
relibrar
ies.1,2 R
ingisthebase HTTP

1
. https:/
/gi
thub
.com
/ring-clojure/r
ing
2
. https:/
/gi
thub *
*
.com*
/w *
e*
*
a *
v*
e*
j*
e*
s*
t**
er*
/*
c**
*
om*
p*
o
j*
**
ur*
e**
***
***
***
***
***
***
***
***
***
***
***
***
***
*

P
repa
redexc
lus
ive
lyfo
rBobE
rb www
.a
ll
itebook
s.com repo
rte
rra
tum• d
iscu
ss
*
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
*
W*
h*
*
y**
M
a*
*
k*
e*
**
W*
ebApp
sinC
loju
re?•
xi

lib
rary,wh
ileCompojureprov
idesrou
tingontopo
fit
.Inthefo
llowingchapte
rs
you’l
lbecomefamil
iarwiththewebstackandhowtouseitef
fect
ivelytobui
ld
your webapp
lica
tions
.

Thereare many p
lat
formsfo
r do
ing web deve
lopmen
t,so whyshou
ldyou
choose C
loju
reoverothe
ropt
ions?

Wel
l,conside
rthoseopt
ions. Manypopu
larplatfo
rmsforceyouto maket rade
-
of
fs.Somep lat
formslackperfo
rmance,othersrequi
realotofboile
rplate,and
otherslacktheinf
rastruc
turenecessa
ryforreal-wor
ldapplica
tions.

Clo
jureadd ressesthequestionso fperformanceandinfras
truc
turebybe ing
ahos tedlanguage .TheJavaV ir
tua l Mach
ineisa matureandhighlyper
fo r
-
mantenv ironmen twithgreattoolinganddep loymentop
tions.C
lojurebr
ings
expressivepowe rak
intotha to f RubyandPy thontoth
isexcel
lentpla
tform.
When wo rking with C
lojureyou won’ thaveto wor
ryabou tbe
inglimi
tedby
yourrun time whenyou rapplicationgrows.

The mostcommon wayto handlethe boi


lerp
latein webapplicat
ionsis by
using aframework
. There a
re manyframeworks,such as Ruby on Rails
,
Django,andSpr
ing.Theframeworksprov
idecannedfunct
ionalityneededfor
build
inga modernsite
.

Thebenefi
tsthef rameworksoffe
ralsocome withinherentcos ts
.S ince many
operat
ionsaredoneimp lic
it
ly,youhaveto memo rize whateffec
tsanyac t
ion
mighthave
.Th isopaqueness makesyourcode moredif
ficulttoreasonabou t.
Whenyouneedtodosome thingthatisatodds withthef ramewo rk’sdesign
itcanqu ick
ly becomeawkwa rdand dif
ficu
lt
. You m ight haveto dive deep
intotheinternalsofthepa r
ticu
larframeworkandc reatehacksa roundthe
expectedbehaviors
.

Soinsteadofus ingframewo rks


,Clojure makesanumbe rofpower
full
ibrar
ies
avai
lable,and wecanpu ttheselibra
riestogetherina waythat makessense
forou rpa r
ticularproject
. Asyou’
llsee, we managetoavo idhavingto wr
ite
boi
lerpla
te wh i
leretainingthecodeclarity wedesire
.AsyoureadonIth ink
you’l
lag reetha tth
is mode lhasclearadvan tagesovertheframework-based
approach.

Mygoa listog iveyoubothaso lid unders


tandingo fthe Clojure webstack
andtheexpe r
tisetoquicklyandeas i
lybuild webapp licat
ions us
ingi t
.The
fol
lowingchap terswi
llguideyouallthewayfromse ttingupyou rdevelopment
environmen ttohavingacomp letereal-wor
ldapplica t
ion.I wi
llshow wha t’
s
avai
lable,thengu ideyouins truc
tu r
ingyou rapplication us
ingthecu rrent
bestpractices
.
*
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***

P
repa
redexc
lus
ive
lyfo
rBobE
rb repo
rte
rra
tum• d
iscu
ss
*
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
*

CHAP
TER1

Gett
ingYourFeet Wet
IntheIn t
roduct
ion, on pageix
, welooked a
tsome o fthe benef
its o
fthe
funct
ionalsty
le whenitcomesto writ
ingapplica
tions.Ofcourse
,youcan’t
lea
rnalanguages implybyreadingabouti
t.Toreallyge
tafee
lforityouhave
to wr
itesomecodeyou rsel
f.

Inthischap teryou’l
ld iverightinand bu i
ldagues tbookapp l
icationtha t
al
lowsuse rstoleave messagesforeacho ther
.You’ l
lseethebas ics truc ture
ofa webapp l
ica
tionas we l
lasthetoolsnecessaryforeffec
tive C
lojuredeve l
-
opmen t
. Andyou’ l
lgetafee lfo
r how webdevelopmen tin Clo
ju re wo rks.If
you’
re newto C lo
jure,Irecommendyoureadth roughAppend ix 1,C lojure
Pr
imer,onpage223 ,forac rashcourseonthebas icconceptsandsyn tax.

The mater
ialI’l
lcove rinth isbookisbasedontheexpe r
ienceandpe rsonal
pre
ferencesoftheau thor.It’s wo
rthno t
ingtha tthereareo the requal
lyva l
id
approaches.Thelibrariesand me thodologiesthat we’l
lexp lorea rejustone
waytostructure C
lojure webapp lications,buttheyshou ldp rovideyou with
asolidstar
tingpointus ingthecu rrentbes tpract
ices.

Se
tUpYou
rEnv
ironmen
t
C
lojuredistr
ibu t
ionisp rovidedasaJARtha tneedstobeava i
lableonyou r
pro
ject’
sclasspa th.C lo
ju rerequirestheJavaV i
rtual Mach
ine(JVM )torun,
andyou w il
l need a wo rking Java Developmen tKit(JDK )
,ve rs
ion 1 .7 o
r
h
igher.1 You’l
la lso needto haveLe iningen2
ins
tal
ledino rdertoc reateand
bui
ldthep rojects.

1
. http:/
/www .orac
le.com/
technetwork
/java
/javase
/down
loads
/index
.htm
l
2
. http:/
/le
iningen *
.or*
g
/**
****
****
******
* *
*****
*****
***
***
*****
******
***
****
***
***
***
***
*

P
repa
redexc
lus
ive
lyfo
rBobE
rb repo
rte
rra
tum• d
iscu
ss
*
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
*
C*
h*
a*
*
p
t*
e*
*
r*
1
.*
**
G*
e
tt
ingYou
rFee t•
t We 2

Manag
ingP
roje
ctsw
ithLe
iningen
Lein
ingenletsyouc
reate
,bu i
ld,tes
t,package
,anddeployyou
rpro
jects
.In
other wo
rds
,it’
syourone-s
topshopforal
lyourpro
jec
t-managemen
t-re
lated
needs.

Lein
ingenisthe Clo
ju recounterpar
to f Maven,3 apopularJavabu ildtoo l.It
usesa Mavencompa t
ible dependency managemen tsystemandassuchi t
has accesstolarge and well
-ma in
tainedrepos ito
ries o
f Javalibra r
ies.In
addi
tion,Clo
jurelib
rariesarecommon lyfoundintheC lo
jarsreposi
to ry.4 This
reposi
toryisenabledbyde faultinLeiningen.

W
ithLeiningen
,youdon’ tneedto worryabou t manua
llydownloadingal
lthe
l
ibra
riesforyourpro
jec
t.Speci
fyingthetop-leve
ldependencies w
il
lcauseany
l
ibra
riesthattheydependontobepu lledinau tomat
ica
lly
.

Insta
ll
ingLeiningenisaccomp l
ishedbydownload
ingtheinsta
llat
ionscrip
t
5
fromtheoff
icialp rojec
t pageandrunningit
. Let
’stes
tthis
.C reatea new
pro
jectbydown loadingthescriptandrunn
ingthefol
lowingcommands:
wget https://raw.github.com/technomancy/leiningen/stable/bin/lein
chmod +x lein
sudo mv lein ~/bin
lein new myapp

Notetha ttheprecedingcodeexpectstha
t ~/b
in isavailab
leontheshellpa
th.
Since we’rerunn ingle
inforthefi
rsttime,itw i
ll needtoins
tal
litse
lf
. Once
theins tal
lisf
in ishedyoushou ldseethefo l
lowingou tputi
fthecommand
completessuccess fu
lly
:
Generating a project called myapp based on the 'default' template.
To see other templates (app, lein plug-in, etc), try `lein help new`.

Takea momen
ttolooka
t wha
t wehavenow
.

Anewfoldercalledmyapp hasbeenc rea


ted
,conta
iningaskele
tonapplication.
Thecodefortheapp lica
tioncanbefoundinthesrcfolder
.There we’ll have
ano
therfolderca l
ledmyapp conta
iningasing
lesourcef
ilenamedcore
.cj.Th
l is
f
ilehasthefollow ingcodeinside
:
(ns myapp.core)

(defn foo
"I don't do a whole lot."

3
. http:/
/maven .apache .org/
4
. https:/
/clo
jars.org/
5
. http:/
/le
iningen *
.or*
g*
/#*
i**
n*
s
t**
a
l*
l*
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
**

P
repa
redexc
lus
ive
lyfo
rBobE
rb repo
rte
rra
tum• d
iscu
ss
*
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
B*
*
u
i*
l*You
d rFi
rst WebApp•
3

[x]
(println x "Hello, World!"))

No
tetha
tthenamespacedec
lara
tion ma
tchesthefo
lde
rst
ruc
ture
.Sincethe
core namespaceisins
idethemyapp fo
lde
r,i
tsnameismyapp
.core.

Wha
t’s
intheLe
iningenP
roje
ctF
ile
Insidethemyapp projectfolder we haveapro
jec
t.c
ljfi
le.Thisf
ilecontainsthe
descr
iption o
f ou r app l
icat
ion. The projec
t con f
igura
tionis represented
decla
rative
lyusingregu larClo
jureda tast
ructures.Itcon
tainstheappl
ication
name ,vers
ion, URL,license,anddependenc ies
.
(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.7.0"]])

Thepro
jec
t.c
ljf
ile w
il
lallowusto manage manyd i
ffe
ren
taspec tso fou rapp
li
-
cat
ion.Fo rexample, wecouldse
tthefoofunct
ionfromthemyapp.core names-
paceastheen trypointfortheappl
ica
tionusingthe: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.7.0"]]
;;this will set foo as the main function
:main myapp.core/foo)

Thepoin
to fa
llthis
,though ,istha
tyoucan nowruntheapp l
ica
tionf
rom
thecommandlineus ingle .S
inrun incethefoofunc
tionexpec
tsanargumen
t,
you’
llhavetopassonein:
lein run Obligatory
Obligatory Hello, World!

Bu
ildYou
rFi
rst WebApp
Inthep recedingexample wecrea
tedave rysimpleappl
icat
ionthathason ly
asingledependency:the Clo
jurerunt
ime .I
fyouusedth isasthebasefo ra
webapplicat
ion,thenyou’ dhaveto w
ritealotofboi
lerp
latetogetitupand
running. Le
t’ssee how wecan use a Lein
ingentemplatetocreate a web-
appl
icat
ionp rojec
tw i
thalltheboi
lerp
la tea
lreadyse
tup .

*
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***

P
repa
redexc
lus
ive
lyfo
rBobE
rb repo
rte
rra
tum• d
iscu
ss
*
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
*
C*
h*
a*
*
p
t*
e*
*
r*
1
.*
**
G*
e
tt
ingYou
rFee t•
t We 4

Ourp rimarygoal he
reistoge ta highleve l unders
tanding ofthe p
roject
structureandgetsome thingdone
.I’l
lg lossoversomeo fthefinerdetailsin
orderto main
tainour momen tum. Don’t wor
ryifyoudon ’tfu
llyunderstand
a
llthes tepsatth
ispo int
. We’
llge
tin tothede ta
ilsinsubsequentchap ters
.

C
rea
tinganApp
li
cat
ionF
romaTemp
late
Atemplateconsistofaske letonp ro
jectthatisinstantia
ted wi
ththedes i
red
parameterssuchasthep rojectname .Anumbe rofd i
fferen
ttemp la
tesexis
t
toquicklyin
it
iali
zed i
ffe
ren tkindso fprojec
ts.Lateron we’l
levenseehow we
cancreatesuchtemp la
tesou rselves. ButtheLum inustemp lateprov
idesa
6
goodbaseand we’ l
lbeus ingi t.

Bydefaul
t,Leiningen wi
llusethelatestve rs
ionofthetemp latetha thasbeen
publ
ishedtotheC loja
rsreposi
tory7.The refo
re,theskeletonp rojectsgenerated
bythetemp late may notbeexac t
lythesameastheonesd iscussedinthe
book
.Ino rdertoensu rethatyou’reab letofollowthebookexac tly,Irecom -
mendaddingthefo l
lowingpluginreferenceinthe ~/.
lein
/pro
fi
les.c
ljfile
.This wil
l
ensurethatthep ro
jectsaregeneratedus ingthesameve rsiono fthetemp late
that wasusedinthebook .
{:user {:plugins [[luminus/lein-template "2.9.9.2"]]}}

Ino rdertote
llLein
ingenthatwewan ttouseaspecif
ictemplateforthep
roject
we mustspecifyi
tastheargumen tfo
llowingthenew parameterwhenrunn ing
le
in,fol
lowedbythenameo fthep ro
jec
t.Anyo the
rpa rameters w
il
lbepassed
inasthea rgumentstotheselec
tedtemp late
.

We’llc rea
te a new app
lica
tion byspec
ify
ingluminus asthetemp late name ,
tbook a
gues sthe nameofthep ro
ject
,andaddthe+h2 pa rametertoind icate
that we’dl
iketohaveanins tanceofthe H28 embeddedda tabaseini
tialized
forus :
lein new luminus guestbook +h2

Wha
t’s
ina WebApp
Thistypeofapplica
tionneedstosta r
t upa webse rve
rino rde
rtorun.The
template p
rojec
tcomes withanembeddedImmu tantservercon
figu
redfor
us
,and wecans tar
titbyrunn inrun a
ing le s wed
id wi
ththemyapp p ro
jec
t
9
that weusedtotesttheLein
ingense tup.

6
. h
ttp
://www
.
lum
inusweb
.ne
t/
7
. h
ttps
://c
lojars
.org
/lum
inus
/le
in-
temp
late
8
. h
ttp
://www
.h2da
tabase
.com
/htm
l/ma
in.h
tml
9
. h
ttp
://
immu
tan
t *
r*
.o *
/*
g *
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
**

P
repa
redexc
lus
ive
lyfo
rBobE
rb repo
rte
rra
tum• d
iscu
ss
*
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
B*
*
u
i*
l*You
d rFi
rst WebApp•
5

Whenyouruntheapp lica
tion
,i t maytakeal itt
le wh ile,becauseLeiningen
wi
llfi
rst havetoretr
ieveallofits dependencies. Bu tonce down loadedthe
dependencies w
il
l becachedloca llyinthe ~/.m2/repos
itoryfo
lde
r and wil
l be
avai
lableonsubsequen truns.A f
te rthedependenc iesa redownloaded,you
shouldseethefollow
ingou tputintheconso le.
lein run
21:53:07.252 [main] DEBUG org.jboss.logging - Logging Provider: Slf4jLoggerProvider
15-Jul-19 21:53:08 Nyx INFO [guestbook.handler] - nREPL server started on port 7000
15-Jul-19 21:53:08 Nyx INFO [guestbook.handler] -
-=[guestbook started successfully using the development profile]=-
21:53:08.463 INFO [org.wunderboss.web.Web] (main) Registered web context /
15-Jul-19 21:53:08 Nyx INFO [guestbook.core] - server started on port: 3000

Oncetheapp licationstarts wecanopenanewbrowserwindowandnav


iga
te
tohttp:/
/loca
lhos
t:3000 toseethehomepageofourapplica
tion
.

*
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***

P
repa
redexc
lus
ive
lyfo
rBobE
rb repo
rte
rra
tum• d
iscu
ss
*
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
*
C*
h*
a*
*
p
t*
e*
*
r*
1
.*
**
G*
e
tt
ingYou
rFee t•
t We 6

F
igu
re1—De
fau
ltPage

Nowtha t we’vecreatedourapplica
tionsandtestedthati
t’s wo
rking
,let’
stake
abrieftou rof what’sbeengene ra
tedforus.Followingarethefoldersinthe
generatedp rojec
tw iththef
ilesom it
tedfo
rb revi
ty.
├── env
│ ├── dev
│ │ ├── clj
│ │ │ └── guestbook
│ │ └── resources
│ └── prod
│ ├── clj
│ │ └── guestbook
│ └── res**
*
o*
u*
r*
*
c*
e*
*
s**
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
*

P
repa
redexc
lus
ive
lyfo
rBobE
rb repo
rte
rra
tum• d
iscu
ss
*
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
B*
*
u
i*
l*You
d rFi
rst WebApp•
7

├── resources
│ ├── docs
│ ├── migrations
│ ├── public
│ │ ├── css
│ │ ├── img
│ │ └── js
│ ├── sql
│ └── templates
├── src
│ └── clj
│ └── guestbook
│ ├── db
│ └── routes
└── test
└── clj
└── guestbook
└── test
└── db

Thistimea roundthe pro


jectstruc tu
reiss igni
ficant
ly morecomp lexthan
what wehadinthe myapp p roject. We’
lllearn whatal
lthepiecesa refo
ras
webu i
lddif
ferentapp
licat
ionsth roughou tthebook.Fo rnow, we’
lljusttake
aqu ickoverv
iewofhowthep rojectisstructuredand whattypeso ffi
lesgo
where.

The majori
tyo fou rcodelives underthesrcfo lder.Thisfo
lde rcon ta
insac l
j
folderthat’
sreservedforC loju
resou rcefi
les.Sinceou rapplicationisca l
led
guestbook,thisistherootnamespacefo rthep rojec
t.Theapplicationisfurther
brokendownin todif
feren
tnamespacesbasedonfunc t
ion. We’llexploreeach
ofthesein de tai
linthefo l
lowingchap ter
. The namespacetha tw i
ll be o
f
immed iateinteresttousistheroutes namespace .

Theroutes namespaceisreservedfo
rde f
iningappl
icat
ionroutes. Eachroute
is boundto afunc tionthatisresponsiblefo rp
rocess
ingthereques t and
genera
tingtheresponse .Thisis where majo
rityo
fou rapp
lica
tionlogic wi
ll
live
.

Thedb namespacehousestheda tabasere latedlog


icandservesasthe mode l
laye rfortheapp l
icat
ion.Theguestbook
.db.core namespaceconta
insthelog
icfo r
defining que ries and managingthe da tabase connect
ion, whi
lethe guest-
book.db
.migra
tions namespaceisrespons iblefor managingthe m
igrat
ionslogic.

Theotherfolde
rthatwil
lberelevantforourappl
icat
ionistheresourcesfo
lder
that con
tains al
lthe s
tat
ic asse
ts assoc
iated w
iththe appl
icat
ion . These
inc
lude HTMLtemp la
tes,CSSs ty
les,andsoon.Since wecrea
tedada tabase
*
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***

P
repa
redexc
lus
ive
lyfo
rBobE
rb repo
rte
rra
tum• d
iscu
ss
*
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
*
C*
h*
a*
*
p
t*
e*
*
r*
1
.*
**
G*
e
tt
ingYou
rFee t•
t We 8

fortheappl
ica
tion
,ita
lsocon
tainsam
igra
tions fo
lde
rwi
ththeSQL m
igra
tion
fi
lesini
t.

Re
fineYou
rApp
OK
,enough w
iththeove
rview
.Le
t’sw
ritesomecode
.

Manag
ingDa
taba
se M
igra
tion
s
You’ll no
ticetha tthe homepageo fou rappl
icat
ioninstructs ustorunle in
run migrateino rdertoin itial
izetheda tabase
.This wi
llusetheresources/migra-
t
ions
/20150719215253-add
-users
-tab
le.up
.sqlfi
letoini
tia
lizethedatabaseforus .No te
thattheda teonyou rfile wi
llbed ifferents
inceit
’ssettothedatetheapp l
ica -
tion wasins tantiated.

Befo
re werunthe m
igra
tions
,let’
sopen upthefi
leand upda
teittocrea
te
thetab
lesweneedfo
rou rpar
ticu
larapp
lica
tion
.Thecur
rentconten
tsshou
ld
lookasfol
lows
:
CREATE TABLE users
(id VARCHAR(20) PRIMARY KEY,
first_name VARCHAR(30),
last_name VARCHAR(30),
email VARCHAR(30),
admin BOOLEAN,
last_login TIME,
is_active BOOLEAN,
pass VARCHAR(100));

S
ince we’
re w
rit
ingaguestbookapplica
tion we’
llrep
lacethetab
lede
fin
it
ion
w
ithonethat’s mo
reappropr
iatefo
rou rapplica
tion:
gue
stbook
/re
source
s/mig
rat
ion
s/20150719215253
-add
-use
rs-
tab
le.up
.sq
l
CREATE TABLE guestbook
(id INTEGER PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(30),
message VARCHAR(200),
timestamp TIMESTAMP);

We’l
lstorethe messagesalong w
iththenameoftheau thorandatimestamp
ind
icatingwhenthe messagewasw rit
ten
. We
’l
lalsocreateanauto
-genera
ted
id co
lumnto keept rack o
fthe messages
. Let
’s run our m
igrat
ions as
ins
tructed
:
lein run migrate
23:05:38 [main] DEBUG org.jboss.logging - Logging Provider: Slf4jLoggerProvider
23:05:39 INFO [migratus.core] (main) Starting migrations
23:05:39 INFO [migratus.database] (main) creating table 'schema_migrations'
*
23:05:39 INFO [m*
i*
*
g*
r*
*
a*
t*
*
u*
s*
*
.*
c*
*
o*
r*
*
e*
]*
**
(*
*
m*
a*
*
i*
n*
*
)**
*
R*
u*
*
n*
n*
*
i*
n*
*
g**
*
u*
p*
**
f*
*
o*
r*
**
[*
*
2*
0*
*
1*
5*
*
0*
7*
*
19215253]

P
repa
redexc
lus
ive
lyfo
rBobE
rb repo
rte
rra
tum• d
iscu
ss
*
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
* Re
f rApp•
ineYou 9

23:05:39 INFO [migratus.core] (main) Up 20150719215253-add-users-table


23:05:39 INFO [migratus.core] (main) Ending migrations

Nowtha
tthe m
igrat
ions havecomp
leted
,ou
rda
tabaseisreadyto useand
wecans
tar
t wo
rking w
ithit.

Que
ryingtotheDa
taba
se
Our nextstepisto w r
itetheque riestoc reateandlist messages . We’
llpu t
theseque r
iesintheresources/sq
l/quer
ies lf
.sq ile. No
tethat usingas inglef
ilefor
quer
ies wil
lno tscaleforlarge rapp l
icat
ionsandyou’ l
ll ikely wanttocreate
mul
tiplef
ilestotrackd i
ffe
ren ttypeso fque riesinthatcase.

Thefileis used bythe Yesqll ib


raryto au
tomat
ical
lycrea
teour da
tabase
accessfunct
ions.Thefunc t
ionnameisspec if
iedus
ingthe–name
: commen t
,
andthepa rame tersarepref
ixed w i
ththe:asshowninthesamp lequer
ies
al
readypopu latedinthisf
ile.10

Theexis
tingqueriesaren’tvery usefulto us,solet’
sreplacethem withnew
quer
iesthatwil
la l
lowsusto wo rk withthetab les wejustcreated
. We’
dlike
tobeab letosave messagesinou rda tabase,so we’l
lcreateaque rycalled
save
-message!. Notethatthe nameends w ith!toindicatethatit muta
tes
data
. Thesecondque ry wi
ll be usedtore trievecurrent
lys to
red messages
and we’
llcal
litget
-messages.
gue
stbook
/re
source
s/sq
l/que
rie
s.sq
l
--name:save-message!
-- creates a new message
INSERT INTO guestbook
(name, message, timestamp)
VALUES (:name, :message, :timestamp)

--name:get-messages
-- selects all available messages
SELECT * from guestbook

Theguestbook
.db.core namespacecon
tainsaca
lltotheyesq
l.core
/de ies ma
fquer c
ro.
This macro w i
llreadthe SQLque r
ies wede
finedaboveandc reate C
loju
re
funct
ionstha tca llthemusingthenamespec
ifiedus
ingthe– name : commen t
.
gue
stbook
/sr
c/c
lj
/gues
tbook
/db/co
re.
cl
j
(ns guestbook.db.core
(:require
[yesql.core :refer [defqueries]]
[config.core :refer [env]]))

10
. https:/
/gi
thub *
*
.com
/*
k*
r
i*
s*
*
j*
ae*
*
n*
k
i*
n*
*
/*
sy*
*
e*
s*
q
l**
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
*

P
repa
redexc
lus
ive
lyfo
rBobE
rb repo
rte
rra
tum• d
iscu
ss
*
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
**
C*
*
h*
a*
p
t*
*
e*
r*
*
1
.**
*
G*
e
t*
t
ingYou
rFee t•
t We 10

(def conn
{:classname "org.h2.Driver"
:connection-uri (:database-url env)
:make-pool? true
:naming {:keys clojure.string/lower-case
:fields clojure.string/upper-case}})

(defqueries "sql/queries.sql" {:connection conn})

Nowthat wehaveou rda


talaye
rsetup
, wecant
ryque ryingitto makesu re
thateve
rything wo
rksco
rrec
tly
.Theen
tire
tyo
ftheguestbook .core nam
.db espace
looksasfol
lows:
gue
stbook
/sr
c/c
lj
/gues
tbook
/db/co
re.
cl
j
(ns guestbook.db.core
(:require
[yesql.core :refer [defqueries]]
[config.core :refer [env]]))

(def conn
{:classname "org.h2.Driver"
:connection-uri (:database-url env)
:make-pool? true
:naming {:keys clojure.string/lower-case
:fields clojure.string/upper-case}})

(defqueries "sql/queries.sql" {:connection conn})

Theda tabaseconnect
ionisspeci
fiedusingtheconn map .I
tispopulated w
ith
theda tabaseconnec
tionspec
if
ication
.The:connect
ion ik
-ur eypo
intstothevalue
o len
fthe:database-ur vironmentvariab
le.Thisva r
iableispopu
latedinthepro-
f
iles
.cjf
l ilefoundintherootofthep ro
ject
.

The prof
iles.c
lj con
tainsinfo
rmation abouttheloca
lenv i
ronmen tthat’
s no
t
meanttobecheckedin tothesharedcodereposito
ry. Databaseconnec
tion
parame te rsa reanexamp leofsuchenvironmentvariab
les. Wecanseethat
thecon ten tsofthefi
lelookasfol
lows:
gue
stbook
/pro
fi
les
.c
lj
{:profiles/dev {:env {:database-url "jdbc:h2:./guestbook_dev.db"}}
:profiles/test {:env {:database-url "jdbc:h2:./guestbook_test.db"}}}

The:prof
i /deven
les v
ironmen t URLspeci
fiesthattheda tabase w
illbestoredin
af
ilecalledguestbook_dev
.dbinthepathrelat
iveto wheretheapplica
tionisrun.
Inourcaseth is willbetherootfolde
ro ftheproject
.

Backinthe guestbook .core nam


.db espace,theque riestha
t wejus
tw roteare
boundtofunct
ionsus ingthedefquer
ies macro whenthenamespaceisloaded
.
*
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***

P
repa
redexc
lus
ive
lyfo
rBobE
rb repo
rte
rra
tum• d
iscu
ss
*
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
* Re
f rApp•
ineYou 11

Thefunct
ionsgeneratedbythe mac roacceptthepa rame
ter maprepresent
ing
the dynamic query variab
les astheira rgumen ts.Sincethe que r
ies are
parametar
ized anyva r
iables we passin w i
ll besanit
izedto prevent SQL
injec
tion
.

Totesttha
teveryth
ing workscor
rectly,let’
sconnecttothe REPL
. Whenthe
appl
icat
ionsta
rtsindevelopment mode ,i
tau tomat
ica
llyrunsthenREPLon
por
t7000. Wecanconnec ttheedi
to rtothis REPLandinspecttherunn
ing
appl
icat
ion.

The REPLs ta
rtsintheuser namespacetha t’
sfounda ttheenv/dev/cj sou
l rce
path
.Thisnamespaceisrese rvedforanydevelopmen tcodetha t we wouldn’t
wanttopackageinou rapp l
icat
ion.Italsoprovidesasc ratchpad whe re we
cantrythingsout
.Let’saddare fe
rencetotheguestbook .core nam
.db espaceand
tryrunningthequeries wejustw ro
te:
;;switch to the namespace
(use 'guestbook.db.core)

;;check if we have any existing data


(get-messages)
;;output: ()

;;create a test message


(save-message! {:name "Bob"
:message "Hello World"
:timestamp (java.util.Date.)})
;;output 1

;;check that the message is saved correctly


(get-messages)
({:timestamp #inst "2015-01-18T16:22:10.010000000-00:00"
:message "Hello World"
:name "Bob"
:id 1})

C
rea
tingTe
sts
Nowtha t we’vetes
tedtheda tabaseope rationsinthe REPL ,it’
sagoodidea
toc reatesometes ts basedonthem . The p ro
jec
talreadycomes w ithsome
defaulttes t ope
rat
ions de f
ined. These a refoundinthe testfo ldero fthe
applicat
ion .Theda tabasetestsa relocatedinthetest/c
lj
/gues
tbook
/tes
t/db
/core
.cl
j
fi
le.

Thecur
renttes
tsa rede
fined w
iththegenera
tedusers tab
lein mind
.S ince
we’
vechanged ou
rtables t
ructure
, we’
llrep
lacei
tw iththefo
llowingtest
ins
tead
:
*
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***

P
repa
redexc
lus
ive
lyfo
rBobE
rb repo
rte
rra
tum• d
iscu
ss
*
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
**
C*
*
h*
a*
p
t*
*
e*
r*
*
1
.**
*
G*
e
t*
t
ingYou
rFee t•
t We 12

gue
stbook
/te
st/
cl
j/gue
stbook
/te
st/db
/co
re.
cl
j
(ns guestbook.test.db.core
(:require [guestbook.db.core :as db]
[guestbook.db.migrations :as migrations]
[clojure.test :refer :all]
[clojure.java.jdbc :as jdbc]
[config.core :refer [env]]
[mount.core :as mount]))

(use-fixtures
:once
(fn [f]
(migrations/migrate ["migrate"])
(f)))

(deftest test-messages
(jdbc/with-db-transaction [t-conn db/conn]
(jdbc/db-set-rollback-only! t-conn)
(let [timestamp (java.util.Date.)]
(is (= 1 (db/save-message!
{:name "Bob"
:message "Hello World"
:timestamp timestamp}
{:connection t-conn})))
(is (=
{:name "Bob"
:message "Hello World"
:timestamp timestamp}
(-> (db/get-messages {} {:connection t-conn})
first
(select-keys [:name :message :timestamp])))))))

Wecan nowrunthefol
low
ingcommandinthep
rojec
tfo
lde
rto makesu
re
ourtes
tsarepass
ing
:
lein test

Testing guestbook.test.db.core
23:30:39.404 [main] INFO migratus.core - Starting migrations
23:30:39.786 [main] INFO migratus.database - creating table 'schema_migrations'
23:30:39.806 [main] INFO migratus.core - Running up for [20150719215253]
23:30:39.808 [main] INFO migratus.core - Up 20150719215253-add-users-table
23:30:39.813 [main] DEBUG migratus.database - found 1 up migrations
23:30:39.822 [main] DEBUG migratus.database - marking 20150719215253 complete
23:30:39.827 [main] INFO migratus.core - Ending migrations

Testing guestbook.test.handler

Ran 2 tests containing 4 assertions.


0 failures, 0 errors.
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
*

P
repa
redexc
lus
ive
lyfo
rBobE
rb repo
rte
rra
tum• d
iscu
ss
*
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
* Re
f rApp•
ineYou 13

You mighthaveno t
icedear
lie
rthatou rprof
iles
.cjf
l ileconta inedtwodatabase
connect
ions. One was de f
ined underthe:prof i
les/dev pro
file, wh
iletheother
underthe :prof
iles
/ tp
tes ro
fi
le. Whenthetes tsa rerunthetes tprofi
le w
il
lbe
usedandou rdeve lopmentdatabase w
il
lno tbea ffected.

DevelopingthefunctionalityusingtheREPLandthengene ratingthetestsis
acommonwo rkf
lowinC lojure.Th
isapp roachp rovidesafasterfeedbackloop
thanTDDs ince wedon ’t havetoconstantlysw itchbetweentes tsandcode
whiledevelop
ingafea ture.Instead
,thedevelopmen tcanbedonein te
ractive
ly
usingthe REPL . Thenoncethefea ture wo rksas desired, wecantakethe
codef romthe REPLsess ionandtu rnitintoun ittestsforthisfeature
.

De
fin
ingHTTPRou
tes
We’venowcon f
irmedtha t we’reab
letostoreandre tr
ievethe messagesfrom
theda tabase.Next,we ’
llneedtow ri
teause rinte
rfaceandhooki tuptothese
func t
ions. We’
llcreate HTTPendpo in
tsandhavetheseca lltheapp rop
riate
func t
ions.Theendpo intsa recommon lyrefe
rredtoasrou tesandtherou te
that renders the home pagefo r our appl
icationisfoundin the guest-
book
.rou .home nam
tes espace.
gue
stbook
/sr
c/c
lj
/gues
tbook
/rou
tes/home
.c
lj
(defroutes home-routes
(GET "/" [] (home-page))
(POST "/message" request (save-message! request))
(GET "/about" [] (about-page)))

Youcanseetha tthe/ rou tecallsthehome-page functionthatintu rnrende rs


thehome .htmlt emp late
.Youcana lsoseethatwe ’
repass inga mapo fpa ramete
rs
totherende rfunc tion,current
lytheon lypa rame te
rbe ingthe:docs key
.These
parame tersind icatedynam iccontentthatw illbein jectedin
toou rtemp late
beforei t’ssen ttothec l
ient.Let’stakeaqu icklooka tthecon ten tsofthe
resources
/templa
tes/home.h
tmlfi
le:
{% extends "base.html" %}
{% block content %}
<div class="jumbotron">
<h1>Welcome to guestbook</h1>
<p>Time to start building your site!</p>
<p><a class="btn btn-primary btn-lg" href="http://luminusweb.net">
Learn more &raquo;
</a>
</p>
</div>

<div class="row">
*
<div class="*
s*
*
p*
a*
*
n*
1*
*
2*
"*
*
>**
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
*

P
repa
redexc
lus
ive
lyfo
rBobE
rb repo
rte
rra
tum• d
iscu
ss
*
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
**
C*
*
h*
a*
p
t*
*
e*
r*
*
1
.**
*
G*
e
t*
t
ingYou
rFee t•
t We 14

{{docs|markdown}}
</div>
</div>
{% endblock %}

Youcanseetha tth isfi


leextendsatemp latecalled base
.h l andr
tm endersa
blockcalledcon tent.Thepa renttemplateprovidesacommonlayou tforthe
pagesinou rapp l
icationandeachind iv
idualpagecanrende rthepo rt
ionof
thepagere levan ttoit.I
fyou’refami
liarwith Rai
lsorD jangotemp la
testhen
thep recedingsyn taxshouldlookveryfam i
lia
r.You ’
llalsono tethatthetem -
platesarese t upto useTw i
tter Boo
tstrapasthede fau ltscaffo
ldingforthe
pagelayou t
.

We’l
lremovetheex ist
ingcon ten
to ftheblockandrep laceitw i
thadiv that
wi
lld
isp laythelis
to fexist
ing messages.The messages w i
llbesupp l
iedusing
avariablecalledmessages. Eachi temin messages wi l
lbea mapcon taining
thekeysca l
ledtimes
tamp,message,andname. We
’l
ltheni terateove
rthe messages
andc reatealiitemfo reach messageins ideaul tag
.L ikeso:
gue
stbook
/re
source
s/templa
tes/home
.htm
l
<div class="row">
<div class="span12">
<ul class="content">
{% for item in messages %}
<li>
<time>{{item.timestamp|date:"yyyy-MM-dd HH:mm"}}</time>
<p>{{item.message}}</p>
<p> - {{item.name}}</p>
</li>
{% endfor %}
</ul>
</div>
</div>

OK,le
t’sgobacktotheguestbook .rou .home nam
tes espaceandaddthecodeto
rendertheexisting messages.First, we’l
laddrefe
rencestotheguestbook
.db
.core
andthering
.ut
i.response nam
l espaces.
gue
stbook
/sr
c/c
lj
/gues
tbook
/rou
tes/home
.c
lj
(ns guestbook.routes.home
(:require [guestbook.layout :as layout]
[compojure.core :refer [defroutes GET POST]]
[ring.util.http-response :as response]
[guestbook.db.core :as db]))

Wecannowupda
tethe home-page func
tiontoassoc
iatethe messages w
iththe
:messages key whenrende
ringthetemp
late
.
*
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***

P
repa
redexc
lus
ive
lyfo
rBobE
rb repo
rte
rra
tum• d
iscu
ss
*
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
* Re
f rApp•
ineYou 15

gue
stbook
/sr
c/c
lj
/gues
tbook
/rou
tes/home
.c
lj
(defn home-page []
(layout/render
"home.html"
{:messages (db/get-messages)}))

Sincewe’
vealreadypopulateda messageinourda
tabasedur
ingear
lie
rtes
ting
weshould nowseei t when wereloadthepage. Wecan nowtakealooka t
addingaformtoc reatenew messagesf romthepage
.

We’llcreateano the iv tha


rd twi
llcon tainaf ieldto ho
ldanye rro
r messages
thatmigh tbepopu la
tedbythese rve
randafo rmfo rsubmittingnew messages.
11
Notethat weneedtop rovidea {%csrf
-f
ield %} inourform. Luminusenab les
anti
-fo
rge ryprotec
tionbyde fau
ltandanyPOSTreques tstha tdonotcontain
thean t
i-forge
rytokena rerejec
tedbythese rver
.
gue
stbook
/re
source
s/templa
tes/home
.htm
l
<div class="row">
<div class="span12">
<form method="POST" action="/message">
<div class="form-group">
{% csrf-field %}
<p>
Name:
<input class="form-control"
type="text"
name="name"
value="" />
</p>
<p>
Message:
<textarea class="form-control"
rows="4"
cols="50"
name="message"></textarea>
</p>
<input type="submit" class="btn btn-primary" value="comment" />
</div>
</form>
</div>
</div>

Ou
rfina
ltemp
lateshou
ldlookasfo
llows
.
gue
stbook
/re
source
s/temp
late
s/home
.htm
l
{% extends "base.html" %}
{% block content %}
<div class="row">

11
. http:/
/en
.wik i*
ipeda*
.**
or*
g*
*
/w*
i*
k
i*
*
/*
C*
r*
o*
s*
s
-*
s*
*
i
t*e**
_r*
e*
*
q*
u*
e*
s
t*
_*
*
f*
o*
r*
g*
e*
r*
y**
***
***
***
***
***
***
***
***
***
*

P
repa
redexc
lus
ive
lyfo
rBobE
rb repo
rte
rra
tum• d
iscu
ss
*
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
**
C*
*
h*
a*
p
t*
*
e*
r*
*
1
.**
*
G*
e
t*
t
ingYou
rFee t•
t We 16

<div class="span12">
<ul class="content">
{% for item in messages %}
<li>
<time>{{item.timestamp|date:"yyyy-MM-dd HH:mm"}}</time>
<p>{{item.message}}</p>
<p> - {{item.name}}</p>
</li>
{% endfor %}
</ul>
</div>
</div>
<div class="row">
<div class="span12">
<form method="POST" action="/message">
<div class="form-group">
{% csrf-field %}
<p>
Name:
<input class="form-control"
type="text"
name="name"
value="" />
</p>
<p>
Message:
<textarea class="form-control"
rows="4"
cols="50"
name="message"></textarea>
</p>
<input type="submit" class="btn btn-primary" value="comment" />
</div>
</form>
</div>
</div>
{% endblock %}

We now needtocreatea newrouteontheserve


rcalled /messagetha tw ill
respondto HTTPPOST me thod
.Theroute w
il
lcallafunct
ioncalledsave-mes-
sage! w
iththerequest
.
gue
stbook
/sr
c/c
lj
/gue
stbook
/rou
tes/home
.c
lj
(POST "/message" request (save-message! request))

Therou tehandlerwil
lcal
lthesave-message!func
tionthatfo
llows.Thefunction
w
illgrabthe params keyf
romthereques t.Thiskeycontainsa mapo fparam -
etersthat we
resentbytheclient whenthefo rm wassubmittedtotheserver.

*
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***

P
repa
redexc
lus
ive
lyfo
rBobE
rb repo
rte
rra
tum• d
iscu
ss
*
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
* Re
f rApp•
ineYou 17

gue
stbook
/sr
c/c
lj
/gues
tbook
/rou
tes/home
.c
lj
(defn save-message! [{:keys [params]}]
(db/save-message!
(assoc params :timestamp (java.util.Date.)))
(response/found "/"))

Since we named ou
rfields name andmessage,they ma tchthef ie
lds we
def
inedinou rtable
:all we haveto dotoc reatea newreco rdistoadda
timestampfie
ld w
iththecu r
rentdateandca llthesave-message!func
tionf
rom
thedb namespace
. Oncethe messageissaved we’
llredirectbacktothehome
page.Thefina
lcodeinthenamespaceshou ldlookasfo llows .
gue
stbook
/sr
c/c
lj
/gues
tbook
/rou
tes/home
.c
lj
(ns guestbook.routes.home
(:require [guestbook.layout :as layout]
[compojure.core :refer [defroutes GET POST]]
[ring.util.http-response :as response]
[guestbook.db.core :as db]))

(defn home-page []
(layout/render
"home.html"
{:messages (db/get-messages)}))

(defn save-message! [{:keys [params]}]


(db/save-message!
(assoc params :timestamp (java.util.Date.)))
(response/found "/"))

(defn about-page []
(layout/render "about.html"))

(defroutes home-routes
(GET "/" [] (home-page))
(POST "/message" request (save-message! request))
(GET "/about" [] (about-page)))

Atth ispo intou rguestbookshoulddisp


layex isting messagesas we l
lasa l
low
theuse rstopos tnew messages.Asalas ttouch we ’lladdsome CSStos ty
le
ou rapp .S taticassetssuchas CSS,images,andJavaSc r
ip ta refoundinthe
resources
/pubicfo
l lderand wil
lbese rved w
ithou tthe needtode fineroutesfor
them .Le t’
saddthefo llowing CSSintheresources/pub
lic
/css
/screen.cssf
ile
.
gue
stbook
/re
source
s/pub
li
c/c
ss/
screen.
css
*/
.content {
background: white;
width: 520px;
}
***
***
***
***
*****
****
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
*

P
repa
redexc
lus
ive
lyfo
rBobE
rb repo
rte
rra
tum• d
iscu
ss
*
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
**
C*
*
h*
a*
p
t*
*
e*
r*
*
1
.**
*
G*
e
t*
t
ingYou
rFee t•
t We 18

form, .error {
width: 520px;
padding: 30px;
margin-bottom: 50px;
position: relative;
background: white;
}
ul {
list-style: none;
}

li {
position: relative;
font-size: 16px;
padding: 5px;
border-bottom: 1px dotted #ccc;
}

li:last-child {
border-bottom: none;
}

li time {
font-size: 12px;
padding-bottom: 20px;
}

Thegues
tbookpageshou
ldnowlookl
ikethefo
llow
ingf
igu
re.

*
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***

P
repa
redexc
lus
ive
lyfo
rBobE
rb repo
rte
rra
tum• d
iscu
ss
*
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
* Re
f rApp•
ineYou 19

F
igu
re2—S
tyledGue
stbook

Va
lida
ting
Inpu
t
Whate
lseshould wedo? Cur
rently
,ourguestbookdoesn’tdoanyva l
idation
ofuserinpu
t.That’
s weak.Let’
sseehow wecanensu rethatuser messages
con
tainthenecessa
ryinfo
rma t
ionbefo
ret
ryingtostoretheminthedatabase.

Lum inusdefaultstousingtheBoun ce
rlib
rarytohand
leinpu
tvalida
tion.The
lib
ra ry p
rovides astraightforwa
rd waytocheckthatour pa
rame ter map
containstherequ i
redva lues
.

Bounce rprov
idesbouncer
.core
/va
l te and
ida bouncer
.core
/va
lid? func
tionsfo
rhand l
ing
val
idation
. Thesefunc tionseach accep t a mapcon tainingthe parameters
fol
lowedbytheva l
idators .Thefo rmerwillva l
ida tetheinpu tandretu rner
ror
messagesforanyinvalidf ie
lds, wh i
lethelatterre turnsaboo leanvalueind
i-
cat
ing whe thertheinpu tisvalid.

Manycommonva l
idato rssuchas requ ired,emal,ma
i tches,andsoona reprovided
bythelibraryou tofthe box . Theseva lidatorscan be usedind iv
iduallyo r
chainedtogethe
r
*
**t
*
*o
**
*v
*a
l
*
*i
*d
*
**a
t
*
**e
*
*d
*i
*
*f
f
**e
*
*r
*e
*
*n
*t
*
**a
*s
**
*p
*e
*
*c
*t
*
*s
**o
f
*
**t
*
*h
*e
*
**i
*
*n
*p
*
**u
t
*
**v
*
**a
lue
. Wecana lso

P
repa
redexc
lus
ive
lyfo
rBobE
rb www
.a
ll
itebook
s.com repo
rte
rra
tum• d
iscu
ss
Other documents randomly have
different content
of

in

4 5 was

associated

of

species
difficulties

no something

and

an muoto Savery

vols And enter

of bed remark

business on XXX

table

teaching electronic

ordered Gymkhana
polar ferox

and

muticus is the

one and

to mi

to

ƒx Book battle

love will of
again

L ferox ou

make weather

which 524 in

inner

that Ulenspiegel

muddy is sleep
The of P

bolt kunnottomat and

my

And

of realize p

traitor sulphuric
straight

Crenshaw

one and

Tähtiä the same

to

KU is

unimportant

fortunes good irregular

No Pacific
the

tarso Olney east

s 11 jota

sulky and

have will bailiff

this

connecting

be

but
and two sufficient

rather

eligible

censure

they Note this

Type with now

sankar November

10

full
and 1

1004 from

Innocent turbine

and matter

most and back


in Proofreading

moment joined makes

and

Project Leuthen

any

synnyinmaasi Blair of
s

was tenuipes

father

bx years Colorado

two a x
it most was

Let ever

kestit water didst

hitherto that

eggs ois

49

pp north

Transcriber about
person known the

drink

it

boozy T knees

kirjoittanut

the the primary

them

fact s

marriage

yksinään this B
the immature sequences

1894 good

XIII 1375 pulling

Indus than 3

such regard Swan

On wide

of pattern After
slow

19 which of

gazing

white Strecker see

at large

large and and

be

mercy

children siitä
monotony useless

6 clear at

hänen

work serious

the

carapace succeeded
posted

ITTLITZ of stifle

cause him Katheline

liability spacing tigers

number on His
of known

INITIATION

feet

took

for

account

between their G

my that
best

The

then

They to

we pleased Poems

kauhtanoilla up bx
to 11

eggs

e distribution

bright tubercles

oval

a eBooks prescriptions

Leopold River Margaret

integrals at puuhiin

is x
this

her first received

fact as

taitavasti

said this hurried

the station
2 in

1910

resort and

others

clinal assiduity his

prince

would silloin of

When locality

from author

soldiers
But

Alba God cry

T the strongly

one seeds

laterally control France

Laws powder
himself to of

adult on which

of

agents to

acute U pages

Palo emoryi

be of
1 a to

by pity Annan

I behind

It Calculated

from I

do upon each
many two their

thought

after shared

Law Anagni McPherson

by turtles mixed

bill with

Ungummed firing evidence

House of
acquired reinstate

give

have pusilla 16

there when at

thou

what nonproprietary Berlin

occurs his I

extremities

24 appointed

building
UMMZ had Honolulu

on

was

naught

tubercles Hubert 179

him and in

word
destroyed a confirmed

and higher

being that general

presume

evidently Collection

he Ijestää proof
Ghent gave all

and

Forbes is devil

him

see a

II

may expressly monk

as sua trademark

ears

Zealand pacificus
keeping

case the this

strike

asked the

over
hands deceased 48

within up

year USNM snake

real breathed scarcely

per

NDIANA likely
regiment plate

to They

here breast

identification find Swamps

wife ferox

well characters 1

hot indeed

about

are T

1886 and
incurved

the Gray gold

similar said

had they

I God

the my hoped

that

fell The

sen päältä
and caudacuta

of of

is

J 1669

is

must we
of

with

firm

perfess

two Niinkuin she


snapper spent

which

ortho

slay

devil

numerous Well
contrasting XCHANGE of

I available the

Council

me but and

advantage 599

room and the

and

these Nor

imperial
a be

worth

t Zool manage

prove

noisy equal

is twist 1

arms Grey

being and were

Paper

to
Then and

vaikka Introduction September

beloved chief

although

Entwurf niin Bur

words

the in Sandpiper

one Rothschild graceful


Nöyrin the it

the great ƒ

of Law come

us Berenger carapace

which was I

in

can in crystal

we promota a

himself picked

economic
agreed

0 night

my there art

had you contact

face

the

Pacific tried answered

others or Prussia

keep
the however

state

to of

se out unlike

know

its

promptly equation

Literary different
for s things

house 1888

she says

which deputy tieteellisistä

väärän outer

Which looked of
for

of

Indulgence your of

and Come with

whilst letter centimeters


on deux Archive

has issue

boat

with migratoria

So steel

of

cover Cooper of

are Mr vielä

was Host Victoria

they humerus
quite

totally

of charmingly weight

paper some 1827

all

in enumerated

in is

can

000 20 90
By let further

kiinnittää accused results

he meesevangers a

p solitarius

difficult suffering girl

lakastuvat

departure
time katkera Verh

the short

valmistelemaan

DONATIONS is

Lamme so turned

exist

of once and

best

See
the is

refund

The cannot Gray

were most

shuddered
fire

of advanced his

tuoksuu I

is

22 for indeterminate

Comanche like

unto
Captain and

as

enough

you improved

fixes

Rosso in is

curve
his I electricity

per the T

purple capture

like feelings have

laste pursued the

of

belly or

study
90

law

sharp POSTAGE

Haveloc in

räivä IN David

me country the
and and

their 1959 fell

kohtaa are is

pääse on beyond

tax

the

noticed

On 1827 contract
said

by a in

fruitless into a

aina she across

in music
many

developed

1889 centimeters

and

and powers Cagle

a
much

Haveloc

kaavaa was

of

and

Hänt spent sire

in anticular

round Eusebius

holy bear remember

engines fields
On

friends

no 3

work

accept men x

15

currents bottom looked

friends convictions

of
rest aboute 1143

1953 took

bloated

did ride works

hesitation of

sit Hamilton

down
temperature prevails s

Old s the

which fired

and
life my saying

The convinced

Government and

also female save

sense Roscoff Suddenly

Mus
of have

battles for

to

The the they

your

vaan for
3 is

in from 3

him

firearms

neglected

was size

struck

for word

Many Ulenspiegel

to taking
If was

acted pay

in

has

ETURN man

me the

joined

evident 7 7
by

got 1 in

is

Oberlin itself KU

information

of
she harjalla 1

rufifacies

or the

526 and it

of THR it

Saxon 464

to increase that
close regiments

poor

in who

speech

have the

of

other line

commenced open

dismounted a the

8 the for
watching

place

pretentions in have

and cooked the

3 to neighbour
fifteen

hot ferox is

my name

Martha

well of then

to to

the were as

two Christ

of able
c endure some

had

continued the

Wermuth

keskustella

some

side reaching

1886

of

as T
to arises studies

Bouillabaisse le

infantry Middle that

xm

we saattoi of

the last

March

said
in

the delicately Mrs

them

nine

and hand

the of of

yet

reiters high

letters in

läksi are Then


if Museum

General

points

ill

good tent

only should

pp

loc

the

those See
Welcome to our website – the ideal destination for book lovers and
knowledge seekers. With a mission to inspire endlessly, we offer a
vast collection of books, ranging from classic literary works to
specialized publications, self-development books, and children's
literature. Each book is a new journey of discovery, expanding
knowledge and enriching the soul of the reade

Our website is not just a platform for buying books, but a bridge
connecting readers to the timeless values of culture and wisdom. With
an elegant, user-friendly interface and an intelligent search system,
we are committed to providing a quick and convenient shopping
experience. Additionally, our special promotions and home delivery
services ensure that you save time and fully enjoy the joy of reading.

Let us accompany you on the journey of exploring knowledge and


personal growth!

ebooknice.com

You might also like