You are on page 1of 19

THEDEADSIMPLESTEPBYSTEPGUIDEFORFRONT

ENDDEVELOPERSTOGETTINGUPANDRUNNING
WITHNODE.JS,EXPRESS,JADE,ANDMONGODB
SETUPTHEFULLSTACKANDHAVEAWEBPAGERUNNINGIN30
MINUTES.MAKEITTALKTOYOURDBINANOTHER30.
ByChristopherBuecheler
LASTUPDATED:September2nd,2015
ThistutorialusesNode.jsv0.12andwillnotworkproperlywitholderversionsonsomesystems.

Youcanfind/forktheentiresampleprojectonGitHub
Hey!ThisandallmyothertutorialswillsoonbemovingtoanewhomeatCloseBrace,asitefor
JavaScriptdevelopers.Youshouldtotallyclickthatlinkrightnow,andsignuptobealertedwhenthe
sitegoeslive.

INTRODUCTION
Thereareapproximatelyonehundredmilliontutorialsonthewebforgettinga"Hello,World!"app
runningwithNode.js.Thisisgreat!It'sespeciallygreatifyourgoalistogreettheworldandthengive
uponyourwebcareerandgospendtherestofyourlifeas,like,ajockeyorsomething.Thatdoesn't
reallydescribemostofus,sowegolookingformoretutorials.
Inmyexperience,the"nextlevel"tutorialsoutthereseemabout30levelsfurtheralong.Wegofrom
"Hello,World!"tobuildingoutanentirebloggingsystemwithcomments.Whichisalsogreat,butalot
oftimesthosetutorialsassumethereaderhasdoneawholebunchofintermediatefiddling,andthey
oftendropabunchofbigfunctionsonyouallatonce.Itendtolearnbestbymakinglotsofsmaller,
intermediatesteps,andIdon'tthinkI'mtheonlyone.
I'mnottheonlyone,right?
Well,goodnews,everyone!I'vedonethefiddlingandreadabunchoftutorialsandshoutedatmy
commandpromptuntilthingsfinallyworked.IhaveawebprojectupandrunningwhichusesNode.JS,
theExpressframework,theJadeHTMLpreprocessor,andMongoDBfordata.Icanreadtoandwrite
fromtheDB.Fromthere,thesky'sthelimit.
Here'sthedeal:I'mgoingtoshowyouhowtogetallofthisstuffsetup.I'llbeassumingthatyou'rea
frontenddeveloperwhoknowsHTML5/CSS3/JavaScriptwellenoughthatIdon'thavetoexplainthose.
Ifthat'syou,thenthisshouldbeasolidprimer.
Yourappwilllookpretty,itwillconnecttoaDB,it'llgetsomeresults,andit'lldostuffwiththose
results.Thenforkickswe'llalsomakeitsavedatatotheDB.Throughitall,Iwillexplainwhatthecode

eveninstalled,toaDBdrivenwebappwritteninalanguageyoufullyunderstand,andthefoundation
necessarytobuildadditionalfunctionalityintoyourapp.Andwe'lldoitinabout60minutesof
installationandcodingtime.Isthatawesome?Isubmitthatitis.
Let'sgo.

PARTI15MINUTESOFINSTALLING
Ifyou'rereallystartingfromscratch,thengettingeverythingupandrunningtakesalittlebitoftime.
Noneofitisdifficult.IrunWindows8onmymainmachine,soit'llbeslightlydifferentforthoseona
MacorUbuntuorother*nixsystem,butit'sprincipallythesamethinginallcases.
STEP1INSTALLNODE.JS
Thisisreallyeasy.HittheNode.jswebsiteandclickthebiggreenInstallbutton.It'lldetectyourOSand
giveyoutheappropriateinstaller(ifforsomereasonitdoesn't,clickthedownloadsbuttonandgrabthe
oneyouneed).Runtheinstaller.That'sit,youhaveinstalledNode.jsand,equallyimportant,NPM
NodePackageManagerwhichletsyouaddallkindsofgreatstufftoNodequicklyandeasily.
Openacommandprompt
cdtothedirectoryinwhichyouwishtokeepyourtestapps
(forthepurposesofthistutorial,C:\node).
STEP2INSTALLEXPRESSGENERATOR
NowthatwehaveNoderunning,weneedtherestofthestuffwe'regoingtoactuallyusetocreatea
workingwebsite.Todothatwe'regoingtoinstallExpress,whichisaframeworkthattakesNodefroma
barebonesapplicationandturnsitintosomethingthatbehavesmorelikethewebserverswe'reallused
toworkingwith(andactuallyquiteabitmorethanthat).WeneedtostartwithExpressGenerator,
whichisactuallydifferentthanExpressitself...it'sascaffoldingappthatcreatesaskeletonforexpress
drivensites.Inyourcommandprompt,typethefollowing:
COMMANDC:\NODE>
C:\node>npminstallgexpressgenerator

