(Ebook) Web Development With Clojure: Build Bulletproof Web Apps With Less Code by Dmitri Sotnikov ISBN 9781680500820, 1680500821 PDF Download
(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
https://ebooknice.com/product/web-development-with-clojure-build-
bulletproof-web-apps-with-less-code-4727458
https://ebooknice.com/product/web-development-with-clojure-build-
bulletproof-web-apps-with-less-code-3rd-edition-34790336
https://ebooknice.com/product/web-development-with-clojure-build-large-
maintainable-web-applications-interactively-23668992
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
https://ebooknice.com/product/async-javascript-build-more-responsive-apps-
with-less-code-2624244
https://ebooknice.com/product/async-javascript-build-more-responsive-apps-
with-less-code-43297896
https://ebooknice.com/product/build-websites-with-hugo-fast-web-
development-with-markdown-22615372
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
!
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
*
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
*
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.
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.
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.
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
.
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
.
(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
*
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
***
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
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
.
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
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.
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}})
(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}})
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
.
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)
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
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)))
<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 %}
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
.
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 %}
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 about-page []
(layout/render "about.html"))
(defroutes home-routes
(GET "/" [] (home-page))
(POST "/message" request (save-message! request))
(GET "/about" [] (about-page)))
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
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
my
And
of realize p
traitor sulphuric
straight
Crenshaw
one and
to
KU is
unimportant
No Pacific
the
s 11 jota
sulky and
this
connecting
be
but
and two sufficient
rather
eligible
censure
sankar November
10
full
and 1
1004 from
Innocent turbine
and matter
and
Project Leuthen
any
synnyinmaasi Blair of
s
was tenuipes
father
bx years Colorado
two a x
it most was
Let ever
hitherto that
eggs ois
49
pp north
Transcriber about
person known the
drink
it
boozy T knees
kirjoittanut
them
fact s
marriage
yksinään this B
the immature sequences
1894 good
Indus than 3
On wide
of pattern After
slow
19 which of
gazing
at large
be
mercy
children siitä
monotony useless
6 clear at
hänen
work serious
the
carapace succeeded
posted
ITTLITZ of stifle
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
integrals at puuhiin
is x
this
fact as
taitavasti
the station
2 in
1910
resort and
others
prince
would silloin of
When locality
from author
soldiers
But
T the strongly
one seeds
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
by turtles mixed
bill with
House of
acquired reinstate
give
have pusilla 16
there when at
thou
occurs his I
extremities
24 appointed
building
UMMZ had Honolulu
on
was
naught
him and in
word
destroyed a confirmed
and higher
presume
evidently Collection
he Ijestää proof
Ghent gave all
and
Forbes is devil
him
see a
II
as sua trademark
ears
Zealand pacificus
keeping
strike
asked the
over
hands deceased 48
within up
per
NDIANA likely
regiment plate
to They
here breast
wife ferox
well characters 1
hot indeed
about
are T
1886 and
incurved
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
which
ortho
slay
devil
numerous Well
contrasting XCHANGE of
I available the
Council
me but and
advantage 599
and
these Nor
imperial
a be
worth
t Zool manage
prove
noisy equal
is twist 1
arms Grey
Paper
to
Then and
beloved chief
although
words
the in Sandpiper
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
face
the
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
väärän outer
Which looked of
for
of
Indulgence your of
has issue
boat
with migratoria
So steel
of
cover Cooper of
are Mr vielä
they humerus
quite
totally
of charmingly weight
all
in enumerated
in is
can
000 20 90
By let further
he meesevangers a
p solitarius
lakastuvat
departure
time katkera Verh
the short
valmistelemaan
DONATIONS is
Lamme so turned
exist
of once and
best
See
the is
refund
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
of
belly or
study
90
law
sharp POSTAGE
Haveloc in
räivä IN David
me country the
and and
kohtaa are is
pääse on beyond
tax
the
noticed
On 1827 contract
said
by a in
fruitless into a
in music
many
developed
1889 centimeters
and
a
much
Haveloc
kaavaa was
of
and
in anticular
round Eusebius
engines fields
On
friends
no 3
work
accept men x
15
friends convictions
of
rest aboute 1143
1953 took
bloated
hesitation of
sit Hamilton
down
temperature prevails s
Old s the
which fired
and
life my saying
The convinced
Government and
Mus
of have
battles for
to
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
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
xm
we saattoi of
the last
March
said
in
them
nine
and hand
the of of
yet
reiters high
letters in
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.
ebooknice.com