Thegeneratorshouldautoinstall,andsinceit(likeallpackagesinstalledwithg)livesinyourmaster
NPMinstallationdirectory,itshouldalreadybeavailableinyoursystempath.Solet'suseourgenerator
tocreatethescaffoldingforawebsite.
STEP3CREATEANEXPRESSPROJECT
We'regoingtouseExpressandJade,butnottheStylusCSSpreprocessor(whichpeopleoftenusein
thisstack).We'rejustgoingtousestraightCSSforrightnow.WehavetouseJadeoranother
templatingenginetogainaccesstoourNode/Expressbaseddata.Jade'snothardtolearnifyou
alreadyknowHTML,justrememberthatyoureallyhavetopayattentiontoindentationorthingswillgo
badlywrong.IfyouwantatemplatingenginewithtrueHTMLsyntax,youcoulduseEJSinstead(note:
IcannotprovidesupportforthistutorialifyouchoosetouseanythingotherthanJade).
Aquicknoteonindentation:everythingisthistutorialhasbeennormalizedto4spacetabs,evencode

thatwasautogeneratedwith2spacetabs.Ifyouwanttousetwoorthreespaces,oractualtabs
(whichisusuallymypreference),that'sjustfinebyme.But,again,YOURINDENTATIONMUSTBE
CONSISTENTorJadewillthrowerrors.Notjust"alltabs"or"allspaces"butyoumustbevery,very
carefultomakesurethateverythingisindentedtheexactrightamount.Forexample,inJade,the
following:
body
h1
ul
li

...isVERYdifferentfrom:
body
h1
ul
li

(thatsecondpieceofcodewouldnesttheULinsideoftheH1...whichyouobviouslydon'twant).
Anyway,stillinc:\nodeorwhereveryou'restoringyournodeapps,typethis:
COMMANDC:\NODE\
C:\node>expressnodetest1

Hitenterandwatchitgo.You'llseesomethinglikethis:
COMMANDC:\NODE\
C:\node>expressnodetest1
create:nodetest1
create:nodetest1/package.json
create:nodetest1/app.js
create:nodetest1/public
create:nodetest1/public/javascripts
create:nodetest1/public/images
create:nodetest1/public/stylesheets
create:nodetest1/public/stylesheets/style.css
create:nodetest1/routes
create:nodetest1/routes/index.js
create:nodetest1/routes/users.js
create:nodetest1/views
create:nodetest1/views/index.jade
create:nodetest1/views/layout.jade
create:nodetest1/views/error.jade
create:nodetest1/bin
create:nodetest1/bin/www
installdependencies:
>cdnodetest1&&npminstall
runtheapp:
>SETDEBUG=nodetest1b:*&npmstart

STEP4EDITDEPENDENCIES
OK,nowwehavesomebasicstructureinthere,butwe'renotquitedone.You'llnotethattheexpress
generatorroutinecreatedafilecalledpackage.jsoninyournodetest1directory.Openthisupinatext

editorandit'lllooklikethis:
C:\NODE\NODETEST1\PACKAGE.JSON
{
"name":"nodetest1",
"version":"0.0.0",
"private":true,
"scripts":{
"start":"node./bin/www"
},
"dependencies":{
"bodyparser":"~1.12.4",
"cookieparser":"~1.3.5",
"debug":"~2.2.0",
"express":"~4.12.4",
"jade":"~1.9.2",
"morgan":"~1.5.3",
"servefavicon":"~2.2.1"
}
}

ThisisabasicJSONfiledescribingourappanditsdependencies.Weneedtoaddafewthingstoit.
Specifically,callsforMongoDBandMonk.Let'smakeourdependenciesobjectlooklikethis:
"dependencies":{
"bodyparser":"~1.12.4",
"cookieparser":"~1.3.5",
"debug":"~2.2.0",
"express":"~4.12.4",
"jade":"~1.9.2",
"morgan":"~1.5.3",
"servefavicon":"~2.2.1",
"mongodb":"^1.4.4",
"monk":"^1.0.1"
}

Notethatcommaattheendoftheservfaviconline.Omitit,andyouwon'tbeabletoinstall!

ImportantNote:thistutorialisabitoutofdateatthemoment.Itisessentialthatyouuse
thisolderversionofthemongodbmodule(1.4.4)ormonkwillnotworkandyourappwill
break.IwillbedoingafullupdateassoonasIcan,butthisshouldkeepyourunningfornow.

STEP5INSTALLDEPENDENCIES
Nowwe'vedefinedourdependenciesandwe'rereadytogo.Notethattheversionnumbersforthose
twomodulesarecurrentasofthelatestupdate,butnewversionsofNPMmodulesarefrequentlyrolled
out.Theseversionsareproventoworkwiththistutorialifyougowiththelatestversions,I'mafraid
you'reonyourown.
Returntoyourcommandprompt,cdtoyournodetest1directory,andtypethis:
COMMANDC:\NODE\NODETEST1\
C:\node\nodetest1>npminstall

It'sgoingtoprintoutatonofstuff.That'sbecauseit'sreadingtheJSONfilewejusteditedand
installingallthestufflistedinthedependenciesobject(yes,includingExpressweinstalledthe
generatorglobally,butwestillhavetoinstalltheactualmoduleinsidethisoneparticularproject).Once
NPMhasrunitscourse,youshouldhaveanode_modulesdirectorywhichcontainsallofour
dependenciesforthistutorial.
Younowhaveafullyfunctioningappreadyandwaitingtorun.Beforewedothat,though,weneedto
doonequickthingtoprepareforsettingupourdatabaselater.Stillinyournodetest1directory,type
this:
COMMANDC:\NODE\NODETEST1\
C:\node\nodetest1>mkdirdata

That'swherewe'reeventuallygoingtostoreourMongoDBdata.Ifthatdirectorydoesn'texist,the
databaseserverwillchokewhenwegotorunitlater.We'renotdoinganythingwithitrightnow,
though,solet'stestoutourwebserver!Typethefollowing:
COMMANDC:\NODE\NODTEST1\
C:\node\nodetest1>npmstart

Note:inpreviousversions,youused"nodeapp.js"thishasbeendeprecatedinfavorofaskeletal
buildsystem.Forthepurposesofthistutorial,thatdoesn'treallymatter,sincewe'renotworyingabout
building.Forourpurposes,using"npmstart"isessentiallyidenticaltopreviousversionsofthistutorial.
Anyway,typethatandhitenter.You'llgetthis:
NODECONSOLE
>applicationname@0.0.1startD:\sites\node\nodetest1
>node./bin/www

Everythingworking?Awesome!Openabrowserandheadforhttp://localhost:3000whereyouwill
seeawelcometoExpresspage.

YouarenowrunningyourownNodeJSwebserver,withtheExpressengineandJadeHTML
preprocessorinstalled.Notsotough,huh?

PART2OK,FINE,LET'SDO"HELLO,WORLD!"

FireupyourfavoritetexteditororIDE.IlikeSublimeTextalot.Pointitatyournodetest1directoryand
openapp.js.Thisiskindoftheheartofyour,well,app.Notabigsurprisethere.Here'sabreakdownof
whatyou'regoingtosee:
C:\NODE\NODETEST1\APP.JS
varexpress=require('express');
varpath=require('path');
varfavicon=require('servefavicon');
varlogger=require('morgan');
varcookieParser=require('cookieparser');
varbodyParser=require('bodyparser');
varroutes=require('./routes/index');
varusers=require('./routes/users');

ThiscreatesabunchofbasicJavaScriptvariablesandtiesthemtocertainpackages,dependencies,
nodefunctionality,androutes.Routesarekindoflikeacombinationofmodelsandcontrollersinthis
setuptheydirecttrafficandalsocontainsomeprogramminglogic(youcanestablishamoretraditional
MVCarchitecturewithExpressifyoulike.That'soutsideofthescopeofthisarticle).Backwhenweset
upthisproject,Expresscreatedallofthisstuffforus.We'regoingtototallyignoretheuserroutefor
nowandjustworkinthetoplevelroute(controlledbyc:\node\nodetest1\routes\index.js).
C:\NODE\NODETEST1\APP.JS
varapp=express();

Thisone'simportant.ItinstantiatesExpressandassignsourappvariabletoit.Thenextsectionuses
thisvariabletoconfigureabunchofExpressstuff.
C:\NODE\NODETEST1\APP.JS
//viewenginesetup
app.set('views',path.join(__dirname,'views'));
app.set('viewengine','jade');
//uncommentafterplacingyourfaviconin/public
//app.use(favicon(__dirname+'/public/favicon.ico'));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended:false}));
app.use(cookieParser());
app.use(express.static(path.join(__dirname,'public')));
app.use('/',routes);
app.use('/users',users);

Thistellstheappwheretofinditsviews,whatenginetousetorenderthoseviews(Jade),andcallsa
fewmethodstogetthingsupandrunning.NotealsothatthefinallineistellingExpresstoservestatic
objectsfromthe/public/dir,buttomakethemactuallyseemlikethey'recomingfromthetoplevel(it
alsodoesthiswiththeviewsdirectory).Forexample,theimagesdirectoryis
c:\node\nodetest1\public\imagesbutitisaccessedathttp://localhost:3000/images
C:\NODE\NODETEST1\APP.JS
///catch404andforwardingtoerrorhandler
app.use(function(req,res,next){

next(err);
});
///errorhandlers
//developmenterrorhandler
//willprintstacktrace
if(app.get('env')==='development'){
app.use(function(err,req,res,next){
res.status(err.status||500);
res.render('error',{
message:err.message,
error:err
});
});
}
//productionerrorhandler
//nostacktracesleakedtouser
app.use(function(err,req,res,next){
res.status(err.status||500);
res.render('error',{
message:err.message,
error:{}
});
});

Theseareerrorhandlersfordevelopmentandproduction(and404's).We'renotreallyworryingabout
thedifferentbetweenthosetworightnow,butbasicallyifyourappisindevelopmentmode,yourerrors
willgiveyoumoreinformation.Obviouslyyoudon'twanttoprintastacktraceoutonaproductionsite
thatanyoneonthewebcansee.
C:\NODE\NODETEST1\APP.JS
module.exports=app;

AcorepartofNodeisthatbasicallyallmodulesexportanobjectwhichcaneasilybecalledelsewherein
thecode.Ourmasterappexportsitsappobject.
Nowthen,let'smakestuff.We'renotgoingtojuststick"Hello,World!"onourindexpage.Instead
we'regoingtousethisasanopportunitytolearnabitmoreaboutroutesandtotakealookathow
Jadeworksforputtingpagestogether.
We'regoingtostartbyaddinganewapp.usedirectivetoapp.js.Findthesectionthatlookslikethis:
C:\NODE\NODETEST1\APP.JS
app.use('/',routes);
app.use('/users',users);

ThisdirectivesaretellingExpresswhatroutefilestouse.Now,normallyI'dadvocatesettingup
separateroutefilesfordifferentpartsofyourapp.Forexample,theusersroutefilemightcontain
routesforaddingusers,deletingthem,updatingthem,andsoforth,whileanewroutefilecalled
"locations"mighthandleadding,editing,deletinganddisplayinglocationdata(inanappforwhichthat
wasrequired).Inthiscase,tokeepthingssimple,we'regoingtodoeverythingintheindexrouter.That
meansyoucancompletelyignorethe/usersline.
RememberthattheExpressscaffoldingalreadydefinedthe"routes"variableandpointeditattheindex

thedefault.Inyourtexteditor,openupyourroutesfolder,findindex.js,andopenit.Itwilllooklike
this:
C:\NODE\NODETEST1\ROUTES\INDEX.JS
varexpress=require('express');
varrouter=express.Router();
/*GEThomepage.*/
router.get('/',function(req,res){
res.render('index',{title:'Express'});
});
module.exports=router;

Prettysparse,right?Basicallywe'rerequiringourExpressfunctionality,thenattachinga"router"
variabletoExpress'sroutermethod,thenusingthatmethodwhenanattemptismadetoHTTPgetthe
topleveldirectoryofourwebsite.Finallyweexportourrouterfunctionbacktoourapp.
Wecaneasilyclonethatgetfunctionforanotherpage,solet'sdothat.Atthebottomofthefile,
justabovethemodule.exportsline,addthiscode:
C:\NODE\NODETEST1\ROUTES\INDEX.JS
/*GETHelloWorldpage.*/
router.get('/helloworld',function(req,res){
res.render('helloworld',{title:'Hello,World!'});
});

That'sallittakestohandleroutingtheURI,butwedon'thaveanyactualpageforres.renderto
render.That'swhereJadecomesin.Openupyourviewsfolder,andthengoaheadandopen
index.jade.Beforeyoudoanythingelse,saveitashelloworld.jade.
Nowtakealookatthecode:
C:\NODE\NODETEST1\VIEWS\HELLOWORLD.JADE
extendslayout
blockcontent
h1=title
pWelcometo#{title}

Thisisprettystraightforward.Ituses("extends")thefilelayout.jadeasatemplate,andthenwithinthe
contentblockdefinedinthelayoutfile,itsticksaheaderandaparagraph.Notetheuseofthe"title"
variablewhichwesetabove,inourindex.jsroute.Thismeanswedon'tevenhavetochangethetextat
allinorderforittoshowdifferentstufffromthehomepage.Butlet'schangeitanywayto:
pHello,World!Welcometo#{title}

Savethefile,gotoyourcommandprompt,ctrlctokillyourserverifit'salreadyrunning,andthentype:
COMMANDC:\NODE\NODETEST1\

Inordertorestarttheserver.Bytheway,thisseemsagoodtimetomention:changestoJade
templatesdonotrequireaserverrestart,butbasicallywheneveryouchangeajsfile,suchasapp.jsor
theroutefiles,you'llneedtorestarttoseechanges.
SOwiththeserverrestarted,navigatetohttp://localhost:3000/helloworldandenjoythecompletely
asininetextthatgetsdisplayed:

OK!Sonowwe'vegotourrouterroutingustoourview,whichweareviewing.Let'sdosomemodeling.
I'llgiveyouamomentifyouneedtofixyourhairormakeup.

PART3CREATEOURDBANDREADSTUFFFROMIT
STEP1INSTALLMONGODB
We'releavingourtexteditorforabitandgoingbacktoourcommandprompt.Well,firstwe'regoingto
ourwebbrowser,pointingittohttp://mongodb.org/anddownloadingMongo.Clickthedownloadslink
inthemainmenuandsnagtheproductionreleasethatfitsyoursystem.ForWindows8ona64bit
processor,wewant"64bit*2008R2+".ThiswillgiveyouanMSIfilethatwillrunthroughastandard
Windowsinstall.ItwilldefaulttoinstallingintoyourProgramFilesdirectory(ina\server\3.0\subfolder),
whichisfine.Forthepurposesofthistutorial,though,I'mgoingtoinstallintoC:\Mongo.Itdoesn't
reallymatterMongoitselfisquitesmall,andwe'llbestoringourdatabaseinournodetest1directory.
Anyway,copythefilesinthebinfolderwithinyourtempdirectorytowhereveryouwantMongotolive,
andyou'redone.You'veinstalledMongo.Nowlet'smakeitdostuff.
STEP2RUNMONGODANDMONGO
Inyournodetest1directory,createasubdircalled"data".Thennavigatetothedirectoryinwhichyou
placedyourMongoDBfiles(let'ssayC:\mongofornow),andthenintothe"bin"directory.Fromthat
directory,typethefollowing:
COMMANDC:\MONGO\BIN\
mongoddbpathc:\node\nodetest1\data\

You'llseetheMongoserverstartup.Thisisgoingtotakeawhileifit'sthefirsttime,becauseithasto
dosomepreallocatingofspaceandafewotherhousekeepingtasks.Onceitsays"[initandlisten]waiting
forconnectionsonport27017",you'regood.There'snothingmoretodoheretheserverisrunning.
Nowyouneedtoopenasecondcommandprompt.NavigateagaintoyourMongoinstallation

directory,andtype:
COMMANDC:\MONGO\BIN\
mongo

You'llseesomethinglikethefollowing:
MONGOCONSOLE
c:\mongo\bin>mongo
MongoDBshellversion:2.4.5
connectingto:test

Additionally,ifyou'repayingattentiontoyourmongodinstance,you'llseeitmentionthataconnection
hasbeenestablished.Allright,you'vegotMongoDBupandrunning,andyou'veconnectedtoitwiththe
client.We'llusethisclienttomanuallyworkonourdatabase,forabit,butit'snotnecessaryforrunning
thewebsite.Onlytheserverdaemon(mongod)isneededforthat.
STEP3CREATEADATABASE
Don'tworryabout"connectingto:test"that'sjustthedefaultdatabaseMongodecidestouseifyou
don'tspecifyoneonthecommandline,whichwedidn'tbecauseit'snotimportantrightnow.Itdoesn't
actuallyevencreatethe"test"databaseunlessyouaddarecord.It'dbetotallyfinetojustworkinthat
databaseforrightnow,butlet'smakeoneofourown.InyourMongoconsole,typethefollowing:
MONGOCONSOLE
usenodetest1

Nowwe'reusingthedatabase"nodetest1."Likewith"test",nothingactuallyexistsyet.Tomakethe
databaseexist,wehavetoaddsomedata.We'regoingtostartoffbydoingthatrightinsideofthe
Mongoclient.
STEP4ADDSOMEDATA
MyfavoritethingaboutMongoDBisthatitusesJSONforitsstructure,whichmeansitwasinstantly
familiarforme.Ifyou'renotfamiliarwithJSON,you'llneedtodosomereading,asI'mafraidthat's
outsidethescopeofthistutorial.
Let'saddarecordtoourcollection.Forthepurposesofthistutorial,we'rejustgoingtohaveasimple
databaseofusernamesandemailaddresses.Ourdataformatwillthuslooklikethis:
MONGOCONSOLE
{
"_id":1234,
"username":"cwbuecheler",
"email":"cwbuecheler@nospam.com"
}

Youcancreateyourown_idassignmentifyoureallywant,butIfindit'sbesttoletMongojustdoits

howitworks.InyourMongoclient,typethis:
MONGOCONSOLE
db.usercollection.insert({"username":"testuser1","email":"testuser1@testdomain.com"})

Somethingimportanttonotehere:that"db"standsforourdatabase,whichasmentionedabovewe've
definedas"nodetest1".The"usercollection"partisourcollection.Notethattherewasn'tastepwhere
wecreatedthe"usercollection"collection.That'sbecausethefirsttimeweaddtoit,it'sgoingtobe
autocreated.Handy.OK,Hitenter.Assumingeverythingwentright,youshouldseenothing.That's
notveryexciting,sotypethis:
MONGOCONSOLE
db.usercollection.find().pretty()

Incaseyou'recurious,the.pretty()methodgivesuslinebreaks.Itwillreturn:
MONGOCONSOLE
{
"_id":ObjectId("5202b481d2184d390cbf6eca"),
"username":"testuser1",
"email":"testuser1@testdomain.com"
}

Except,ofcourse,yourObjectIDwillbedifferent,sinceasmentioned,Mongoisautomatically
generatingthose.That'sallthereistowritingtoMongoDBfromtheclientapp,andifyou'veever
workedwithJSONservicesbefore,youareprobablygoing"oh,wow,that'sgoingtobeeasyto
implementontheweb."you'reright!
AquicknoteonDBstructure:obviouslyinthelongrunyou'reunlikelytobestoringeverythingatthe
toplevel.ThereareatonofresourcesontheinternetforschemadesigninMongoDB.Googleisyour
friend!
Nowthatwe'vegotonerecord,let'saddaacouplemore.InyourMongoconsole,typethefollowing:
MONGOCONSOLE

newstuff=[{"username":"testuser2","email":"testuser2@testdomain.com"},{"username":"testuser3","em
db.usercollection.insert(newstuff);

Notethat,yes,wecanpassanarraywithmultipleobjectstoourcollection.Handy!Anotheruseof
db.usercollection.find().pretty()willshowallthreerecords:
MONGOCONSOLE
{
"_id":ObjectId("5202b481d2184d390cbf6eca"),
"username":"testuser1",
"email":"testuser1@testdomain.com"

"_id":ObjectId("5202b49ad2184d390cbf6ecb"),
"username":"testuser2",
"email":"testuser2@testdomain.com"
}
{
"_id":ObjectId("5202b49ad2184d390cbf6ecc"),
"username":"testuser3",
"email":"testuser3@testdomain.com"
}

Nowwe'regoingtostartactuallyinteractingwiththewebserverandsitethatwesetupearlier.
STEP5HOOKMONGOUPTONODE
Thisiswheretherubbermeetstheroad.Let'sstartbybuildingapagethatjustspitsoutourDBentries
inamildlyprettyform.Here'stheHTMLwe'reshootingtogenerate:
<ul>
<li><ahref="mailto:testuser1@testdomain.com">testuser1</a></li>
<li><ahref="mailto:testuser2@testdomain.com">testuser2</a></li>
<li><ahref="mailto:testuser3@testdomain.com">testuser3</a></li>
</ul>

Iknowthisisn'trocketscience,butthat'sthepoint.We'rejustdoingasimpleDBreadandwriteinthis
tutorial,nottryingtobuildawholewebsite.Firstthingsfirst,weneedtoaddafewlinestoourmain
app.jsfiletheheartandsoulofourappinordertoactuallyconnecttoourMongoDBinstance.Open
C:\node\nodetest1\app.jsandatthetopyou'llsee:
C:\NODE\NODETEST1\APP.JS
varexpress=require('express');
varpath=require('path');
varfavicon=require('servefavicon');
varlogger=require('morgan');
varcookieParser=require('cookieparser');
varbodyParser=require('bodyparser');

Nowaddthesethreelines:
C:\NODE\NODETEST1\APP.JS
varexpress=require('express');
varpath=require('path');
varfavicon=require('servefavicon');
varlogger=require('morgan');
varcookieParser=require('cookieparser');
varbodyParser=require('bodyparser');
//NewCode
varmongo=require('mongodb');
varmonk=require('monk');
vardb=monk('localhost:27017/nodetest1');

TheselinestellourappwewanttotalktoMongoDB,we'regoingtouseMonktodoit,andour
databaseislocatedatlocalhost:27017/nodetest1.Notethat27017isthedefaultportyourMongoDB
instanceshouldberunningon.Ifforsomereasonyou'vechangedit,obviouslyusethatportinstead.
Nowlookatthebottomofthefile,whereyouhavethis:

app.use('/',routes);
app.use('/users',users);

Weneedtodosomeworkhere.Thoseapp.usestatements(alongwiththeothersyou'llfindinapp.js)
areestablishingmiddlewareforExpress.Theshort,simpleexplanationis:they'reprovidingcustom
functionsthattherestofyourappcanmakeuseof.It'sprettystraightforward,butduetochainingit
needstocomebeforeourroutedefinitions,sothattheycanmakeuseofit.
Abovethetwolinesjustmentioned,addthefollowing:
C:\NODE\NODETEST1\APP.JS
//Makeourdbaccessibletoourrouter
app.use(function(req,res,next){
req.db=db;
next();
});

NOTE:Ifyoudon'tputthisabovetheroutingstuffmentionedabove(app.use('/',routes)),
yourappWILLNOTWORK.
Wealreadydefined"db"whenweaddedMongoandMonktoapp.js.It'sourMonkconnectionobject.By
addingthisfunctiontoapp.use,we'readdingthatobjecttoeveryHTTPrequest(ie:"req")ourapp
makes.Note:thisisprobablysuboptimalforperformancebut,again,we'regoingquickndirtyhere.
So,again,thatcodeneedstogoaboveourroutingcode.Yourentireapp.jsshouldlooklikethis,now:
C:\NODE\NODETEST1\APP.JS
varexpress=require('express');
varpath=require('path');
varfavicon=require('servefavicon');
varlogger=require('morgan');
varcookieParser=require('cookieparser');
varbodyParser=require('bodyparser');
//NewCode
varmongo=require('mongodb');
varmonk=require('monk');
vardb=monk('localhost:27017/nodetest1');
varroutes=require('./routes/index');
varusers=require('./routes/users');
varapp=express();
//viewenginesetup
app.set('views',path.join(__dirname,'views'));
app.set('viewengine','jade');
//uncommentafterplacingyourfaviconin/public
//app.use(favicon(__dirname+'/public/favicon.ico'));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended:false}));
app.use(cookieParser());
app.use(express.static(path.join(__dirname,'public')));
//Makeourdbaccessibletoourrouter
app.use(function(req,res,next){
req.db=db;
next();

app.use('/',routes);
app.use('/users',users);
///catch404andforwardingtoerrorhandler
app.use(function(req,res,next){
varerr=newError('NotFound');
err.status=404;
next(err);
});
///errorhandlers
//developmenterrorhandler
//willprintstacktrace
if(app.get('env')==='development'){
app.use(function(err,req,res,next){
res.status(err.status||500);
res.render('error',{
message:err.message,
error:err
});
});
}
//productionerrorhandler
//nostacktracesleakedtouser
app.use(function(err,req,res,next){
res.status(err.status||500);
res.render('error',{
message:err.message,
error:{}
});
});
module.exports=app;

Nextthingweneedtodoismodifyourroutesothatwecanactuallyshowdatathat'sheldinour
database,usingourdbobject.
STEP6PULLYOURDATAFROMMONGOANDDISPLAYIT
OpenupC:\node\nodetest1\routes\index.jsinyoureditor.It'sstillgottheindexroute,andthegoofy
/helloworldroute.Let'saddathird:
C:\NODE\NODETEST1\ROUTES\INDEX.JS
/*GETUserlistpage.*/
router.get('/userlist',function(req,res){
vardb=req.db;
varcollection=db.get('usercollection');
collection.find({},{},function(e,docs){
res.render('userlist',{
"userlist":docs
});
});
});

OKthat'sgettingfairlycomplicated.Allit'sreallydoing,though,isextractingthe"db"objectwe
passedtoourhttprequest,andthenusingthatdbconnectiontofillour"docs"variablewithdatabase
documents,ie:userdata.Thenwedoapagerenderjustliketheothertwo"gets"inthisroutefile.
Basically,wetellourappwhichcollectionwewanttouse('usercollection')anddoafind,thenreturnthe
resultsasthevariable"docs".Oncewehavethosedocuments,wethendoarenderofuserlist(which
willneedacorrespondingJadetemplate),givingittheuserlistvariabletoworkwith,andpassingour

Nextlet'ssetupourJadetemplate.NavigatetoC:\node\nodetest1\views\andopenindex.jade.Once
again,immediatelysaveitasuserlist.jade.ThenedittheHTMLsoitlookslikethis:
C:\NODE\NODETEST1\VIEW\USERLIST.JADE
extendslayout
blockcontent
h1.
UserList
ul
eachuser,iinuserlist
li
a(href="mailto:#{user.email}")=user.username

Thisissayingthatwe'regoingtopullinthesetofdocumentswejustcalleduserlistoverintheroute
file,andthenforeachentry(named'user'duringtheloop),gettheemailandusernamevaluesfromthe
objectandputthemintoourhtml.We'vealsogotthecountihandyincaseweneedit,thoughin
thisinstancewedon't.
We'reallset.Savethatfile,andlet'srestartournodeserver.Rememberhowtodothat?Gotoyour
commandprompt,headforC:\node\nodetest1\andctrlctokillyourserverifit'sstillrunningfromway
backbefore.Thentype:
COMMANDC:\NODE\NODETEST1\
C:\node\nodetest1>npmstart

TIP
Gettingthefollowingerror?
{[Error:Cannotfindmodule'../build/Release/bson']code:'MODULE_NOT_FOUND'}jsbson:Failedtoloadc++
bsonextension,usingpureJSversion
ClickHereforHelp

Nowopenyourbrowserandheadtohttp://localhost:3000/userlistandmarvelattheresults.

You'renowpullingdatafromtheDBandspittingitoutontoawebpage.Nice!
TIP
Gettingthefollowingerror?

ClickHereforHelp

ThereonemorethingIbadlywantedtocoverinthistutorial,butbecauseit'salreadyaboutaslongas
theBible,I'mgoingtobreezethroughithere.Youcouldveryeasilychangeyouruserlistviewfroman
ExpressdrivenwebpagecompletewithJadetemplatetoaplainoldJSONresponse.Youcouldthen
accessthiswithAJAXandmanipulateitontheclientside,withjQueryforexample,insteadofonthe
serverside.Infact,IwantedtocoverthatsobadlythatIwroteanentiresecondtutorialonit.Youcan
findthelinkattheendofthisone!
Let'sfinishthisup.

PART4THEHOLYGRAIL:WRITINGTOTHEDB
Writingtothedatabaseisnotparticularlydifficult.Essentiallyweneedtosetuparoutethattakesa
POST,ratherthanaGET.
STEP1CREATEYOURDATAINPUT
We'regoingquickanddirtyhere:twougly,unstyledtextinputsandasubmitbutton.1996style,but
beforewegettothat,we'regoingtodosomejavacripting.Let'sstartbyquicklywiringuparoutefor
ouradduserform.Open/routes/index.jsandaddthefollowingcodeabovethelastmodule.exportsline:
C:\NODE\NODETEST1\ROUTES\INDEX.JS
/*GETNewUserpage.*/
router.get('/newuser',function(req,res){
res.render('newuser',{title:'AddNewUser'});
});

Nowwejustneedatemplate.Openup/views/index.jade,saveitasnewuser.jade,andreplacethe
wholefilecontentswiththis:
C:\NODE\NODETEST1\VIEWS\NEWUSER.JADE
extendslayout
blockcontent
h1=title
form#formAddUser(name="adduser",method="post",action="/adduser")
input#inputUserName(type="text",placeholder="username",name="username")
input#inputUserEmail(type="text",placeholder="useremail",name="useremail")
button#btnSubmit(type="submit")submit

Herewe'recreatingaformwiththeID"formAddUser"(IliketoprefacemyIDswiththetypeofthing
we'reID'ing.It'sapersonalquirk).Methodispost,actionisadduser.Prettystraightforward.Underthat
we'vedefinedourtwoinputsandourbutton.
Ifyourestartyournodeserverandgotohttp://localhost:3000/newuseryou'llseeyourforminallits
glory.

Goaheadandsubmit.Enjoythe404error.We'reabouttofixthat.
STEP2CREATEYOURDBFUNCTIONS
OK,thisisprettymuchthesameprocessaswiththeuserlist.Wedon'tneedanotherapp.usestatement
sincewe'vealreadywrappedourdatabaseobjectintoeveryrequest(seeabove).Thatmeansit'llbe
accessibletoanynewrouteswewrite.ThatmeansthatallweneedtodoisaddarouteforPOSTingto
/adduser.
Gobackto/routes/index.jsandlet'screateourinsertionfunction.Onceagain,you'llwanttoput
thisabovethefinalmodule.exportsline(itdoesn'tREALLYmatter,butitmakesthingscleanertowrap
upwiththeexport).Thisisabigone,soI'vecommentedthecodeprettythoroughly.Hereitis:
C:\NODE\NODETEST1\ROUTES\INDEX.JS
/*POSTtoAddUserService*/
router.post('/adduser',function(req,res){
//SetourinternalDBvariable
vardb=req.db;
//Getourformvalues.Theserelyonthe"name"attributes
varuserName=req.body.username;
varuserEmail=req.body.useremail;
//Setourcollection
varcollection=db.get('usercollection');
//SubmittotheDB
collection.insert({
"username":userName,
"email":userEmail
},function(err,doc){
if(err){
//Ifitfailed,returnerror
res.send("Therewasaproblemaddingtheinformationtothedatabase.");
}
else{
//Andforwardtosuccesspage
res.redirect("userlist");
}
});
});

Obviouslyintherealworldyouwouldwantatonmorevalidating,errorchecking,andthelike.You'd
wanttocheckforduplicateusernamesandemails,forexample.Andtovetthattheemailaddressat
leastlookslikealegitentry.Butthis'llworkfornow.Asyoucansee,onsuccessfullyaddingtotheDB,

Aretheresmootherwaystodothis?Absolutely.We'restayingasbarebonesaspossiblehere.Now,let's
goaddsomedata!
STEP3CONNECTANDADDDATATOYOURDB
Makesuremongodisrunning!Thenheadtoyourcommandprompt,killyournodeserverifit'sstill
running,andrestartit:
COMMANDC:\NODE\NODETEST1\
C:\node\nodetest1>npmstart

Assumingyourserverisrunning,whichitshouldbe,returntoyourwebbrowserandpointit
athttp://localhost:3000/newuseragain.There'sourexcitingform,justlikebefore.Exceptnowlet'sfillin
somevaluesbeforewehitsubmit.Iwentwithusername"noderocks"andemail
"noderocks@rockingnode.com"...youcangowithwhateveryou'dlike.

Clicksubmit,andcheckitout...we'rebackat/userlistandthere'sournewentry!

WeareofficiallyreadingandwritingfromaMongoDBdatabaseusingNode.js,Express,andJade.You
arenowwhatthekidscalla"fullstack"developer(probablynotaGOODone,justyet,butIdidn't
promisethat).
Congratulations.Seriously.Ifyoufollowedthisallthewaythrough,andifyoureallypaidattentionto
whatyouweredoinganddidn'tjustpastecode,youshouldhaveareallysolidgrasponroutesand
views,readingfromtheDB,andpostingtotheDB.Thatisallyouneedtogetstarteddeveloping
whateverappyouwanttobuild.Idon'tknowaboutyou,butIthinkthat'sreallycool.

PART5NEXTSTEPS
Fromhere,there'samilliondifferentdirectionsyoucouldgo.YoucouldcheckoutMongoose,whichis
anotherMongomanipulationpackageforNode/Express(here'sagoodtutorialforbeginners).It'sbigger
thanMonk,butitalsodoesmore.YoucouldcheckoutStylus,theCSSpreprocessorthatcomeswith
Express.Youcouldgoogle"NodeExpressMongoTutorial"andseewhatcomesup.Justkeepexploring
andkeepbuilding!
Ihopethistutorial'sbeenhelpful.IwroteitbecauseIcould'veuseditwhenIgotstarted,andIcouldn't
seemtofindsomethingthatwasquiteatthislevel,orthatbrokethingsdowninsuchlong,
long,loooongdetail.Ifyoumadeitthisfar,thanksforstickingwithit!
NEW:The"sequel"tothistutorialisnowavailable!Finditat:CreatingaSimpleRESTfulWebAppwith
Node.js,Express,andMongoDB.
Resource:thefolksatUdemyhaveputupanincrediblyextensiveMEANstackintroductionthat'swell
worthcheckingout.
MERCIBEAUCOUP

You might also like