node.js essentials - the-eye.eu · node.js essentials credits about the author about the reviewer...
TRANSCRIPT
![Page 1: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/1.jpg)
![Page 2: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/2.jpg)
![Page 3: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/3.jpg)
Node.jsEssentials
![Page 4: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/4.jpg)
TableofContents
Node.jsEssentials
Credits
AbouttheAuthor
AbouttheReviewer
www.PacktPub.com
Supportfiles,eBooks,discountoffers,andmore
Whysubscribe?
FreeaccessforPacktaccountholders
Preface
Whatthisbookcovers
Whatyouneedforthisbook
Whothisbookisfor
Conventions
Readerfeedback
Customersupport
Downloadingtheexamplecode
Errata
Piracy
Questions
1.GettingStarted
Settingup
Hellorequire
Hellonpm
Summary
2.SimpleHTTP
Introducingrouting
Summary
3.Authentication
Basicauthentication
![Page 5: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/5.jpg)
Bearertokens
OAuth
Summary
4.Debugging
Logging
Errorhandling
Summary
5.Configuration
JSONfiles
Environmentalvariables
Arguments
Summary
6.LevelDBandNoSQL
LevelDB
MongoDB
Summary
7.Socket.IO
Rooms
Authentication
Summary
8.CreatingandDeployingPackages
Creatingnpmpackages
Summary
9.UnitTesting
Installingmocha
Chai
Stubbingmethods
Summary
10.UsingMoreThanJavaScript
CoffeeScript
Codeblocksandfunctions
![Page 6: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/6.jpg)
Theexistentialoperator
Objectsandarrays
Classes
Summary
Index
![Page 7: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/7.jpg)
![Page 8: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/8.jpg)
Node.jsEssentials
![Page 9: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/9.jpg)
![Page 10: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/10.jpg)
Node.jsEssentialsCopyright©2015PacktPublishing
Allrightsreserved.Nopartofthisbookmaybereproduced,storedinaretrievalsystem,ortransmittedinanyformorbyanymeans,withoutthepriorwrittenpermissionofthepublisher,exceptinthecaseofbriefquotationsembeddedincriticalarticlesorreviews.
Everyefforthasbeenmadeinthepreparationofthisbooktoensuretheaccuracyoftheinformationpresented.However,theinformationcontainedinthisbookissoldwithoutwarranty,eitherexpressorimplied.Neithertheauthor,norPacktPublishing,anditsdealersanddistributorswillbeheldliableforanydamagescausedorallegedtobecauseddirectlyorindirectlybythisbook.
PacktPublishinghasendeavoredtoprovidetrademarkinformationaboutallofthecompaniesandproductsmentionedinthisbookbytheappropriateuseofcapitals.However,PacktPublishingcannotguaranteetheaccuracyofthisinformation.
Firstpublished:November2015
Productionreference:1301015
PublishedbyPacktPublishingLtd.
LiveryPlace
35LiveryStreet
BirminghamB32PB,UK.
ISBN978-1-78528-492-2
www.packtpub.com
![Page 11: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/11.jpg)
![Page 12: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/12.jpg)
CreditsAuthor
FabianCook
Reviewers
ShoubhikBose
GlennGeenen
CommissioningEditor
EdwardGordan
AcquisitionEditor
DivyaPoojari
ContentDevelopmentEditor
AthiraLaji
TechnicalEditor
NaveenkumarJain
CopyEditor
SnehaSingh
ProjectCoordinator
HarshalVed
Proofreader
SafisEditing
Indexer
HemanginiBari
ProductionCoordinator
ShantanuN.Zagade
CoverWork
ShantanuN.Zagade
![Page 13: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/13.jpg)
![Page 14: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/14.jpg)
AbouttheAuthorFabianCookisanexperiencedJavaScriptdeveloperwholivesinHawkesBay,NewZealand.HebeganworkingwithJavaandC#veryearlyinhislife,whichleadtousingNode.jsinanopensourcecontext.HeisnowcurrentlyworkingforaNewZealandISP,knownasNOWNZwheretheyareutilizingthefullpowerofNode.js,DockerandCoreOS.
![Page 15: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/15.jpg)
![Page 16: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/16.jpg)
AbouttheReviewerGlennGeenenisaNode.jsdeveloperwithabackgroundingameandmobiledevelopment.HehasmostlyworkedasaniOSconsultantbeforebecomingaNode.jsconsultantforhiscompany,GeenenTijd.
![Page 17: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/17.jpg)
![Page 18: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/18.jpg)
www.PacktPub.com
![Page 19: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/19.jpg)
Supportfiles,eBooks,discountoffers,andmoreForsupportfilesanddownloadsrelatedtoyourbook,pleasevisitwww.PacktPub.com.
DidyouknowthatPacktofferseBookversionsofeverybookpublished,withPDFandePubfilesavailable?YoucanupgradetotheeBookversionatwww.PacktPub.comandasaprintbookcustomer,youareentitledtoadiscountontheeBookcopy.Getintouchwithusat<[email protected]>formoredetails.
Atwww.PacktPub.com,youcanalsoreadacollectionoffreetechnicalarticles,signupforarangeoffreenewslettersandreceiveexclusivediscountsandoffersonPacktbooksandeBooks.
https://www2.packtpub.com/books/subscription/packtlib
DoyouneedinstantsolutionstoyourITquestions?PacktLibisPackt’sonlinedigitalbooklibrary.Here,youcansearch,access,andreadPackt’sentirelibraryofbooks.
![Page 20: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/20.jpg)
Whysubscribe?FullysearchableacrosseverybookpublishedbyPacktCopyandpaste,print,andbookmarkcontentOndemandandaccessibleviaawebbrowser
![Page 21: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/21.jpg)
FreeaccessforPacktaccountholdersIfyouhaveanaccountwithPacktatwww.PacktPub.com,youcanusethistoaccessPacktLibtodayandview9entirelyfreebooks.Simplyuseyourlogincredentialsforimmediateaccess.
![Page 22: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/22.jpg)
![Page 23: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/23.jpg)
PrefaceNode.jsissimplyatoolthatletsyouuseJavaScriptontheserverside.However,itactuallydoesmuchmorethanthat–byextendingJavaScript,itallowsforamuchmoreintegratedandefficientapproachtodevelopment.Itcomesasnosurprisethatit’safundamentaltoolforfull-stackJavaScriptdevelopers.Whetheryouworkonthebackendorfrontend,youadoptamuchmorecollaborativeandagilewayofworkingusingNode.js,sothatyouandyourteamcanfocusondeliveringaqualityendproduct.Thiswillensurethatyou’rereadytotakeonanynewchallengethatgetsthrownatyou.
Thisbookwillbefastpacedandcoverdependencymanagement,runningyourownHTTPserver,realtimecommunication,andeverythinginbetweenthatisneededtogetupandrunningwithNode.js.
![Page 24: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/24.jpg)
WhatthisbookcoversChapter1,GettingStarted,coversthesetupofNode.js.Youwillalsocoverhowtoutilizeandmanagedependencies.
Chapter2,SimpleHTTP,covershowtorunasimpleHTTPserverandhelpsyouunderstandroutingandutilizationofmiddleware.
Chapter3,Authentication,coverstheutilizationofmiddlewareandJSONWebTokentoauthenticateusers.
Chapter4,Debugging,coverstheintegrationofpost-mortemtechniquesinyourdevelopmenttasksandhowtodebugyourNode.jsprograms.
Chapter5,Configuration,coverstheconfigurationandmaintenanceofyoursoftwareusingcentralizedconfigurationoptions,arguments,andenvironmentalvariables.
Chapter6,LevelDBandNoSQL,coverstheintroductionofNoSQLdatabases,suchasLevelDBandMongoDB.Italsocoverstheuseofthesimplekey/valuestoreandamorecompletedocumentdatabase.
Chapter7,Socket.IO,exploresthereal-timecommunicationbetweenclients,servers,andbackagainandalsohowitauthenticatesandnotifiestheusers.
Chapter8,CreatingandDeployingPackages,focusesonsharingthemodulesandcontributingtotheeco-system
Chapter9,UnitTesting,testsyourcodeusingMocha,Sinon,andChanceandalsocovershowtousemockswithfunctionsandgeneraterandomvaluestotestyourcode
Chapter10,UsingMoreThanJavaScript,explainstheusageofCoffeeScriptwithNode.jstoexpandlanguagecapabilities.
![Page 25: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/25.jpg)
![Page 26: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/26.jpg)
WhatyouneedforthisbookYouwillneedacomputerthatrunsUnix(Macintosh),LinuxorWindows,alongwithyourpreferredIntegratedDevelopmentEnvironment.Ifyoudon’thaveanIDEthenyouhaveafewoptions,suchas:
Atom:https://atom.io/Sublime:http://www.sublimetext.com/Cloud9:https://c9.io/
![Page 27: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/27.jpg)
![Page 28: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/28.jpg)
WhothisbookisforThebookwillbehelpfultoanybodywhowantstohaveknowledgeofNode.js(whatNode.jsisabout,howtouseit,whereit’susefulandwhentouseit).Familiaritywithserver-sideandNode.jsisaprerequisite.
![Page 29: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/29.jpg)
![Page 30: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/30.jpg)
ConventionsInthisbook,youwillfindanumberofstylesoftextthatdistinguishbetweendifferentkindsofinformation.Herearesomeexamplesofthesestyles,andanexplanationoftheirmeaning.
Codewordsintext,databasetablenames,foldernames,filenames,fileextensions,pathnames,dummyURLs,userinput,andTwitterhandlesareshownasfollows:“Wecanincludeothercontextsthroughtheuseoftheincludedirective.”
Ablockofcodeissetasfollows:
<scripttype='application/javascript'src='script_a.js'></script>
<scripttype='application/javascript'src='script_b.js'></script>
Anycommand-lineinputoroutputiswrittenasfollows:
[~]$npminstall-gn
Newtermsandimportantwordsareshowninbold.Wordsthatyouseeonthescreen,inmenusordialogboxesforexample,appearinthetextlikethis:“Iftheuserhasn’tpassedboththeusernameandpasswordtheserverwillreturn500BadRequest“.
NoteWarningsorimportantnotesappearinaboxlikethis.
TipTipsandtricksappearlikethis.
![Page 31: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/31.jpg)
![Page 32: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/32.jpg)
ReaderfeedbackFeedbackfromourreadersisalwayswelcome.Letusknowwhatyouthinkaboutthisbook—whatyoulikedormayhavedisliked.Readerfeedbackisimportantforustodeveloptitlesthatyoureallygetthemostoutof.
Tosendusgeneralfeedback,simplysendane-mailto<[email protected]>,andmentionthebooktitleviathesubjectofyourmessage.
Ifthereisatopicthatyouhaveexpertiseinandyouareinterestedineitherwritingorcontributingtoabook,seeourauthorguideonwww.packtpub.com/authors.
![Page 33: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/33.jpg)
![Page 34: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/34.jpg)
CustomersupportNowthatyouaretheproudownerofaPacktbook,wehaveanumberofthingstohelpyoutogetthemostfromyourpurchase.
![Page 35: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/35.jpg)
DownloadingtheexamplecodeYoucandownloadtheexamplecodefilesforallPacktbooksyouhavepurchasedfromyouraccountathttp://www.packtpub.com.Ifyoupurchasedthisbookelsewhere,youcanvisithttp://www.packtpub.com/supportandregistertohavethefilese-maileddirectlytoyou.
![Page 36: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/36.jpg)
ErrataAlthoughwehavetakeneverycaretoensuretheaccuracyofourcontent,mistakesdohappen.Ifyoufindamistakeinoneofourbooks—maybeamistakeinthetextorthecode—wewouldbegratefulifyouwouldreportthistous.Bydoingso,youcansaveotherreadersfromfrustrationandhelpusimprovesubsequentversionsofthisbook.Ifyoufindanyerrata,pleasereportthembyvisitinghttp://www.packtpub.com/submit-errata,selectingyourbook,clickingontheerratasubmissionformlink,andenteringthedetailsofyourerrata.Onceyourerrataareverified,yoursubmissionwillbeacceptedandtheerratawillbeuploadedonourwebsite,oraddedtoanylistofexistingerrata,undertheErratasectionofthattitle.Anyexistingerratacanbeviewedbyselectingyourtitlefromhttp://www.packtpub.com/support.
![Page 37: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/37.jpg)
PiracyPiracyofcopyrightmaterialontheInternetisanongoingproblemacrossallmedia.AtPackt,wetaketheprotectionofourcopyrightandlicensesveryseriously.Ifyoucomeacrossanyillegalcopiesofourworks,inanyform,ontheInternet,pleaseprovideuswiththelocationaddressorwebsitenameimmediatelysothatwecanpursuearemedy.
Pleasecontactusat<[email protected]>withalinktothesuspectedpiratedmaterial.
Weappreciateyourhelpinprotectingourauthors,andourabilitytobringyouvaluablecontent.
![Page 38: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/38.jpg)
QuestionsYoucancontactusat<[email protected]>ifyouarehavingaproblemwithanyaspectofthebook,andwewilldoourbesttoaddressit.
![Page 39: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/39.jpg)
![Page 40: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/40.jpg)
Chapter1.GettingStartedEveryWebdevelopermusthavecomeacrossiteveryonceinawhile,eveniftheyjustdabbleinsimpleWebpages.WheneveryouwanttomakeyourWebpagealittlemoreinteractive,yougrabyourtrustworthyfriends,suchasJavaScriptandjQuery,andhacktogethersomethingnew.YoumighthavedevelopedsomeexcitingfrontendapplicationsusingAngularJSorBackboneandwanttolearnmoreaboutwhatelseyoucandowithJavaScript.
WhiletestingyourwebsiteonmultiplebrowsersyoumusthavecomeacrossGoogleChromeatsomepointandyoumighthavenoticedthatitisagreatplatformforJavaScriptapplications.
GoogleChromeandNode.jshavesomethingverybigincommon:theybothworkonGoogle’shigh-performanceV8JavaScriptengine,thisgivesusthesameengineinthebrowserthatwewillbeusinginthebackend,prettycool,right?
![Page 41: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/41.jpg)
SettingupInordertogetstartedanduseNode.js,weneedtodownloadandinstallNode.js.Thebestwaytoinstallitwillbetoheadovertohttps://nodejs.org/anddownloadtheinstaller.
Atthetimeofwriting,thecurrentversionofNode.jsis4.2.1.
Toensureconsistency,wearegoingtouseanpmpackagetoinstallthecorrectversionofNode.JSand,forthis,wearegoingtousethenpackagedescribedathttps://www.npmjs.com/package/n.
Currently,thispackagehassupportonlyfor*nixmachines.ForWindows.seenvm-windowsordownloadthebinaryfor4.2.1fromhttps://nodejs.org/dist/v4.2.1/.
OnceyouhaveNode.jsinstalled,openaterminalandrun:
[~]$npminstall-gn
The–gargumentwillinstallthepackagegloballysowecanusethepackageanywhere.
Linuxusersmayneedtoruncommandsthatinstallglobalpackagesassudo.
Usingtherecentlyinstallpackage,run:
[~]$n
Thiswilldisplayascreenwiththefollowingpackages:
node/0.10.38
node/0.11.16
node/0.12.0
node/0.12.7
node/4.2.1
Ifnode/4.2.1isn’tmarkedwecansimplyrunthefollowingpackages;thiswillensurethatnode/4.2.1getsinstalled:
[~]$sudon4.2.1
Toensurethatthenodeisgood-to-go,letscreateandrunasimplehelloworldexample:
[~/src/examples/example-1]$touchexample.js
[~/src/examples/example-1]$echo"console.log(\"Helloworld\")">
example.js
[~/src/examples/example-1]$nodeexample.js
HelloWorld
Cool,itworks;nowlet’sgetdowntobusiness.
![Page 42: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/42.jpg)
![Page 43: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/43.jpg)
HellorequireIntheprecedingexample,wejustloggedasimplemessage,nothinginteresting,solet’sdiveabitdeeperinthissection.
Whenusingmultiplescriptsinthebrowser,weusuallyjustincludeanotherscripttagsuchas:
<scripttype='application/javascript'src='script_a.js'></script>
<scripttype='application/javascript'src='script_b.js'></script>
Boththesescriptssharethesameglobalscope,thisusuallyleadstosomeunusualconflictswhenpeoplewanttogivevariablesthesamename.
//script_a.js
functionrun(){
console.log("I'mrunningfromscript_a.js!");
}
$(run);
//script_b.js
functionrun(){
console.log("I'mrunningfromscript_b.js!");
}
$(run);
Thiscanleadtoconfusion,andwhenmanyfilesareminifiedandcrammedtogetheritcausesaproblem;script_adeclaresaglobalvariable,whichisthendeclaredagaininscript_band,onrunningthecode,weseethefollowingontheconsole:
>I'mrunningfromscript_b.js!
>I'mrunningfromscript_b.js!
Themostcommonmethodtogetaroundthisandtolimitthepollutionoftheglobalscopeistowrapourfileswithananonymousfunction,asshown:
//script_a.js
(function($,undefined){
functionrun(){
console.log("I'mrunningfromscript_a.js!");
}
$(run);
})(jQuery);
//script_b.js
(function($,undefined){
functionrun(){
console.log("I'mrunningfromscript_b.js!");
}
$(run);
})(jQuery);
Nowwhenwerunthis,itworksasexpected:
>I'mrunningfromscript_a.js!
![Page 44: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/44.jpg)
>I'mrunningfromscript_b.js!
Thisisgoodforcodethatisn’tdependeduponexternally,butwhatdowedoforthecodethatis?Wejustexportit,right?
Somethingsimilartothefollowingcodewilldo:
(function(undefined){
functionLogger(){
}
Logger.prototype.log=function(message/*...*/){
console.log.apply(console,arguments);
}
this.Logger=Logger;
})()
Now,whenwerunthisscript,wecanaccessLoggerfromtheglobalscope:
varlogger=newLogger();
logger.log("This","is","pretty","cool")
>Thisisprettycool
Sonowwecanshareourlibrariesandeverythingisgood;ButwhatifsomeoneelsealreadyhasalibrarythatexposesthesameLoggerclass.
Whatdoesnodedotosolvethisissue?Hellorequire!
Node.jshasasimplewaytobringinscriptsandmodulesfromexternalsources,comparabletorequireinPHP.
Letscreateafewfilesinthisstructure:
/example-2
/util
index.js
logger.js
main.js
/*util/index.js*/
varlogger=newLogger()
varutil={
logger:logger
};
/*util/logger.js*/
functionLogger(){
}
Logger.prototype.log=function(message/*...*/){
console.log.apply(console,arguments);
};
/*main.js*/
util.logger.log("Thisisprettycool");
Wecanseethatmain.js.isdependentonutil/index.js,whichisinturndependentonutil/logger.js.
![Page 45: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/45.jpg)
Thisshouldjustworkright?Maybenot.Let’srunthecommand:
[~/src/examples/example-2]$nodemain.js
ReferenceError:loggerisnotdefined
atObject.<anonymous>(/Users/fabian/examples/example-2/main.js:1:63)
/*Removedforsimplicity*/
atNode.js:814:3
Sowhyisthis?Shouldn’ttheybesharingthesameglobalscope?Well,inNode.jsthestoryisabitdifferent.Rememberthoseanonymousfunctionsthatwewerewrappingourfilesinearlier?Node.jswrapsourscriptsinthemautomaticallyandthisiswhererequirefitsin.
Letsfixourfiles,asshown:
/*util/index.js*/
Logger=require("./logger")
/*main.js*/
util=require("./util");
Ifyounotice,Ididn’tuseindex.jswhenrequiringutil/index.js;thereasonforthisisthatwhenyouarequireafolderratherthanafileyoucanspecifyanindexfilethatcanrepresentthatfolder’scode.Thiscanbehandyforsomethingsuchasamodelfolderwhereyouexposeallyourmodelsinonerequireratherthanhavingaseparaterequireforeachmodel.
Sonow,wehaverequiredourfiles.Butwhatdowegetback?
[~/src/examples/example-2]$node
>varutil=require("./util");
>console.log(util);
{}
Still,thereisnologger.Wehavemissedanimportantstep;wehaven’ttoldNode.jswhatwewanttoexposeinourfiles.
ToexposesomethinginNode.js,weuseanobjectcalledmodule.exports.Thereisashorthandreferencetoitthatisjustexports.Whenourfileiswrappedinananonymousfunction,bothmoduleandexportsarepassedasaparameter,asshowninthefollowingexample:
functionModule(){
this.exports={};
}
functionrequire(file){
//.....
returnsmodule.exports;
}
varmodule=newModule();
varexports=module.exports;
(function(exports,require,module){
![Page 46: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/46.jpg)
exports="Valuea"
module.exports="Valueb"
})(exports,require,module);
console.log(module.exports);
//Valueb
TipDownloadingtheexamplecode
YoucandownloadtheexamplecodefilesforallPacktbooksyouhavepurchasedfromyouraccountathttp://www.packtpub.com.Ifyoupurchasedthisbookelsewhere,youcanvisithttp://www.packtpub.com/supportandregistertohavethefilese-maileddirectlytoyou.
Theexampleshowsthatexportsisinitiallyjustareferencetomodule.exports.Thismeansthat,ifyouuseexports={},thevalueyousetitaswon’tbeaccessibleoutsidethefunction’sscope.However,whenyouaddpropertiestoanexportsobject,youareactuallyaddingpropertiestothemodule.exportsobjectastheyareboththesamevalue.Assigningavaluetomodule.exportswillexportthatvaluebecauseitisaccessibleoutsidethefunction’sscopethroughthemodule.
Withthisknowledge,wecanfinallyrunourscriptinthefollowingmanner:
/*util/index.js*/
Logger=require("./logger.js");
exports.logger=newLogger();
/*util/logger.js*/
functionLogger(){
}
Logger.prototype.log=(message/*...*/){
console.log.apply(console,arguments);
};
module.exports=Logger;
/*main.js*/
util=require("./utils");
util.logger.log("Thisisprettycool");
Runningmain.js:
[~/src/examples/example-2]$nodemain.js
Thisisprettycool
Requirecanalsobeusedtoincludemodulesinourcode.Whenrequiringmodules,wedon’tneedtouseafilepath,wejustneedthenameofthenodemodulethatwewant.
Node.jsincludesmanyprebuiltcoremodules,oneofwhichistheutilmodule.Youcanfinddetailsontheutilmoduleathttps://nodejs.org/api/util.html.
Let’sseetheutilmodulecommand:
[~]$node
>varutil=require("util")
![Page 47: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/47.jpg)
>util.log('Thisisprettycoolaswell')
01Jan00:00:00-Thisisprettycoolaswell
![Page 48: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/48.jpg)
![Page 49: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/49.jpg)
HellonpmAlongwithinternalmodulesthereisalsoanentireecosystemofpackages;themostcommonpackagemanagerforNode.jsisnpm.Atthetimeofwriting,thereareatotalof192,875packagesavailable.
Wecanusenpmtoaccesspackagesthatdomanythingsforus,fromroutingHTTPrequeststobuildingourprojects.Youcanalsobrowsethepackagesavailableathttps://www.npmjs.com/.
Usingapackagemanageryoucanbringinothermodules,whichisgreatasyoucanspendmoretimeworkingonyourbusinesslogicratherthanreinventingthewheel.
Let’sdownloadthefollowingpackagetomakeourlogmessagescolorful:
[~/src/examples/example-3]$npminstallchalk
Now,touseit,createafileandrequireit:
[~/src/examples/example-3]$touchindex.js
/*index.js*/
varchalk=require("chalk");
console.log("Iamjustnormaltext")
console.log(chalk.blue("Iambluetext!"))
Onrunningthiscode,youwillseethefirstmessageinadefaultcolorandthesecondmessageinblue.Let’slookatthecommand:.
[~/src/examples/example-3]$nodeindex.js
Iamjustnormaltext
Iambluetext!
Havingtheabilitytodownloadexistingpackagescomesinhandywhenyourequiresomethingthatsomeoneelsehasalreadyimplemented.Aswesaidearlier,therearemanypackagesouttheretochoosefrom.
Weneedtokeeptrackofthesedependenciesandthereisasimplesolutiontothat:package.json.
Usingpackage.jsonwecandefinethings,suchasthenameofourproject,whatthemainscriptis,howtoruntests,ourdependencies,andsoon.Youcanfindafulllistofpropertiesathttps://docs.npmjs.com/files/package.json.
npmprovidesahandycommandtocreatethesefilesanditwillaskyoutherelevantquestionsneededtocreateyourpackage.jsonfile:
[~/src/examples/example-3]$npminit
Theprecedingutilitywillwalkyouthroughthecreationofapackage.jsonfile.
Itonlycoversthemostcommonitemsandtriestoguessvaliddefaults.
Runthenpmhelpjsoncommandfordefinitivedocumentationonthesefieldsandtoknowwhattheydoexactly.
![Page 50: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/50.jpg)
Afterwards,usenpmandinstall<pkg>--savetoinstallapackageandsaveitasadependencyinthepackage.jsonfile.
Press^Ctoquitatanytime:
name:(example-3)
version:(1.0.0)
description:
entrypoint:(main.js)
testcommand:
gitrepository:
keywords:
license:(ISC)
Abouttowriteto/examples/example-3/package.json:
{
"name":"example-3",
"version":"1.0.0",
"description":"",
"main":"main.js",
"scripts":{
"test":"echo\"Error:notestspecified\"&&exit1"
},
"author":"....",
"license":"ISC"
}
Isthisok?(yes)
Theutilitywillprovideyouwithdefaultvalues,soitiseasiertojustskipthroughthemusingtheEnterkey.
Nowwheninstallingourpackagewecanusethe--saveoptiontosavechalkasadependency,asshown:
[~/src/examples/example-3]$npminstall--savechalk
Wecanseechalkhasbeenadded:
[~/examples/example-3]$catpackage.json
{
"name":"example-3",
"version":"1.0.0",
"description":"",
"main":"main.js",
"scripts":{
"test":"echo\"Error:notestspecified\"&&exit1"
},
"author":"...",
"license":"ISC",
"dependencies":{
"chalk":"^1.0.0"
}
}
Wecanaddthesedependenciesmanuallybymodifyingpackage.json;thisisthemostcommonmethodtosavedependenciesoninstallation.
![Page 51: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/51.jpg)
Youcanreadmoreaboutthepackagefileat:https://docs.npmjs.com/files/package.json.
Ifyouarecreatingaserveroranapplicationratherthanamodule,youmostlikelywanttofindawaytostartyourprocesswithouthavingtogiveapathtoyourmainfileallthetime;thisiswherethescriptobjectinyourpackage.jsonfilecomesintoplay.
Tosetyourstartupscript,youjustneedtosetthestartpropertyinthescriptsobject,asshown:
"scripts":{
"test":"echo\"Error:notestspecified\"&&exit1",
"start":"nodeserver.js"
}
Now,allweneedtodoisrunnpmstartandthennpmwillrunthestartscriptwehavealreadyspecified.
Wecandefinemorescripts,forexampleifwewantastartscriptforthedevelopmentenvironmentwecanalsodefineadevelopmentproperty;withnon-standardscriptnameshowever,insteadofjustusingnpm<script>,weneedtousenpmrun<script>.Forexample,ifwewanttorunournewdevelopmentscriptwewillhavetousenpmrundevelopment.
npmhasscriptsthataretriggeredatdifferenttimes.Wecandefineapostinstallscriptthatrunsafterwerunnpminstall;wecanusethisifwewanttotriggerapackagemanagertoinstallthemodules(forexample,bower)
Youcanreadmoreaboutthescriptsobjecthere:https://docs.npmjs.com/misc/scripts.
Youneedtodefineapackageifyouareworkinginateamofdeveloperswheretheprojectistobeinstalledondifferentmachines.Ifyouareusingasourcecontroltoolsuchasgit,itisrecommendedthatyouaddthenode_modulesdirectoryintoyourignorefile,asshown:
[~/examples/example-3]$echo"node_modules">.gitignore
[~/examples/example-3]$cat.gitignore
node_modules
![Page 52: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/52.jpg)
![Page 53: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/53.jpg)
SummaryThatwasquick,wasn’tit?WehavecoveredthefundamentalsofNode.js,whichweneedtocontinueonourjourney.
WehavecoveredhoweasyitistoexposeandprotectpublicandprivatecodecomparedtoregularJavaScriptcodeinthebrowser,wheretheglobalscopecangetverypolluted.
Wealsoknowhowtoincludepackagesandcodefromexternalsourcesandhowtoensurethatthepackagesincludedareconsistent.
Asyoucanseethereisahugeecosystemofpackagesinoneofthemanypackagemanagers,suchasnpm,justwaitingforustouseandconsume.
Inthenextchapter,wewillfocusoncreatingasimpleservertoroute,authenticate,andconsumerequests.
![Page 54: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/54.jpg)
![Page 55: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/55.jpg)
Chapter2.SimpleHTTPNowthatwehaveunderstoodthebasics,wecanmoveontosomethingabitmoreuseful.Inthischapter,wewilllookatcreatinganHTTPserverandroutingrequests.WhileworkingwithNode.jsyouwillcomeacrossHTTPveryoften,asserversidescriptingisoneofthecommonusesofNode.js.
Node.jscomeswithabuiltinHTTPserver;allyouneedtodoisrequiretheincludedhttppackageandcreateaserver.Youcanreadmoreaboutthepackageathttps://nodejs.org/api/http.html.
varHttp=require('http');
varserver=Http.createServer();
ThiswillcreateyourveryownHTTPserverthatisreadytoroll.Inthisstate,though,itwon’tbelisteningforanyrequests.Wecanstartlisteningonanyportorsocketwewish,aslongasitisavailable,asshown:
varHttp=require('http');
varserver=Http.createServer();
server.listen(8080,function(){
console.log('Listeningonport8080');
});
Let’ssavetheprecedingcodetoserver.jsandrunit:
[~/examples/example-4]$nodeserver.js
Listeningonport8080
Bynavigatingtohttp://localhost:8080/onyourbrowseryouwillseethattherequesthasbeenacceptedbuttheserverisn’tresponding;thisisbecausewehaven’thandledtherequestsyet,wearejustlisteningforthem.
Whenwecreatetheserverwecanpassacallbackthatwillbecalledeachtimethereisarequest.Theparameterspassedwillbe:request,response.
functionrequestHandler(request,response){
}
varserver=Http.createServer(requestHandler);
Noweachtimewegetarequestwecandosomething:
varcount=0;
functionrequestHandler(request,response){
varmessage;
count+=1;
response.writeHead(201,{
'Content-Type':'text/plain'
});
message='Visitorcount:'+count;
console.log(message);
![Page 56: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/56.jpg)
response.end(message);
}
Let’srunthescriptandrequestthepagefromthebrowser;youshouldseeVisitorcount:1returnedtothebrowser:
[~/examples/example-4]$nodeserver.js
Listeningonport8080
Visitorcount:1
Visitorcount:2
Somethingweirdhashappenedthough:anextrarequestgetsgenerated.Whoisvisitor2?
Thehttp.IncomingMessage(theparameterrequest)exposesafewpropertiesthatcanbeusedtofigurethisout.Thepropertywearemostinterestedinrightnowisurl.Weareexpectingjust/toberequested,solet’saddthistoourmessage:
message='Visitorcount:'+count+',path:'+request.url;
Nowyoucanrunthecodeandseewhat’sgoingon.Youwillnoticethat/favicon.icohasbeenrequestedaswell.IfyouarenotabletoseethisthenyoumustbewonderingwhatIhavebeengoingonaboutorifyourbrowserhasbeentohttp://localhost:8080recentlyandhasacachediconalready.Ifthisisthecase,thenyoucanrequesttheiconmanually,forexamplefromhttp://localhost:8080/favicon.ico:
[~/examples/example-4]$nodeserver.js
Listeningonport8080
Visitorcount:1,path:/
Visitorcount:2,path:/favicon.ico
Wecanalsoseethatifwerequestanyotherpagewewillgetthecorrectpath,asshown:
[~/examples/example-4]$nodeserver.js
Listeningonport8080
Visitorcount:1,path:/
Visitorcount:2,path:/favicon.ico
Visitorcount:3,path:/test
Visitorcount:4,path:/favicon.ico
Visitorcount:5,path:/foo
Visitorcount:6,path:/favicon.ico
Visitorcount:7,path:/bar
Visitorcount:8,path:/favicon.ico
Visitorcount:9,path:/foo/bar/baz/qux/norf
Visitorcount:10,path:/favicon.ico
Thisisn’tthedesiredoutcomethough,foreverythingbutafewrouteswewanttoreturn404:NotFound.
![Page 57: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/57.jpg)
IntroducingroutingRoutingisessentialforalmostallNode.jsservers.First,wewillimplementourownsimpleversionandthenmoveontothemorecomplexrounting.
Wecanimplementourownsimplerouterusingaswitchstatement,suchas:
functionrequestHandler(request,response){
varmessage,
status=200;
count+=1;
switch(request.url){
case'/count':
message=count.toString();
break;
case'/hello':
message='World';
break;
default:
status=404;
message='NotFound';
break;
}
response.writeHead(201,{
'Content-Type':'text/plain'
});
console.log(request.url,status,message);
response.end(message);
}
Let’srunthefollowingexample:
[~/examples/example-4]$nodeserver.js
Listeningonport8080
/foo404NotFound
/bar404NotFound
/world404NotFound
/count2004
/hello200World
/count2006
Youcanseethecountincreasingwitheachrequest;however,itisn’treturnedeachtime.Ifwehaven’tdefinedacasespecificallyforthatroute,wereturn404:NotFound.
ForservicesthatimplementaRESTfulinterface,wewanttobeabletorouterequestsbasedontheHTTPmethodaswell.Therequestobjectexposesthisusingthemethodproperty.
Addingthistothelogwecanseethis:
console.log(request.method,request.url,status,message);
![Page 58: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/58.jpg)
Runtheexampleandexecuteyourrequests,youcanuseaRESTclienttoinvokeaPOSTrequest:
[~/examples/example-4]$nodeserver.js
Listeningonport8080
GET/count2001
POST/count2002
PUT/count2003
DELETE/count2004
Wecanimplementaroutertoroutebasedonamethod,buttherearepackagesthatdothisforusalreadyoutthere.Fornowwewilluseasimplepackagecalledrouter:
[~/examples/example-5]$npminstallrouter
Now,wecandosomemorecomplexroutingofourrequests:
Let’screateasimpleRESTfulinterface.
First,weneedtocreatetheserver,asshown:
/*server.js*/
varHttp=require('http'),
Router=require('router'),
server,
router;
router=newRouter();
server=Http.createServer(function(request,response){
router(request,response,function(error){
if(!error){
response.writeHead(404);
}else{
//Handleerrors
console.log(error.message,error.stack);
response.writeHead(400);
}
response.end('\n');
});
});
server.listen(8080,function(){
console.log('Listeningonport8080');
});
Runningtheservershouldshowthattheserverislistening.
[~/examples/example-5]$nodeserver.js
Listeningonport8080
Wewanttodefineasimpleinterfacetoread,save,anddeletemessages.Wemightwanttoreadindividualmessagesaswellasalistofmessages;thisessentiallydefinesasetofRESTfulendpoints.
RESTstandsforRepresentationalStateTransfer;itisaverysimpleandcommonstyle
![Page 59: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/59.jpg)
usedbymanyHTTPprogramminginterfaces.
Theendpointswewanttodefineare:
HTTPMethod Endpoint Usedto
POST /message Createmessage
GET /message/:id Readmessage
DELETE /message/:id Deletemessage
GET /message Readmultiplemessages
ForeachHTTPmethod,therouterhasamethodtouseformappingaroute.Thisinterfaceisintheformof:
router.<HTTPmethod>(<path>,[...<handler>])
Wecandefinemultiplehandlersforeachroute,butwewillcomebacktothatinamoment.
Wewillgothrougheachroute,createanimplementation,andappendthecodetotheendofserver.js.
Wewanttostoreourmessagessomewhere,andintherealworldwewillstoretheminadatabase;however,forsimplicitywewilluseanarraywithasimplecounter,asshown:
varcounter=0,
messages={};
Ourfirstroutewillbeusedtocreatemessages:
functioncreateMessage(request,response){
varid=counter+=1;
console.log('Createmessage',id);
response.writeHead(201,{
'Content-Type':'text/plain'
});
response.end('Message'+id);
}
router.post('/message',createMessage);
WecanensurethatthisrouteworksbyrunningtheserveranddoingaPOSTrequesttohttp://localhost:8000/message.
[~/examples/example-5]$nodeserver.js
Listeningonport8080
Createmessage1
Createmessage2
Createmessage3
Wecanalsoconfirmthatthecounterisincrementing,astheidincreaseseachtimewemakearequest.Wewilldothistokeepatrackofthecountofmessagesandtogiveauniqueidtoeachmessage.
![Page 60: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/60.jpg)
Nowthatthisisworking,weneedtobeabletoreadthemessagetextandtodothisweneedtobeabletoreadtherequestbodythatwassentbytheclient.Thisiswheremultiplehandlerscomeintoplay.Wecouldtacklethisintwodifferentways,ifwewerereadingthebodyinonlyonerouteorifweweredoingsomeotheractionspecifictoaroute,forinstanceauthorization,wewilladdanadditionalhandlertotheroute,suchas:
router.post('/message',parseBody,createMessage)
Theotherwaywecoulddoitisbyaddingahandlerforallmethodsandroutes;thiswillbeexecutedfirstbeforetheroutehandlers,thesearecommonlyreferredtoasmiddleware.Youcanthinkofhandlersasbeingachainoffunctionswhereeachoneiscallingthenext,onceitisfinishedwithitstasks.Withthisinmindyoushouldnotethattheorderinwhichyouaddahandler,bothmiddlewareandroute,willdictatetheorderofoperations.Thismeansthat,ifweareregisteringahandlerthatisexecutedforallmethods,wemustdothisfirst.
Therouterexposesafunctiontoaddthefollowinghandlers:
router.use(function(request,response,next){
console.log('middlewareexecuted');
//Nullastherewerenoerrors
//Iftherewasanerrorthenwecouldcall`next(error);`
next(null);
});
YoucanaddthiscodejustaboveyourimplementationofcreateMessage:
Onceyouhavedonethat,runtheserverandmakethefollowingrequest:
[~/examples/example-5]$nodeserver.js
Listeningonport8080
middlewareexecuted
Createmessage1
Youcanseethatthemiddlewaregetsexecutedbeforetheroutehandler.
Nowthatweknowhowmiddlewareworks,wecanusethemasfollows:
[~/examples/example-5]$npminstallbody-parser
Replaceourcustommiddlewarewith:
varBodyParser=require('body-parser');
router.use(BodyParser.text());
Atthisstage,wejustwanttoreadallrequestsasplaintext.
NowwecanretrievethemessageincreateMessage:
functioncreateMessage(request,response){
varid=counter+=1,
message=request.body;
console.log('Createmessage',id,message);
messages[id]=message;
response.writeHead(201,{
![Page 61: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/61.jpg)
'Content-Type':'text/plain',
'Location':'/message/'+id
});
response.end(message);
}
Runserver.jsandPOSTacoupleofmessagestohttp://localhost:8080/message;youwillseesomethingsimilartothesemessages:
[~/examples/example-5]$nodeserver.js
Listeningonport8080
Createmessage1Hellofoo
Createmessage2Hellobar
Ifyounotice,youwillseethataheaderreturnswithanewlocationofthemessageanditsid,Ifwerequesthttp://localhost:8080/message/1,thecontentfromthefirstmessageshouldbereturned.
However,thereissomethingdifferentwiththisroute;ithasakeythatisgeneratedeachtimeamessageiscreated.Wedon’twanttosetupanewrouteforeachnewmessageasitwillbehighlyinefficient.Instead,wecreatearoutethatmatchesapattern,suchas/message/:id.ThisisacommonwaytodefineadynamicrouteinNode.js.
Theidpartoftherouteiscalledaparameter.Wecandefineasmanyoftheseaswewantinourrouteandreferthemusingtherequest;forexamplewecanhavearoutesimilarto/user/:id/profile/:attribute.
WiththisinmindwecancreateourreadMessagehandler,asshown:
functionreadMessage(request,response){
varid=request.params.id,
message=messages[id];
console.log('Readmessage',id,message);
response.writeHead(200,{
'Content-Type':'text/plain'
});
response.end(message);
}
router.get('/message/:id',readMessage);
Nowlet’ssavetheprecedingcodeintheserver.jsfileandruntheserver:
[~/examples/example-5]$nodeserver.js
Listeningonport8080
Createmessage1Hellofoo
Readmessage1Hellofoo
Createmessage2Hellobar
Readmessage2Hellobar
Readmessage1Hellofoo
Wecanseeit’sworkingbysendingafewrequeststotheserver.
Deletingmessagesisalmostthesameasreadingthem;butwedon’treturnanythingandnullouttheoriginalmessagevalue:
![Page 62: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/62.jpg)
functiondeleteMessage(request,response){
varid=request.params.id;
console.log('Deletemessage',id);
messages[id]=undefined;
response.writeHead(204,{});
response.end('');
}
router.delete('/message/:id',deleteMessage)
First,runtheserver,thencreate,read,anddeleteamessage,asshown:
[~/examples/example-5]$nodeserver.js
Listeningonport8080
Deletemessage1
Createmessage1Hello
Readmessage1Hello
Deletemessage1
Readmessage1undefined
Thatlooksgood;however,wehaverunintoaproblem.Weshouldn’tbeabletoreadamessageagainafterdeletingit;wewillreturn404inboththereadanddeletehandlersifwecan’tfindamessage.Wecandothisbyaddingthefollowingcodetoourreadanddeletehandlers:
varid=request.params.id,
message=messages[id];
if(typeofmessage!=='string'){
console.log('Messagenotfound',id);
response.writeHead(404);
response.end('\n');
return;
}
Nowlet’ssavetheprecedingcodeintheserver.jsfileandruntheserver:
[~/examples/example-5]$nodeserver.js
Listeningonport8080
Messagenotfound1
Createmessage1Hello
Readmessage1Hello
Lastly,wewanttobeabletoreadallmessagesandreturnalistofallmessagevalues:
functionreadMessages(request,response){
varid,
message,
messageList=[],
messageString;
for(idinmessages){
![Page 63: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/63.jpg)
if(!messages.hasOwnProperty(id)){
continue;
}
message=messages[id];
//Handledeletedmessages
if(typeofmessage!=='string'){
continue;
}
messageList.push(message);
}
console.log('Readmessages',JSON.stringify(
messageList,
null,
''
));
messageString=messageList.join('\n');
response.writeHead(200,{
'Content-Type':'text/plain'
});
response.end(messageString);
}
router.get('/message',readMessages);
Nowlet’ssavetheprecedingcodeintheserver.jsfileandruntheserver:
[~/examples/example-5]$nodeserver.js
Listeningonport8080
Createmessage1Hello1
Createmessage2Hello2
Createmessage3Hello3
Createmessage4Hello4
Createmessage5Hello5
Readmessages[
"Hello1",
"Hello2",
"Hello3",
"Hello4",
"Hello5"
]
Awesome;nowwehaveafullRESTfulinterfacetoreadandwritemessages.But,wedon’twanteveryonetobeabletoreadourmessages;theyshouldbesecureandwealsowanttoknowwhoiscreatingthemessages,wewillcoverthisinthenextchapter.
![Page 64: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/64.jpg)
![Page 65: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/65.jpg)
SummaryNowwehaveeverythingweneedtomakesomeprettycoolservices.WecannowcreateanHTTPfromscratch,routeourrequests,andcreateaRESTfulinterface.
ThiswillhelpyouwiththecreationofcompleteNode.JSservices.Inthenextchapter,wewillcoverauthentication.
![Page 66: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/66.jpg)
![Page 67: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/67.jpg)
Chapter3.AuthenticationWecannowcreateRESTfulAPIs,butwedon’twanteveryonetoaccesseverythingweexpose.Wewanttheroutestobesecureandtobeabletotrackwhoisdoingwhat.
Passportisagreatmoduleandanothermiddlewarethathelpsusauthenticaterequests.
PassportexposesasimpleAPIforproviderstoexpandonandcreatestrategiestoauthenticateusers.Atthetimeofwriting,thereare307officiallysupportedstrategies;however,thereisnoreasonwhyyoucan’twriteyourownstrategyandpublishitforotherstouse.
![Page 68: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/68.jpg)
BasicauthenticationThesimpleststrategyforpassportisthelocalstrategythatacceptsausernameandpassword.
Wewillintroducetheexpressframeworkfortheseexamplesand,nowthatyouknowthebasicsofhowitallworksunderneath,wecanputitalltogether.
Youcaninstallexpress,body-parser,passport,andpassport-local.Expressisabatteries-includedWebframeworkforNode.js,andincludesroutingandtheabilitytousemiddleware:
[~/examples/example-19]$npminstallexpressbody-parserpassportpassport-
local
Fornow,wecanstoreourusersinasimpleobjecttoreferencelater,asshown:
varusers={
foo:{
username:'foo',
password:'bar',
id:1
},
bar:{
username:'bar',
password:'foo',
id:2
}
}
Oncewehaveafewusers,weneedtosetuppassport.Whenwecreateaninstanceofthelocalstrategy,weneedtoprovideaverifycallbackwherewechecktheusernameandpassword,whilereturningauser:
varPassport=require('passport'),
LocalStrategy=require('passport-local').Strategy;
varlocalStrategy=newLocalStrategy({
usernameField:'username',
passwordField:'password'
},
function(username,password,done){
user=users[username];
if(user==null){
returndone(null,false,{message:'Invaliduser'});
}
if(user.password!==password){
returndone(null,false,{message:'Invalidpassword'});
}
done(null,user);
}
![Page 69: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/69.jpg)
)
Theverifycallbackinthiscaseisexpectingdonetobecalledwithauser.Italsoallowsustoprovideinformationiftheuserwasinvalidorthepasswordwaswrong.
Now,thatwehaveastrategywecanpassthistopassport,whichallowsustoreferenceitlateranduseittoauthenticateourrequests,asfollows:
Passport.use('local',localStrategy);
Youcanusemultiplestrategiesperapplicationandreferenceeachonebythenameyoupassed,inthiscase'local'.
Now,let’screateourserver,asshownhere:
varExpress=require('express');
varapp=Express();
Wewillhavetousethebody-parsermiddleware.Thiswillensurethat,whenweposttoourloginroute,wecanreadourbody;wealsoneedtoinitializepassport:
varBodyParser=require('body-parser');
app.use(BodyParser.urlencoded({extended:false}));
app.use(BodyParser.json());
app.use(Passport.initialize());
Tologintoourapplication,weneedtocreateapostroutethatusesauthenticationasoneofthehandlers.Thecodeforthisisasfollows:
app.post(
'/login',
Passport.authenticate('local',{session:false}),
function(request,response){
}
);
Now,whenwesendaPOSTrequestto/logintheserverwillauthenticateourrequests.
Onceauthenticated,theuserpropertywillbepopulatedontherequestobject,asfollows:
app.post(
'/login',
Passport.authenticate('local',{session:false}),
function(request,response){
response.send('UserId'+request.user.id);
}
);
Lastly,weneedtolistenforrequests,aswithalltheotherservers:
app.listen(8080,function(){
console.log('Listeningonport8080');
});
Letsruntheexample:
![Page 70: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/70.jpg)
[~/examples/example-19]$nodeserver.js
Listeningonport8080
Now,wecanauthenticateuserswhenwesendaPOSTrequestatourserver.Iftheuserhasn’tpassedboththeusernameandpasswordtheserverwillreturn400BadRequest.
TipIfyouaren’tfamiliarwithcurlyoucoulduseatool,suchasAdvancedRESTClient:
https://chromerestclient.appspot.com/
InthefollowingexamplesIwillbeusingthecommandlineinterfacecurl.
WecanexecutealoginrequestbyexecutingaPOSTto/logincommand:
[~]$curl-XPOSThttp://localhost:8080/login-v
<HTTP/1.1400BadRequest
Iftheuserprovidesthewrongdetailsthen401Unauthorizedwillbereturned:
[~]$curl-XPOSThttp://localhost:8080/login\
-H'Content-Type:application/json'\
-d'{"username":"foo","password":"foo"}'\
-v
<HTTP/1.1401Unauthorized
Ifweprovidethecorrectdetailsthenwecanseeourhandlerwascalledandthecorrectdatawasreturned:
[~]$curl-XPOSThttp://localhost:8080/login\
-H'Content-Type:application/json'\
-d'{"username":"foo","password":"bar"}'
UserId1
[~]$curl-XPOSThttp://localhost:8080/login\
-H'Content-Type:application/json'\
-d'{"username":"bar","password":"foo"}'
UserId2
![Page 71: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/71.jpg)
![Page 72: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/72.jpg)
BearertokensNowthatwehaveanauthenticateduser,wecangenerateatokenthatcanbeusedwiththerestofourrequestsratherthanpassingourusernameandpasswordeverywhere.ThisiscommonlyknownasaBearertokenand,conveniently,thereisapassportstrategyforthis.
Forourtokens,wewillusesomethingcalledaJSONWebToken(JWT).JWTallowsustoencodetokensfromJSONobjectsandthendecodethemandverifythem.Thedatastoredinthemisopenandsimpletoread,sopasswordsshouldn’tbestoredinthem;however,itmakesverifyingauserverysimple.Wecanalsoprovidethesetokenswithexpirydates,whichhelpslimittheseverityoftokensbeingexposed.
YoucanreadmoreaboutJWTathttp://jwt.io/.
WecaninstallJWTusingthefollowingcommand:
[~/examples/example-19]$npminstalljsonwebtoken
Onceauserisauthenticated,wecansafelyprovidethemwithatokentouseinfuturerequests:
varJSONWebToken=require('jsonwebtoken'),
Crypto=require('crypto');
vargenerateToken=function(request,response){
//Thepayloadjustcontainstheidoftheuser
//andtheirusername,wecanverifywhethertheclaim
//iscorrectusingJSONWebToken.verify
varpayload={
id:user.id,
username:user.username
};
//Generatearandomstring
//Usuallythiswouldbeanappwideconstant
//Butcanbedonebothways
varsecret=Crypto.randomBytes(128)
.toString('base64');
//Createthetokenwithapayloadandsecret
vartoken=JSONWebToken.sign(payload,secret);
//Theuserisstillreferencingthesameobject
//inusers,sononeedtosetitagain
//Ifwewereusingadatabase,wewouldsave
//ithere
request.user.secret=secret
returntoken;
}
vargenerateTokenHandler=function(request,response){
varuser=request.user;
//Generateourtoken
vartoken=generateToken(user);
![Page 73: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/73.jpg)
//Returntheuseratokentouse
response.send(token);
};
app.post(
'/login',
Passport.authenticate('local',{session:false}),
generateTokenHandler
);
Now,whentheuserlogsintheywillbepresentedwithatokentousethatwecanverify.
LetsrunourNode.jsserver:
[~/examples/example-19]$nodeserver.js
Listeningonport8080
Whenweloginnowwereceiveatoken:
[~]$curl-XPOSThttp://localhost:8080/login\
-H'Content-Type:application/json'\
-d'{"username":"foo","password":"bar"}'
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpZC
I6MSwidXNlcm5hbWUiOiJmb28iLCJpYXQiOjE0MzcyO
TQ3OTV9.iOZO7oCIceZl6YvZqVP9WZLRx-XVvJFMF1p
pPCEsGGs
Wecanenterthisintothedebuggerathttp://jwt.io/andseethecontents,asshown:
{
"id":1,
"username":"foo",
"iat":1437294795
}
Ifwehadthesecretwecouldverifythatthetokeniscorrect.Thesignaturechangeseverytimewerequestatoken:
[~]$curl-XPOSThttp://localhost:8080/login\
-H'Content-Type:application/json'\
-d'{"username":"foo","password":"bar"}'
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpZC
I6MSwidXNlcm5hbWUiOiJmb28iLCJpYXQiOjE0MzcyO
TQ5OTl9.n1eRQVOM9qORTIMUpslH-ycTNEYdLDKa9lU
pmhf44s0
Wecanauthenticateauserusingpassport-bearer;itissetupverysimilartopassport-local.However,ratherthanacceptingausernameandpasswordfromthebody,weacceptabearertoken;thiscanbepassedusingthequerystring,body,ortheAuthorizationheader:
Firstwemustinstallpassport-http-bearer:
[~/examples/example-19]$npminstallpassport-http-bearer
Thelet’screateourverifier.Therearetwosteps:thefirstisensuringthedecodedinformationmatchesouruser,thiswillbewhereweusuallyretrieveouruser;then’once
![Page 74: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/74.jpg)
wehaveauserandit’svalid,wecancheckwhetherthetokenisvalidbasedontheuser’ssecret:
varBearerStrategy=require('passport-http-bearer').Strategy;
varverifyToken=function(token,done){
varpayload=JSONWebToken.decode(token);
varuser=users[payload.username];
//Ifwecan'tfindauser,ortheinformation
//doesn'tmatchthenreturnfalse
if(user==null||
user.id!==payload.id||
user.username!==payload.username){
returndone(null,false);
}
//Ensurethetokenisvalidnowwehaveauser
JSONWebToken.verify(token,user.secret,function(error,decoded){
if(error||decoded==null){
returndone(error,false);
}
returndone(null,user);
});
}
varbearerStrategy=newBearerStrategy(
verifyToken
)
Wecanregisterthisstrategyasthebearersowecanuseitlater:
Passport.use('bearer',bearerStrategy);
Wecancreateasimpleroutewhereweretrieveuserdetailsforanauthenticateduser:
app.get(
'/userinfo',
Passport.authenticate('bearer',{session:false}),
function(request,response){
varuser=request.user;
response.send({
id:user.id,
username:user.username
});
}
);
Let’sruntheNode.jsserver:
[~/examples/example-19]$nodeserver.js
Listeningonport8080
Oncewereceiveatoken:
[~]$curl-XPOSThttp://localhost:8080/login\
-H'Content-Type:application/json'\
-d'{"username":"foo","password":"bar"}'
Wecanusetheresultinourrequests:
![Page 75: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/75.jpg)
[~]$curl-XGEThttp://localhost:8080/userinfo\
-H'Authorization:Bearer<token>'
{"id":1,"username":"foo"}
![Page 76: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/76.jpg)
![Page 77: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/77.jpg)
OAuthOAuthprovidesmanyadvantages;forinstance,itdoesnotneedtodealwiththeactualidentificationofusers.Wecanletusersloginusingservicestheytrust,suchasGoogle,Facebook,orAuth0.
Forthefollowingexamples,IwillbeusingAuth0.Theyprovideafreeaccountforyoutogetup-and-running:https://auth0.com/.
Youwillneedtosignupandcreateanapi(chooseAngularJS+Node.js),thengotoSettingsandtakedownthedomain,clientid,andclientsecret.YouwillneedthesetosetupOAuth.
WecanauthenticateusingOAuthusingpassport-oauth2:
[~/examples/example-19]$npminstall--savepassport-oauth2
Aswithourbearertokens,wewanttovalidatewhattheserverreturns,whichwillbeauserobjectthathasanid.Wewillmatchthiswithauserthatisinourdataorcreateanewuser:
varvalidateOAuth=function(accessToken,refreshToken,profile,done){
varkeys=Object.keys(users),user=null;
for(variKey=0;iKey<keys.length;i+=1){
user=users[key];
if(user.thirdPartyId!==profile.user_id){continue;}
returndone(null,user);
}
users[profile.name]=user={
username:profile.name,
id:keys.length,
thirdPartyId:profile.user_id
}
done(null,user);
};
OncewehaveafunctiontovalidateouruserswecanputtogethertheoptionsforourOAuthstrategy:
varoAuthOptions={
authorizationURL:'https://<domain>.auth0.com/authorize',
tokenURL:'https://<domain>.auth0.com/oauth/token',
clientID:'<clientid>',
clientSecret:'<clientsecret>',
callbackURL:"http://localhost:8080/oauth/callback"
}
Thenwecreateourstrategy,asfollows:
varOAuth2Strategy=require('passport-oauth2').Strategy;
![Page 78: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/78.jpg)
oAuthStrategy=newOAuth2Strategy(oAuthOptions,validateOAuth);
BeforeweuseourstrategyweneedtoducktypethestrategiesuserProfilemethodwithourown,thisissowecanrequesttheuserobjecttouseinvalidateOAuth:
varparseUserProfile=function(done,error,body){
if(error){
returndone(newError('Failedtofetchuserprofile'))
}
varjson;
try{
json=JSON.parse(body);
}catch(error){
returndone(error);
}
done(null,json);
}
vargetUserProfile=function(accessToken,done){
oAuthStrategy._oauth2.get(
"https://<domain>.auth0.com/userinfo",
accessToken,
parseUserProfile.bind(null,done)
)
}
oAuthStrategy.userProfile=getUserProfile
Wecanregisterthisstrategyasoauthsowecanuseitlater:
Passport.use('oauth',oAuthStrategy);
WeneedtocreatetworoutestohandleourOAuthauthentication:oneroutetostarttheflowandtheotherfortheidentificationservertoreturnto:
app.get('/oauth',Passport.authenticate('oauth',{session:false}));
WecanuseourgenerateTokenHandlerhere,asourrequestwillhaveauseronit.
app.get('/oauth/callback',
Passport.authenticate('oauth',{session:false}),
generateTokenHandler
);
Wecannowstartourserverandrequesthttp://localhost:8080/oauth;theserverwillredirectyoutoAuth0.Onceloggedin,youwillreceiveatokenthatyoucanusewith/userinfo.
Ifyouwereusingsessions,youcouldsavetheusertothesessionandredirectthembacktoyourfrontpage(orthedefaultpagesetforaloggedinuser).Forasingle-pageapp,whenusingsomethinglikeAngular,youmaywanttoredirecttheuserwithatokenintheURLfortheclientframeworktograbontoandsave.
![Page 79: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/79.jpg)
![Page 80: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/80.jpg)
SummaryWecannowauthenticateusers;thisisgreataswecannowfigureoutwhothepeopleareandthenlimittheuserstocertainresources.
Inthenextchapterwewillcoverdebugging,wemayneedtouseitifourusersaren’tbeingauthenticated.
![Page 81: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/81.jpg)
![Page 82: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/82.jpg)
Chapter4.DebuggingAtsomepointinyourjourneywithNode.js,itisinevitablethatyouwillhavetodebugsomenastybugs.So,let’sexpectthembeforehandandplanforthatday.
![Page 83: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/83.jpg)
LoggingThereareafewmethodsthatwecanusetodebugoursoftware;thefirstonewearegoingtolookatislogging.Thesimplestwaytologamessageistouseconsole.InmostofthepreviousexamplesconsolehasbeenusedtoportraywhatisgoingonwithoutneedingtoseetheentireHTTPrequestandresponse,thusmakingthingsalotmorereadableandsimple.
Anexampleofthisis:
varHttp=require('http');
Http.createServer(function(request,response){
console.log(
'Receivedrequest',
request.method,
request.url
)
console.log('Returning200');
response.writeHead(200,{'Content-Type':'text/plain'});
response.end('HelloWorld\n');
}).listen(8000);
console.log('Serverrunningonport8000');
Runningthisexamplewilllogrequestsandresponsesontheconsole:
[~/examples/example-6]$nodeserver.js
Serverrunningonport8000
ReceivedrequestGET/
Returning200
ReceivedrequestGET/favicon.ico
Returning200
ReceivedrequestGET/test
Returning200
ReceivedrequestGET/favicon.ico
Returning200
Ifweareusingaframeworkthatacceptsmiddleware,suchasexpress,wecoulduseasimplenpmpackagecalledmorgan;youcanfindthepackageathttps://www.npmjs.com/package/morgan:
[~/examples/example-7]$npminstallmorgan
[~/examples/example-7]$npminstallrouter
Wecanuseitbyusingrequiretobringitintoourcodeandaddingitasmiddleware:
varMorgan=require('morgan'),
Router=require('router'),
Http=require('http');
![Page 84: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/84.jpg)
router=newRouter();
router.use(Morgan('tiny'));
/*Simpleserver*/
Http.createServer(function(request,response){
router(request,response,function(error){
if(!error){
response.writeHead(404);
}else{
//Handleerrors
console.log(error.message,error.stack);
response.writeHead(400);
}
response.end('\n');
});
}).listen(8000);
console.log('Serverrunningonport8000');
functiongetInfo(request,response){
varinfo=process.versions;
info=JSON.stringify(info);
response.writeHead(200,{'Content-Type':'application/json'});
response.end(info);
}
router.get('/info',getInfo);
Whentheserverisrunning,wecanseeeachrequestandresponsewithouthavingtoaddloggingtoeachhandler:
[~/examples/example-7]$nodeserver.js
Serverrunningonport8000
GET/test404--4.492ms
GET/favicon.ico404--2.281ms
GET/info200--1.120ms
GET/info200--1.120ms
GET/test404--0.199ms
GET/info200--0.494ms
GET/test404--0.162ms
Thiskindofloggingisasimplewaytoseewhatisbeingusedontheserverandhowlongeachrequestistaking.Here,youcanseethatthefirstrequeststookthelongestandthentheygotalotfaster.Thedifferenceisonlyof3ms;ifthetimewaslarger,itcouldhavebeenabigproblem.
Wecanincreasetheinformationthat’sloggedbychangingtheformatwepasstomorgan,asshown:
router.use(Morgan('combined'));
Byrunningtheserveryouwillseemoreinformation,suchastheremoteuser,dateandtimeoftherequest,amountofcontentthatwasreturned,andtheclienttheyareusing.
![Page 85: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/85.jpg)
[~/examples/example-7]$nodeserver.js
Serverrunningonport8000
::1--[07/Jun/2015:11:09:03+0000]"GET/infoHTTP/1.1"200-"-""--
REMOVED---"
Timingisdefinitelyanimportantfactorasitcanbehelpfulwhensiftingthroughthemountainsoflogsthatyouwillobtain.Somebugscanbelikeatickingtime-bombwaitingtoexplodeat3AMonaSaturdaynight.Alltheselogsmeannothingtousiftheprocesshasdiedandthelogshavedisappeared.Thereisanotherpopularandusefulpackagecalledbunyan,whichwrapsmanyloggingmethodsintoone.
Bunyanbringstothetabletheadvantageofwriteablestreamstowritelogs,whetheritisafileondiskorstdout.Thisallowsustopersistourlogsforpostmortemdebugging.Youcanfindmoredetailsaboutbunyanathttps://www.npmjs.com/package/bunyan.
Now,let’sinstallthepackage.Wewantitinstalledbothlocallyandgloballysothatwecanalsouseitasacommandlinetool:
[~/examples/example-8]$npminstall–gbunyan
[~/examples/example-8]$npminstallbunyan
Now,letsdosomelogging:
varBunyan=require('bunyan'),
logger;
logger=Bunyan.createLogger({
name:'example-8'
});
logger.info('Hellologging');
Runningourexample:
[~/examples/example-8]$nodeindex.js
{"name":"example-
8","hostname":"macbook.local","pid":2483,"level":30,"msg":"Hello
logging","time":"2015-06-07T11:35:13.973Z","v":0}
Thisdoesn’tlookverypretty,doesit?BunyanusesasimplestructuredJSONstringtosavemessages;thismakesiteasytoparse,extend,andread.BunyancomeswithaCLIutilitytomakeeverythingniceandpretty.
Ifweruntheexamplewiththeutility,thenwewillseethattheoutputisnicelyformatted:
[~/examples/example-8]$nodeindex.js|bunyan
[2015-06-07T11:38:59.698Z]INFO:example-8/2494onmacbook.local:Hello
logging
Ifweaddafewmorelevels,youwillseeonyourconsolethateachiscoloreddifferentlytohelpusidentifythem:
varBunyan=require('bunyan'),
logger;
logger=Bunyan.createLogger({
name:'example-8'
});
![Page 86: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/86.jpg)
logger.trace('Trace');
logger.debug('Debug');
logger.info('Info');
logger.warn('Warn');
logger.error('Error');
logger.fatal('Fatal');
logger.fatal('Wegotafatal,letsexit');
process.exit(1);
Let’sruntheexample:
[~/examples/example-8]$nodeindex.js|bunyan
[2015-06-07T11:39:55.801Z]INFO:example-8/2512onmacbook.local:Info
[2015-06-07T11:39:55.811Z]WARN:example-8/2512onmacbook.local:Warn
[2015-06-07T11:39:55.814Z]ERROR:example-8/2512onmacbook.local:Error
[2015-06-07T11:39:55.814Z]FATAL:example-8/2512onmacbook.local:Fatal
[2015-06-07T11:39:55.814Z]FATAL:example-8/2512onmacbook.local:Wegota
fatal,letsexit
Ifyounotice,traceanddebugweren’toutputtedontheconsole.Thisisbecausetheyareusedtofollowtheflowoftheprogramratherthanthekeyinformationandareusuallyverynoisy.
Wecanchangetheleveloflogswewanttoseebypassingthisasanoptionwhenwecreatethelogger:
logger=Bunyan.createLogger({
name:'example-8',
level:Bunyan.TRACE
});
Now,whenweruntheexample:
[~/examples/example-8]$nodeindex.js|bunyan
[2015-06-07T11:55:40.175Z]TRACE:example-8/2621onmacbook.local:Trace
[2015-06-07T11:55:40.177Z]DEBUG:example-8/2621onmacbook.local:Debug
[2015-06-07T11:55:40.178Z]INFO:example-8/2621onmacbook.local:Info
[2015-06-07T11:55:40.178Z]WARN:example-8/2621onmacbook.local:Warn
[2015-06-07T11:55:40.178Z]ERROR:example-8/2621onmacbook.local:Error
[2015-06-07T11:55:40.178Z]FATAL:example-8/2621onmacbook.local:Fatal
[2015-06-07T11:55:40.178Z]FATAL:example-8/2621onmacbook.local:Wegota
fatal,letsexit
Weusuallydon’twanttoseelogsthatarelowerthantheinfolevel,asanyinformationthatisusefulforpost-mortemdebuggingshouldhavebeenloggedusingtheinfoorhigher.
Bunyan’sapiisgoodforthefunctionofloggingerrorsandobjects.ItsavesthecorrectstructuresinitsJSONoutput,whichisreadyfordisplay:
try{
ref.go();
}catch(error){
logger.error(error);
}
Let’sruntheexample:
![Page 87: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/87.jpg)
[~/examples/example-9]$nodeindex.js|bunyan
[2015-06-07T12:00:38.700Z]ERROR:example-9/2635onmacbook.local:refis
notdefined
ReferenceError:refisnotdefined
atObject.<anonymous>(~/examples/example-8/index.js:9:2)
atModule._compile(module.js:460:26)
atObject.Module._extensions..js(module.js:478:10)
atModule.load(module.js:355:32)
atFunction.Module._load(module.js:310:12)
atFunction.Module.runMain(module.js:501:10)
atstartup(node.js:129:16)
atnode.js:814:3
Ifwelookattheexampleandpretty-printit,wewillseethattheysaveitasanerror:
[~/examples/example-9]$npminstall-gprettyjson
[~/examples/example-9]$nodeindex.js|prettyjson
name:example-9
hostname:macbook.local
pid:2650
level:50
err:
message:refisnotdefined
name:ReferenceError
stack:
"""
ReferenceError:refisnotdefined
atObject.<anonymous>(~/examples/example-8/index.js:9:2)
atModule._compile(module.js:460:26)
atObject.Module._extensions..js(module.js:478:10)
atModule.load(module.js:355:32)
atFunction.Module._load(module.js:310:12)
atFunction.Module.runMain(module.js:501:10)
atstartup(node.js:129:16)
atnode.js:814:3
"""
msg:refisnotdefined
time:2015-06-07T12:02:33.875Z
v:0
Thisisusefulbecause,ifyoujustloganerror,youwilleithergetanemptyobjectifyouusedJSON.stringifyorjustthemessageifyouusedtoString:
try{
ref.go();
}catch(error){
console.log(JSON.stringify(error));
console.log(error);
console.log({
message:error.message
name:error.name
stack:error.stack
});
}
Let’sruntheexample:
![Page 88: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/88.jpg)
[~/examples/example-10]$nodeindex.js
{}
[ReferenceError:refisnotdefined]
{message:'refisnotdefined',
name:'ReferenceError',
stack:'--REMOVED--'}
Itistolotsimplerandcleanertouselogger.error(error)thanlogger.error({message:error.message/*,...*/});.
Asmentionedearlier,bunyanusestheconceptofstreams,whichmeansthatwecanwritetoafile,stdout,oranyotherservicewewishtoextendto.
Towritetoafile,allweneedtodoisaddittotheoptionspassedtobunyanatsetup:
varBunyan=require('bunyan'),
logger;
logger=Bunyan.createLogger({
name:'example-11',
streams:[
{
level:Bunyan.INFO,
path:'./log.log'
}
]
});
logger.info(process.versions);
logger.info('Applicationstarted');
Byrunningtheexample,youwon’tseeanylogsbeingoutputtedtotheconsolebuttheywillbewrittentofileinstead:
[~/examples/example-11]$nodeindex.js
Ifyoulistwhat’sinthedirectoryyouwillseeanewfilehasbeencreated:
[~/examples/example-11]$ls
index.jslog.lognode_modules
Ifyoureadwhat’sinthefileyouwillseethatthelogshavealreadybeenwritten:
[~/examples/example-11]$catlog.log
{"name":"example-
11","hostname":"macbook.local","pid":3614,"level":30,"http_parser":"2.3","n
ode":"0.12.2","v8":"3.28.73","uv":"1.4.2-
node1","zlib":"1.2.8","modules":"14","openssl":"1.0.1m","msg":"","time":"20
15-06-07T12:29:46.606Z","v":0}
{"name":"example-
11","hostname":"macbook.local","pid":3614,"level":30,"msg":"Application
started","time":"2015-06-07T12:29:46.608Z","v":0}
Wecanrunthisthroughbunyaninordertoprintitoutnicely:
[~/examples/example-11]$catlog.log|bunyan
[~/examples/example-11]$catlog.log|bunyan
[2015-06-07T12:29:46.606Z]INFO:example-11/3614onmacbook.local:
![Page 89: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/89.jpg)
(http_parser=2.3,node=0.12.2,v8=3.28.73,uv=1.4.2-node1,zlib=1.2.8,
modules=14,openssl=1.0.1m)
[2015-06-07T12:29:46.608Z]INFO:example-11/3614onmacbook.local:
Applicationstarted
Nowthatwecanlogtoafile,wealsowanttobeabletoseethemessagesastheyaredisplayed.Ifwewerejustloggingtoafile,wecoulduse:
[~/examples/example-11]$tail-flog.log|bunyan
Thiswilllogtostdoutasthefileitisbeingwrittento;alternativelywecouldjustaddanotherstreamtobunyan:
logger=Bunyan.createLogger({
name:'example-11',
streams:[
{
level:Bunyan.INFO,
path:'./log.log'
},
{
level:Bunyan.INFO,
stream:process.stdout
}
]
});
Runningtheexamplewilldisplaythelogstotheconsole:
[~/examples/example-11]$nodeindex.js|bunyan
[2015-06-07T12:37:19.857Z]INFO:example-11/3695onmacbook.local:
(http_parser=2.3,node=0.12.2,v8=3.28.73,uv=1.4.2-node1,zlib=1.2.8,
modules=14,openssl=1.0.1m)[2015-06-07T12:37:19.860Z]INFO:example-
11/3695onmacbook.local:Applicationstarted
Wecanalsoseethelogshavebeenappendedtothefile:
[~/examples/example-11]$catlog.log|bunyan
[2015-06-07T12:29:46.606Z]INFO:example-11/3614onmacbook.local:
(http_parser=2.3,node=0.12.2,v8=3.28.73,uv=1.4.2-node1,zlib=1.2.8,
modules=14,openssl=1.0.1m)
[2015-06-07T12:29:46.608Z]INFO:example-11/3614onmacbook.local:
Applicationstarted
[2015-06-07T12:37:19.857Z]INFO:example-11/3695onmacbook.local:
(http_parser=2.3,node=0.12.2,v8=3.28.73,uv=1.4.2-node1,zlib=1.2.8,
modules=14,openssl=1.0.1m)
[2015-06-07T12:37:19.860Z]INFO:example-11/3695onmacbook.local:
Applicationstarted
Great,nowwehavetheloggingdown,whatshallwedowithit?
Well,ithelpstoknowwhereourerrorsareoccurringanditstartstogetreallymessywhenyouhavelotsofanonymousfunctionsaroundtheplace.IfyounoticedintheexamplesthatcoveranHTTPserver,themajorityofthefunctionswerenamed.Thisisveryhelpfulintrackingdownerrorswhencallbacksareinvolved.
Let’slookatthisexample:
![Page 90: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/90.jpg)
try{
a=function(callback){
returnfunction(){
callback();
};
};
b=function(callback){
returnfunction(){
callback();
}
};
c=function(callback){
returnfunction(){
thrownewError("I'mjustmessingwithyou");
};
};
a(b(c()))();
}catch(error){
logger.error(error);
}
Itmightlookabitmessyandthat’sbecauseitis.Let’srunthefollowingexample:
[~/examples/example-12]$nodeindex.js|bunyan
[2015-06-07T12:51:11.665Z]ERROR:example-12/4158onmacbook.local:I'm
justmessingwithyou
Error:I'mjustmessingwithyou
at/Users/fabian/examples/example-12/index.js:19:10
at/Users/fabian/examples/example-12/index.js:14:4
at/Users/fabian/examples/example-12/index.js:9:4
atObject.<anonymous>(/Users/fabian/examples/example-
12/index.js:22:16)
atModule._compile(module.js:460:26)
atObject.Module._extensions..js(module.js:478:10)
atModule.load(module.js:355:32)
atFunction.Module._load(module.js:310:12)
atFunction.Module.runMain(module.js:501:10)
atstartup(node.js:129:16)
Youcanseethattherearenofunctionnamesinourcodeandalsothereisnonaminginthestacktraceunlikethefirstfewfunctions.InNode.js,thenamingoffunctionswillcomefromeitherthevariablenameortheactualfunctionname.Forexample,ifyouuseCls.prototype.functhenthenamewillbeCls.funcbutifyouusethefunctionfuncthenthenamewillbefunc.
Youcanseethatthereisaslightbenefitherebutthisbecomesveryusefulonceyoustartusingpatternsinvolvingasynccallbacks:
[~/examples/example-13]$npminstallq
Let’sthrowanerrorinacallback:
varQ=require('q');
Q()
.then(function(){
![Page 91: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/91.jpg)
//Promisedreturnedfromanotherfunction
returnQ()
.then(function(){
thrownewError('Helloerrors');
});
})
.fail(function(error){
logger.error(error);
});
Runningourexamplegivesus:
[~/examples/example-13]$nodeindex.js|bunyan
[2015-06-07T13:03:57.047Z]ERROR:example-13/4598onmacbook.local:Hello
errors
Error:Helloerrors
at/Users/fabian/examples/example-13/index.js:12:9
at_fulfilled(/Users/fabian/examples/example-
13/node_modules/q/q.js:834:54)
Thisiswhereitstartstogetdifficulttoread;assigningsimplenamestoourfunctionscanhelpusfindwheretheerroriscomingfrom:
returnQ()
.then(functionresultFromOtherFunction(){
thrownewError('Helloerrors');
});
Runningtheexample:
[~/examples/example-13]$nodeindex.js|bunyan
[2015-06-07T13:04:45.598Z]ERROR:example-13/4614onmacbook.local:Hello
errors
Error:Helloerrors
atresultFromOtherFunction(/Users/fabian/examples/example-
13/index.js:12:9)
at_fulfilled(/Users/fabian/examples/example-
13/node_modules/q/q.js:834:54)
![Page 92: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/92.jpg)
![Page 93: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/93.jpg)
ErrorhandlingAnotheraspectofdebuggingishandlingandexpectingerrorsbeforehand.Therearethreewaysinwhichwecanhandleourerrors:
asimpletry/catchcatchingthemattheprocesslevelcatchingerrorsonthedomainlevel
Atry/catchfunctionwillbesufficientifweexpectanerrortooccurandwewillbeabletocontinuewithoutknowingtheresultofwhateverwasbeingexecuted,orwecouldhandleandreturntheerror,asshown:
functionparseJSONAndUse(input){
varjson=null;
try{
json=JSON.parse(input);
}catch(error){
returnQ.reject(newError("Couldn'tparseJSON"));
}
returnQ(use(json));
}
Anothersimplewaytocatcherrorsistoaddanerrorhandlertoyourprocess;anyerrorsthatarecaughtatthislevelareusuallyfatalandshouldbetreatedassuch.Anexitoftheprocessshouldfollowandyoushouldbeusingapackage,suchasforeverorpm2:
process.on('uncaughtException',functionerrorProcessHandler(error){
logger.fatal(error);
logger.fatal('Fatalerrorencountered,exitingnow');
process.exit(1);
});
Youshouldalwaysexittheprocessfollowinganuncaughterror.Thefactthatitisuncaughtmeansthatyourapplicationisinanunknownstatewhereanythingcanhappen.Forexample,therecouldhavebeenanerrorinyourHTTProuterandnomorerequestscanberoutedtothecorrecthandlers.Youcanreadmoreaboutthisathttps://nodejs.org/api/process.html#process_event_uncaughtexception.
Abetterwaytohandleerrorsonagloballevelisusingdomain.Withdomainsyoucanalmostsandboxagroupofasynchronouscodetogether.
Let’sthinkinthecontextofarequesttoourserver.Wemakearequest,readfromadatabase,makecallstoexternalservices,writebacktoadatabase,dosomelogging,dosomebusinesslogic,andweexpectperfectdatacomingfromexternalsourcesallaroundthecode.However,intherealworlditisn’talwayssoandwecan’thandleeveryerrorthatcouldpossiblyoccur;moreover,wedon’twanttotakedownourentireserverjustbecauseofoneerrorforaveryspecificrequest.That’swhereweneeddomains.
Let’slookatthefollowingexample:
varDomain=require('domain'),
![Page 94: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/94.jpg)
domain;
domain=Domain.create();
domain.on('error',function(error){
console.log('Domainerror',error.message);
});
domain.run(function(){
//Runcodeinsidedomain
console.log(process.domain===domain);
thrownewError('Errorhappened');
});
Let’srunthecode:
[~/examples/example-14]$nodeindex.js
true
DomainerrorErrorhappened
Thereisaproblemwiththiscode;however,aswearerunningthissynchronouslywearestillputtingtheprocessintoabrokenstate.Thisisbecausetheerrorbubbleduptothenodeitselfandthenwaspassedtotheactivedomain.
Whenwearecreatingthedomaininanasynchronouscallback,wecanbesurethattheprocesscancontinue.Wecanmimicthisbyusingprocess.nextTick:
process.nextTick(function(){
domain.run(function(){
thrownewError('Errorhappened');
});
console.log("Iwon'texecute");
});
process.nextTick(function(){
console.log('Nexttickhappend!');
});
console.log('Ihappenedbeforeeverythingelse');
Runningtheexampleshoulddisplaythecorrectlogs:
[~/examples/example-15]$nodeindex.js
Ihappenedbeforeeverythingelse
DomainerrorErrorhappened
Nexttickhappend!
![Page 95: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/95.jpg)
![Page 96: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/96.jpg)
SummaryInthischapterwehavecoveredafewpost-mortemdebuggingmethodstohelpusuncoverbugsincludinglogging,namingpractices,andsufficienterrorhandling.
Inthenextchapter,wewillcoverconfigurationofourapplications.
![Page 97: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/97.jpg)
![Page 98: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/98.jpg)
Chapter5.ConfigurationAsourapplicationsgetlargerandlarger,westarttolosesightofwhatisconfiguredtodowhat;wemayalsogetintoasituationwherewehavecoderunningin12differentplaces,eachneedingabitofcodethathastobechangedtodosomethingelse,forexampleconnectingtoadifferentdatabase.Then,foreachofthose12environments,wehavethreeversions:production,staging,anddevelopment.Allofasudden,itgetsverycomplicated.Thisiswhyweneedtobeabletoconfigureourcodefromahigher-levelsothatwedon’tbreakanythingintheprocess.
![Page 99: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/99.jpg)
JSONfilesThereareafewwaysinwhichwecanconfigureourapplication.ThefirstwaythatwewilllookatisasimpleJSONfile.
Ifwelookattheextensionsrequiresupportsbydefault,wecanseethatwecanimportJSONrightintoourcode,asshown:
[~/examples/example-16]$node
>require.extensions
{'.js':[Function],
'.json':[Function],
'.node':[Function:dlopen]}
Let’screateasimpleserverwithaconfigurationfileratherthanahardcodedfile:
First,wehavetocreatetheconfigurationfile:
{
"host":"localhost",
"port":8000
}
Withthis,wecannowcreateourserver:
varConfig=require('./config.json'),
Http=require('http');
Http.createServer(function(request,response){
}).listen(Config.port,Config.host,function(){
console.log('Listeningonport',Config.port,'andhost',Config.host);
});
Now,wecanjustchangetheconfigfileinsteadofchangingthecodetochangetheportonwhichourserverisrunning.
Butourconfigfileisabittoogeneric;wehavenoideaastowhatisahostoraportandwhattheyarerelatedto.
Whileconfiguring,thekeysneedtobelessgenericsothatweknowwhattheyarebeingusedfor,unlessthecontextisgivendirectlybytheapplication.Forexample,iftheapplicationwastoservepurelystaticcontentthenitmaybeacceptabletohavemoregenerickeys.
Tomaketheseconfigurationkeyslessgeneric,wecanwrapthemallinaserverobject:
{
"server":{
"host":"localhost",
"port":8000
}
}
Sonow,inordertoknowabouttheportoftheserverweneedtousethefollowingcode:
![Page 100: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/100.jpg)
Config.server.port
Anexamplewherethiswillbeusefulcouldbeforaserverthatconnectstoadatabase,astheycanacceptboththeportandhostastheparameters:
{
"server":{
"host":"localhost",
"port":8000
},
"database":{
"host":"db1.example.com",
"port":27017
}
}
![Page 101: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/101.jpg)
![Page 102: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/102.jpg)
EnvironmentalvariablesAnotherwayinwhichwecanconfigureourapplicationsisthroughtheuseofenvironmentalvariables.
Thesecanbedefinedbytheenvironmentyouarerunningyourapplicationinorinthecommandthatyouareusingtostartyourprocesswith.
InNode.js,youcanaccesstheenvironmentalvariablesusingprocess.env.Whenusingenv,youdon’twanttobepollutingthisspacetoomuchandsoitisagoodideatoprefixthekeywithsomethingrelatedtoyourself—yourprogramorcompany.Forexample,Config.server.hostbecomesprocess.env.NAME_SERVER_HOST;thereasonforthisisthatwecanclearlyseewhatisrelatedtoyourprogramandwhatisn’t.
Usingenvironmentalvariablestoconfigureourserver,ourcodewilllookasfollows:
varHttp=require('http'),
server_port,
server_host;
server_port=parseInt(process.env.FOO_SERVER_PORT,10);
server_host=process.env.FOO_SERVER_HOST;
Http.createServer(function(request,response){
}).listen(server_port,server_host,function(){
console.log('Listeningonport',server_port,'andhost',server_host);
});
Torunthiscodewithourvariables,wewilluse:
[~/examples/example-17]$FOO_SERVER_PORT=8001\
FOO_SERVER_HOST=localhostnodeserver.js
Listeningonport8001andhostlocalhost
YouprobablynoticedthatIhadtouseparseIntforFOO_SERVER_PORT;thisisbecauseallvariablespassedinthismannerareessentiallystrings.Wecanseethisbyexecutingtypeofprocess.env.FOO_ENV:
[~/examples/example-17]$FOO_ENV=1234node
>typeofprocess.env.FOO_ENV
'string'
>typeofparseInt(process.env.FOO_ENV,10)
'number'
Althoughthiskindofconfigurationisverysimpletocreateandconsume,itmaynotbethebestmethod,asthevariablesarehardtokeeptrackofiftherearealotofthemandtheycanbedroppedveryeasily.
![Page 103: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/103.jpg)
![Page 104: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/104.jpg)
ArgumentsAnotherwayinwhichtheconfigurationcanbedoneisthroughtheuseofargumentsthatarepassedtoNode.jsastheprocessstarts,youcanaccesstheseusingprocess.argv,withargvstandingforargumentvector.
Thearraythatprocess.argvreturnswillalwayshaveanodeatindex0.Forexample,ifyourunnodeserver.jsthenprocess.argvwillhavethevalueof['node','/example/server.js'].
IfyoupassanargumenttoNode.jsthenitwillbeaddedtotheendofprocess.argv.
Ifyourunnodeserver.js--port=8001,theprocess.argvwillcontain['node','/example/server.js','--port=8001'],prettysimple,right?
Eventhoughwecanhaveallthisconfiguration,weshouldalwaysrememberthatconfigurationcanbesimplyexcludedandwewillstillwantourapplicationtorunwhenthishappens.Usually,youshouldprovidedefaulthardcodedvaluesasabackupwhenyouhaveconfigurationoptions.
Parameterssuchaspasswordsandprivatekeysshouldneverhaveadefaultvaluebutlinksandoptionsthatareusuallystandardshouldbegivendefaults.ItisprettyeasytogiveadefaultvalueinNode.js,allyouneedtodoisusetheORoperator.
value=value||'default';
Essentially,whatthisdoesischeckifthevalueisfalsy;ifitis,thenusethedefaultvalue.Youneedtowatchoutforvaluesthatyouknowcouldbefalsy,booleansandnumbersdefinitelyfallintothiscategory.
Inthesecasesyoucanuseanifstatementcheckingforanullvalue,asshown:
if(value==null)value=1
![Page 105: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/105.jpg)
![Page 106: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/106.jpg)
SummaryThat’sallforconfiguration.Inthischapteryoulearnedaboutthethreemethodsthatyoucanusetocreateadynamicapplication.Welearnedthatweshouldnameourconfigurationkeysinawaythatwecanidentifywhatthevaluesarechangingtoandhowtheywillaffectourapplication.Wealsolearnedabouthowwecanpasssimpleargumentstoourapplicationusingenvironmentalvariablesandargv.
Withthisinformation,wecanmoveforwardtoconnectingandutilizingdatabasesinthenextchapter.
![Page 107: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/107.jpg)
![Page 108: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/108.jpg)
Chapter6.LevelDBandNoSQLInthischapter,wewillcovertwovariationsofdatabasesthatcanbeusedwithNode.js;oneprovidesaverylightweightandsimplesetoffeatures,whiletheothergivesusmoreflexibilityandageneral-purposesetoffeatures.Inthischapter,wearegoingtocoverLevelDBandMongoDB
![Page 109: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/109.jpg)
LevelDBOneofthegreatthingswithNode.jsisthatweusethesamelanguageforboththefrontandbackendandthesamegoesforNoSQLdatabases.ThemajorityofthemsupportJSONrightoffthemark;thisisgreatforanyoneusingNode.jsasthereisnotimespentinmakingarelationalmodel,turningitintoaJSON-likestructure,passingittothebrowser,doingsomethingwithit,andreversingtheprocess.
WithadatabasethatsupportsJSONnatively,youcangetrightdowntobusinessandplayball.
GooglehasprovideduswithasimplehookintoaNoSQLdatabasethatcanbeinstalledandcanbemadereadytousewithjustonecommand:
[~/examples/example-18]$npminstalllevel
YouwillseethatthiswillinstallbothLevelDOWNandLevelUP.
LevelDOWNisthelow-levelbindingtoLevelDBandLevelUPisthesimplewrapperaroundthis.
LevelDBisverysimpleintermsofsetup.Onceitisinstalled,wejustcreateaninstanceofLevelUPandpassitwherewewantourdatabasetobestored:
varLevelUP=require('level'),
db=newLevelUP('./example-db');
Nowwehaveafastandsimplewaytostoredata.
AsLevelDBisjustasimplekey/valuestore,itdefaultstostringkeysandstringvalues.Thisisusefulifthat’salltheinformationyouwishtostore.Youcanalsouseitasasimplecachestore.IthasaverysimpleAPI,atthisstageweareonlygoingtofocusonfourmethods:put,get,del,andcreateReadStream;it’sprettyobviouswhatmostofthemdo:
Method Usedfor Arguments
put insertingpairs key,value,callback(error)
get fetchingpairs key,callback(error,value)
del deletingpairs key,callback(error)
createReadStream fetchingmanypairs
Toinsertdataoncewehavecreatedourdatabase,allweneedtodois:
db.put('key','value',function(error){
if(error)returnconsole.log('Error!',error)
db.get('key',function(error,value){
if(error)returnconsole.log('Error!',error)
console.log("key=",value)
![Page 110: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/110.jpg)
});
});
Ifwerunthecode,wewillseethatweinsertedandretrievedourvalue:
[~/examples/example-18]$nodeindex.js
key=value
Thisisn’toursimpleJSONstructure;however,it’sjustastring.TogetourstoretosaveJSON,allweneedtodoistopassthevalueencodingasanoptiontothedatabase,asshown:
varLevelUP=require('level'),
db=newLevelUP('./example-db',{
valueEncoding:'json'
});
NowwecanstoreJSONdata:
db.put('jsonKey',{inner:'value'},function(error){
if(error)returnconsole.log('Error!',error)
db.get('jsonKey',function(error,value){
if(error)returnconsole.log('Error!',error)
console.log("jsonKey=",value)
});
});
However,astringcanbestoredasJSONandwecanstillpassstringsasavalueandalsoretrieveitassuch.
Runningthisexamplewillshowthefollowing:
[~/examples/example-18]$nodeindex.js
key=value
jsonKey={inner:'value'}
Now,wehavethesimplemethodsdownandwecannowmoveontocreateReadStream.
ThisfunctionreturnsanobjectthatcanbecomparedtoNode.jsbuiltinReadableStream.Foreachkey/valuepairinourdatabase,itwillemitadataevent;italsoemitsotherevents,suchaserrorandend.Iferrordoesn’thaveaneventlistener,thenitwillpropagate,therebykillingyourentireprocess(ordomain),asshown:
db.put('key1',{inner:'value'},function(error){
if(error)returnconsole.log('Error!',error)
varstream=db.createReadStream();
stream
.on('data',function(pair){
console.log(pair.key,"=",pair.value);
})
.on('error',function(error){
console.log(error);
})
![Page 111: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/111.jpg)
.on('end',function(){
console.log('end');
});
});
Runningthisexample:
[~/examples/example-20]$nodeindex.js
key1={inner:'value'}
end
Ifweputmoredatainthedatabasewewillhavemultipledataeventsemitted:
[~/examples/example-20]$nodeindex.js
key1={inner:'value'}
key2={inner:'value'}
end
![Page 112: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/112.jpg)
![Page 113: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/113.jpg)
MongoDBAsyoucansee,databaseswithNode.jscanbeverysimple.IfwewantsomethingabitmorecompletewecanuseanotherNoSQLdatabasecalledMongoDB–anotherverypopulardocument-baseddatabase.
Forthissetofexamples,youcaneitheruseahosteddatabaseusingaprovidersuchasMongoLab(theyprovideafreetierfordevelopment)oryoucansetupadatabaselocallyfollowingtheinstructionsathttp://docs.mongodb.org/manual/installation.
Wecancontinueonceyouhaveadatabasetoconnectto.
MongoDBhasseveralmodulesthatcanbeusedwithNode.js,themostpopularoneisMongoose;however,wewillbeusingthecoreMongoDBmodule:
[~/examples/example-21]$npminstallmongodb
Touseourdatabase,wefirstneedtoconnecttoit.Weneedtoprovidetheclientwithaconnectionstring,agenericURIwiththeprotocolofmongodb.
Ifyouhavealocalmongodatabaserunningwithnocredentialsyouwilluse:
mongodb://localhost:27017/database
Thedefaultportis27017,soyoudon’tneedtospecifythat;however,itisincludedforcompleteness.
IfyouareusingMongoLab,theywillprovideyouwithaconnectionstring;itshouldbeintheformatof:
mongodb://<dbuser>:<dbpassword>@<ds>.mongolab.com:<port>/<db>
Connectingtoourdatabaseisactuallyprettysimple.Allweneedtodoisprovidethedriverwithaconnectionstringandwegetbackadatabase:
varMongoDB=require('mongodb'),
MongoClient=MongoDB.MongoClient;
connection="mongodb://localhost:27017/database"
MongoClient.connect(connection,function(error,db){
if(error)returnconsole.log(error);
console.log('Wehaveaconnection!');
});
EachsetofdatainMongoDBisstoredinacollection.Oncewehaveadatabasewecanfetchacollectiontoruntheoperationson:
varcollection=db.collection('collection_name');
Inacollection,wehaveafewsimplemethodsthatholdlotsofpower,givingusafullCRUD“API”.
EachdocumentinMongoDBhasanid,whichisaninstanceofObjectId.Theproperty
![Page 114: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/114.jpg)
theyuseforthisidis_id.
Tosaveadocumentwejustneedtocallsave,itacceptsanobjectoranarrayofobjects.Asingleobjectinacollectionisreferredtoasadocument:
vardoc={
key:'value_1'
};
collection.save(doc,{w:1},function(){
console.log('Documentsaved')
});
IfwecallthesavefunctionwithadocumentthathasanIDthenthedocumentwillbeupdatedratherthaninserted:
varObjectId=MongoDB.ObjectId
//Thisdocumentalreadyexistsinmydatabase
vardoc_id={
_id:newObjectId("55b4b1ffa31f48c6fa33a62a"),
key:'value_2'
};
collection.save(doc_id,{w:1},function(){
console.log('DocumentwithIDsaved');
});
Nowthatwehavedocumentsinourdatabase,wecanqueryforthem,asshown:
collection.find().toArray(function(error,result){
console.log(result.length+"documentsinourdatabase!")
});
Ifnocallbackisprovidedtofindthenitwillreturnacursor;thisallowsustousemethodssuchaslimit,sort,andtoArray.
Youcanpassaquerytofindtolimitwhatisreturned.InordertofindanobjectbyitsIDweneedtousesomething,suchas:
collection.find(
{_id:newObjectId("55b4b1ffa31f48c6fa33a62a")},
function(error,documents){
console.log('Founddocument',documents[0]);
}
);
Wecanalsofilteritbyanyotherpropertyyoumightuse:
collection.find(
{key:'value'},
function(error,documents){
console.log('Found',documents.length,'documents');
}
);
IfyouhaveusedSQLbefore,youmusthavenoticedthelackofoperators,suchasOR,AND,orNOT.However,youdon’tneedtoworrybecausemongoprovidesmanyequivalents.
Youcanseeacompletelisthere:
![Page 115: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/115.jpg)
http://docs.mongodb.org/manual/reference/operator/query/.
Alloperatorsareprefixedwiththedollarsign,forexample$and,$or,$gt,and$lt.
Youcanseethespecificsyntaxtousethesebylookingatthedocumentation.
Tousean$orcondition,youneedtoincludeitasifitisaproperty:
collection.find(
{
$or:[
{key:'value'},
{key:'value_2'}
]
},
function(error,documents){
console.log('Found',documents.length,'documents');
}
);
UsingadatabasesuchasMongoDBgivesusmorepowertoretrieveourdataandcreateamorefeaturefullsoftware.
![Page 116: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/116.jpg)
![Page 117: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/117.jpg)
SummaryNowwehaveplaceswherewecanstoreourdata.Ononeendwehaveasimplekey/valuestorethatprovidesuswithasuper-convenientwaytostoredataandontheotherendwehaveafeaturefulldatabasethatprovidesuswithafullsetofqueryoperators.
Boththesedatabaseswillhelpusinthenextchaptersaswemoveclosertocreatingourfullstackapplication.
InthenextchapterwewillcoverSocket.IO,areal-timecommunicationframeworkbuiltontopofWebSockets.
![Page 118: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/118.jpg)
![Page 119: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/119.jpg)
Chapter7.Socket.IOSimpleHTTPisgreatforthingsthatdon’tneedreal-timedata,butwhataboutwhenweneedtoknowaboutthingsastheyhappen.Forexample,ifwewerecreatingawebsitethathadachatinterfaceorsimilar?
ThisiswhensomethinglikeWebsocketscomeintoplay.WebsocketsareusuallyreferredtoasWebSocketsandarefullduplexortwo-waylow-latencycommunicationchannels.Theyaregenerallyusedbymessagingapplicationsandgameswheremessagesneedtoberelayedbetweentheserverandclient.Thereisareallyhandynpmmodulecalledsocket.io,whichcanaddWebsocketstoanyNode.jsapplication.
Toinstallitwejustneedtorun:
[~/examples/example-27]npminstallsocket.io
Socket.IOcanbesetupverysimplytolistenforconnections.First,wewanttobeabletoserveoutastatichtmlpagetorunclientsidecodewith:
varHttp=require('http'),
FS=require('fs');
varserver=Http.createServer(handler);
server.listen(8080);
functionhandler(request,response){
varindex=FS.readFileSync('index.html');
index=index.toString();
response.writeHead(200,{
'Content-Type':'text/html',
'Content-Length':Buffer.byteLength(index)
});
response.end(index);
}
Now,letscreateanHTMLfileaswell,namedindex.html,inthesamedirectory:
<html>
<head>
<title>WSExample</title>
</head>
<body>
<h2>WSExample</h2>
<pid="output"></p>
<!--SocketIOClientlibrary-->
<scriptsrc="/socket.io/socket.io.js"></script>
<scripttype="application/javascript">
/*Ourclientsidecodewillgohere*/
</script>
</body>
</html>
![Page 120: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/120.jpg)
Let’srunourexampleandensurethatwegetourpage,weshouldbeabletoseeWSExampleonscreen.Now,toaddsocketsupporttoourapplicationwejustneedtorequiresocket.ioandspecifywhathttpservertolistenwithtoIOServer:
varIOServer=require('socket.io');
vario=newIOServer(server);
Now,wheneverthereisanewsocketconnectionover8080wewillgetaconnectioneventonio:
io.on('connection',function(socket){
console.log('NewConnection');
});
Letsaddsomecodetotheclient.Socket.IOprovidesuswithaclientlibraryandtheyexposethisthroughtheendpoint/socket.io/socket.io.js.Thisisincludedintheprecedingindex.htmlfile.
TipAlltheclientsidecodeiscontainedwithinthesecondscripttagoftheindex.htmlfile.
Tocreateaconnectionwiththeserverallweneedtodoiscallio.connectandpassthelocation.Thiswillreturnasocketforuswithwhichwecancommunicatetoourserver.
WeareusingtheclientprovidedbySocket.IOhere,asitwilldetectwhetherWebSocketsareavailable,andifpossibleusethem.Otherwise,itwillutilizeothermethodssuchaspolling,whichmakessurethatitworkseverywhereratherthanjustonevergreenbrowsers:
varsocket=io.connect('http://localhost:8080');
Wewilluseapelementtologmessagestothescreenwith.Wecandothatwiththiscode,thenallweneedtodoiscalllogScreen:
varoutput=document.getElementById('output');
functionlogScreen(text){
vardate=newDate().toISOString();
line=date+""+text+"<br/>";
output.innerHTML=line+output.innerHTML
}
Onceaconnectionismade,justlikeontheserversideaconnectioneventisemitted,wecanlistentothisusingon:
socket.on('connection',function(){
logScreen('Connection!');
});
Now,wecanrunourserveroncewenavigatetohttp://localhost:8080.YoushouldbeabletoseeConnection!showingup:
![Page 121: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/121.jpg)
Toreceiveamessageonserverside,wejustneedtolistenforthemessageevent.Fornow,wewilljustechothemessageback:
socket.on('connection',function(){
socket.on('message',function(message){
socket.send(message);
});
});
Ontheclientside,wejustneedtocallsendtosendamessageandwewanttodothisinsideourconnectionevent.Theapioneachsideisverysimilartoeachother,asyoucansee:
socket.send('Hello');
Ontheclientside,wealsowanttolistenformessagesandlogthemtothescreen:
socket.on('message',logScreen);
Oncewerestarttheserverandrefreshourpage,weshouldbeabletoseeanadditionalHellomessageappearonscreen.
[~/examples/example-27]$nodeindex.js
Hello
Thishappensbecausetheservercannowsendtheclientpacketsofdata.Italsomeansthatwecanupdatetheclientatanytime.Forexample,everysecondwecansendanupdatetotheclient:
socket.on('connection',function(){
functiononTimeout(){
socket.send('Update');
}
setInterval(onTimeout,1000);
});
Now,whenwerestartourserverweshouldbeabletoseeanupdatemessageeverysecond.
Youmighthavenoticedthatyoudidn’tneedtorefreshyourwebpagefortheconnectiontobeopenedagain.Thisisbecausesocket.iotransparentlykeepsourconnections“alive”
![Page 122: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/122.jpg)
aswellasreconnectingifneeded.Thistakesallthepainoutofusingsockets,aswehavenoneofthesetroubles.
![Page 123: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/123.jpg)
RoomsSocket.IOalsohastheconceptofrooms,wheremultipleclientscanbegroupedintodifferentrooms.Toemulatethis,allyouwillneedtodoisnavigatetohttp://localhost:8080inmultipletabs.
Onceaclientconnects,weneedtocallthejoinmethodtotellthesocketwhatroomtobein.Ifwewishtodosomethingsuchasagroupchatwithspecificusersonly,weneedhavearoomidentifierinadatabaseorcreateone.Fornowwewilljusthaveeveryonejointhesameroom:
socket.on('connection',function(){
console.log('NewConnection');
varroom='ourroom';
socket.join(room,function(error){
if(error)returnconsole.log(error);
console.log('Joinedroom!');
});
});
Foreverytabweopen,weshouldseeamessagethatwehavejoinedaroom:
[~/examples/example-27]$nodeindex.js
NewConnection
Joinedroom!
NewConnection
Joinedroom!
NewConnection
Joinedroom
Withthis,wecanbroadcastamessagetotheentireroom.Let’sdothiseverytimesomeonejoins.Withinthejoincallback:
socket
.to(room)
.emit(
'message',
socket.id+'joinedtheroom!'
);
Ifyoulookinyourbrowser,witheachconnectiontheotherclientsgetanotificationthatsomeoneelsehasjoined:
x3OwYOkOCSsa6Qt5AAAFjoinedtheroom!
mlx-Cy1k3szq8W8tAAAEjoinedtheroom!
Connection!
Connecting
Thisisgreat,wecannowcommunicatealmostdirectlybetweenbrowsers!
Ifwewanttoleavearoom,allweneedtodoiscallleave,wewillbroadcastthisbeforewecallthefunction:
socket
![Page 124: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/124.jpg)
.to(room)
.emit(
'message',
socket.id+'isleavingtheroom'
);
socket.leave(room);
Whilerunningthis,youwillnotseeanymessagesfromanotherclientbecauseyouareleavingrightaway:however,ifyouweretoputadelayonthisyoumightseeanotherclientcomeandgo:
leave=function(){
socket
.to(room)
.emit(
'message',
socket.id+'isleavingtheroom'
);
socket.leave(room);
};
setTimeout(leave,2000);
![Page 125: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/125.jpg)
![Page 126: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/126.jpg)
AuthenticationForauthentication,wecanusethesamemethodthatweusedwithourHTTPserverandwecanacceptaJSONWebToken
Intheseexamples,forsimplicitywewilljusthaveasingleHTTProutetologin.WewillsignaJWTthatwewilllaterauthenticatebycheckingthesignature
Weneedtoinstallacoupleofextranpmmodulesforthis;wewillincludechancesothatwecangeneratesomerandomdata.
[~/examples/example-27]npminstallsocketio-jwtjsonwebtokenchance
First,wearegoingtoneedaroutetologin.Wewillmodifyourhandlertowatchfortheurl/login:
if(request.url==='/login'){
returngenerateToken(response)
}
OurnewfunctiongenerateTokenwillcreateaJSONWebTokenwithsomerandomdatausingchance.Wewillalsoneedasecretforourtokens:
varJWT=require('jsonwebtoken'),
Chance=require('chance').Chance();
varjwtSecret='Oursecret';
functiongenerateToken(response){
varpayload={
email:Chance.email(),
name:Chance.first()+''+Chance.last()
}
vartoken=JWT.sign(payload,jwtSecret);
response.writeHead(200,{
'Content-Type':'text/plain',
'Content-Length':Buffer.byteLength(token)
})
response.end(token);
}
Now,wheneverwerequesthttp://localhost:8080/loginwewillreceiveatokenthatwecanuse:
[~]$curl-XGEThttp://localhost:8080/login
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJlbW
joiR2VuZSBGbGVtaW5nIiwiaWF0IjoxNDQxMjcyMjM0
e1Y
Wecanenterthisintothedebuggerathttp://jwt.io/andseethecontents:
{
![Page 127: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/127.jpg)
"email":"[email protected]",
"name":"GeneFleming",
"iat":1441272234
}
Awesome,wehaveatokenandarandomuserbeinggeneratedforus.Now,wecanusethistoauthenticateourusers.Socket.IOhasamethodontheservertodothisandwejustneedtopassahandlertypefunctiontoit.Thisiswheresocketio-jwtcomesin,wepassitoursecretanditwillensureitisarealtoken,prettysimple:
varSocketIOJWT=require('socketio-jwt');
io.use(SocketIOJWT.authorize({
secret:jwtSecret,
handshake:true}));
Now,whenwetrytoconnecttoourserverfromtheclientitwillneveremittheconnectevent,asourclientisn’tauthenticated.Thisisexactlywhatwewant.
WefirstwanttowrapupourSocket.IOcode(wewillcallthislater);wealsowanttogiveitaparameteroftoken:
functionsocketIO(token){
varsocket=io.connect('http://localhost:8080');
varoutput=document.getElementById('output');
functionlogScreen(text){
vardate=newDate().toISOString();
line=date+""+text+"<br/>";
output.innerHTML=line+output.innerHTML
}
logScreen('Connecting');
socket.on('connect',function(){
logScreen('Connection!');
socket.send('Hello');
});
socket.on('message',logScreen);
}
Next,wewillcreatealoginfunction,thiswillrequesttheloginURLandthenpasstheresponsetothesocketIOfunction,asshown:
functionlogin(){
{
varrequest=newXMLHttpRequest();
request.onreadystatechange=function(){
if(
request.readyState!==4||
request.status!==200
![Page 128: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/128.jpg)
)return
socketIO(request.responseText);
}
request.open("GET","/login",true);
request.send(null);
}
Thenwewanttocalltheloginfunction:
login();
Wecanpassthetokenontotheserverbychangingtheconnectcalltopassaquerystring:
varsocket=io.connect('http://localhost:8080',{
query:'token='+token
});
Now,whenrunningourserverandnavigatingtoourclientweshouldbeabletoconnect—awesome!Sincewehaveauthenticatedwecanalsorespondwithapersonalizedmessageforeachuser,insideourserver-sideconnectioneventhandlerwewillemitamessagetotheclient.
Oursocketwillhaveanewpropertycalleddecoded_token;usingthiswewillbeabletoviewthecontentsofourtoken:
varpayload=socket.decoded_token;
varname=payload.name;
socket.emit('message','Hello'+name+'!');
Oncewejoinourroom,wecantelltherestoftheclientswhohavealsojoined:
socket
.to(room)
.emit(
'message',
name+'joinedtheroom!'
);
![Page 129: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/129.jpg)
![Page 130: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/130.jpg)
SummarySocket.IObringsamazingcapabilitiestoourapplications.Wecannowinstantlycommunicatewithothers,eitherindividuallyorbybroadcastinginaroom.Withtheabilitytoidentifyusers,wecanrecordmessagesorthehistoryofthatuser,readytobeservedupbyaRESTfulAPI.
Wearenowreadytobuildreal-timeapplications!
![Page 131: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/131.jpg)
![Page 132: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/132.jpg)
Chapter8.CreatingandDeployingPackagesNowthatwehaveallofthepiecesthatareneededtocreateNode.jsapplicationsandservers,wewillnowfocusmoreonsharingourmodulesandcontributingtotheeco-system.
Allthepackagesonnpmhavebeenuploaded,maintained,andcontributedbysomeoneinthecommunity,solet’shavealookathowwecandothesameourselves.
![Page 133: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/133.jpg)
CreatingnpmpackagesWecanstartwiththefollowingsteps:
Firstweneedtocreateauser:
[~]$npmadduser
Username:<username>
Password:
Email:(thisISpublic)<email>
Oncewehaveauserwehaveopenedthegatestonpm.
Now,let’screateapackage:
[~/examples/example-22]$npminit
{
"name":"njs-e-example-package",
"version":"1.0.0",
"description":"",
"main":"index.js",
"scripts":{
"test":"echo\"Error:notestspecified\"&&exit1"
},
"author":"",
"license":"ISC"
}
Topublishthispackageallweneedtodoisrunnpmpublish:
[~/examples/example-22]$npmpublish
Youcanseethatwehavepublishedourpackagesuccessfully,youcanviewtheoneIpublishedat:
https://www.npmjs.com/package/njs-e-example-package
Youwillhavetonameyourpackagesomethingelseinordertopublishit;otherwise,wewillhaveaconflict.
Nowwecanrunthefollowingcommand:
[~/examples/example-21]$npminstallnjs-e-example-package
[email protected]_modules/njs-e-example-package
Thenwewillhavethepackage!Isn’tthatprettycool?
Ifwetrytopublishagain,wewillgetanerrorbecauseversion1.0.2isalreadypublished,asshowninthefollowingscreenshot:
![Page 134: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/134.jpg)
Toincrementourpackageversion,allweneedtodoisexecute:
[~/examples/example-22]$npmversionpatch
v1.0.1
Nowwecanpublishagain:
[~/examples/example-22]$npmpublish
Youcangotoyourpackagespageonnpmandyouwillseethattheversionnumberandreleasecounthasbeenupdated.
VersioninginNode.jsfollowsthesemverschema,whichismadeupofmajor,minor,andpatchversions.Whenthepatchversionisincremented,itmeansthattheAPIhasstayedthesamehoweversomethinghasbeenfixedbehindthescenes.Iftheminorversionhasbeenincremented,itmeansthatanon-breakingAPIchangehasoccurred,suchasamethodhasbeenadded.Ifthemajorversionisupdated,itmeansthattherehasbeenabreakingAPIchange;forexampleamethodhasbeendeletedoramethodsignaturehaschanged.
Sometimes,therearethingsinyourprojectthatyoudon’twanttobepushedoutforotherpeopletohave.Thiscouldbeanoriginalsource,somecertificates,ormaybesomekeysfordevelopment.Justlikewhenusinggit,wehaveanignorefilecalled.npmignore.
Bydefault,ifthereisno.npmignorebutthereisa.gitignore,npmwillignorewhatismatchedbythe.gitignorefile.Ifyoudon’tlikethisbehaviorthenyoucanjustcreateanempty.npmignorefile.
The.npmignorefilefollowsthesamerulesas.gitignore,whichareasfollows:
Blanklinesorlinesstartingwith#areignoredStandardglobpatternsworkYoucanendpatternswithaforwardslash/tospecifyadirectoryYoucannegateapatternbystartingitwithanexclamationpoint!
Forexample,ifwehadadirectoryofcertificatesinwhichwehadakey:
[~/examples/example-22]$mkdircertificates
[~/examples/example-22]$touchcertifticates/key.key
Weprobablydon’twantthistobepublished,soinourignorefilewewillhave:
![Page 135: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/135.jpg)
certificates/
Wealsodon’twantanykeyfilesthatwehavelyingaround,soweaddthisaswell:
*.key
Now,let’spublish:
[~/examples/example-22]$npmversionpatch
v1.0.2
[~/examples/example-22]$npmpublish
Now,let’sinstallourpackage:
[~/examples/example-23][email protected]
Now,whenwelistwhat’sinthedirectory,wedon’tseeallourcertificatesbeingpassedaround:
[~/examples/example-23]$lsnode_modules/njs-e-example-package
package.json
Thisisgreat,butwhatifwewanttoprotectourentirepackageandnotjustafewcertificates?
Allweneedtodoissetprivatetotrueinourpackage.jsonfileanditwillpreventnpmfrompublishingthemodulewhenwerunnpmpublish:
Ourpackage.jsonshouldlooksomethinglike:
{
"name":"example-23",
"version":"1.0.0",
"description":"",
"main":"index.js",
"scripts":{
"test":"echo\"Error:notestspecified\"&&exit1"
},
"author":"",
"license":"UNLICENSED",
"dependencies":{
"njs-e-example-package":"^1.0.2"
},
"private":true
}
Now,whenwerunnpmpublish:
[~/examples/example-23]$npmpublish
npmERR!Thispackagehasbeenmarkedasprivate
Awesome,that’sexactlywhatwewantedtosee.
![Page 136: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/136.jpg)
![Page 137: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/137.jpg)
SummaryLookslikewearegettingclosertobeingreadywithallthingsaboutNode.js.Weknownowhowtosetup,debug,develop,anddistributeoursoftware.
Inthenextchapter,wewillcoveronemoreconceptweneedtoknowabout:unittesting.
![Page 138: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/138.jpg)
![Page 139: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/139.jpg)
Chapter9.UnitTestingWehavecomethisfarbuthaven’tdoneanytesting!That’snotverygood,isit?Usually,ifnotalways,testingisamajorconcerninsoftwaredevelopment.Inthischapter,wewillcoverunittestingconceptswithNode.
TherearemanytestingframeworksforNode.jsandinthischapterwewillbecoveringMocha.
![Page 140: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/140.jpg)
InstallingmochaToensurethatmochagetsinstalledeverywhere,weneedtoinstallitglobally.Thiscanbedoneusingthe-gflagwithnpminstall:
[~/examples/example-24]$npminstall-gmocha
Now,wecanuseMochathroughtheterminalconsole.
Typically,wewillcontainallourtestingcodeinatestsub-directorywithintheproject.Allweneedtodotogetourcoderunningisrunmocha,assumingwehavewrittensometestsfirst.
Aswithmany(ifnotall)unittestingframeworks,Mochausesassertionstoensurethatatestrunscorrectly.Ifanerroristhrownandisnothandledthenthetestisconsideredtohavefailed.Whatassertionlibrariesdoisthrowerrorswhenanunexpectedvalueispassed,sothisworkswell.
Node.jsprovidesasimpleassertionmodule,let’shavealookatthefollowing:
[~/examples/example-24]$node
>assert=require('assert')
>expected=1
>actual=1
>assert.equal(actual,expected)
>actual=1
>assert.equal(actual,expected)
AssertionError:2==1
Aswecansee,anerroristhrowniftheassertiondoesn’tpass.However,theerrormessageprovidedwasn’tveryhandy;tofixthiswecanpassanerrormessageaswell:
>assert.equal(actual,expected,'Expected1')
AssertionError:Expected1
Withthiswecancreateatest.
Mochaprovidesmanywaysofcreatingtests,thesearecalledinterfacesandthedefaultiscalledBDD.
Youcanviewallinterfacesathttp://mochajs.org/#interfaces.
TheBDD(BehaviorDrivenDevelopment)interfacecanbecomparedtoGherkinwherewespecifyafeatureandasetofscenarios.Itprovidesmethodstohelpdefinethesesets,describeorcontextisusedtodefineafeature,andtheitorspecifyfunctionsareusedtodefineascenario.
Forexample,ifweweretohaveafunctionthatjoinssomeone’sfirstandlastname,thetestsmightlooksomethinglikethefollowing:
varGetFullName=require('../lib/get-full-name'),
assert=require('assert');
describe('Fetchfullname',function(){
![Page 141: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/141.jpg)
it('shouldreturnbothafirstandlastname',function(){
varresult=GetFullName({first:'Node',last:'JS'})
assert.equal(result,'NodeJS');
})
})
Wecanalsoaddafewmoretestsforthis;forexample,ifitthrewanerrorincaseofnoobjectbeingpassed:
it('shouldthrowanerrorwhenanobjectwasnotpassed',function(){
assert.throws(
function(){
GetFullName(null);
},
/Objectexpected/
)
})
Youcanexploremanymoremocha-specificfeaturesathttp://mochajs.org/.
![Page 142: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/142.jpg)
![Page 143: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/143.jpg)
ChaiAlongwiththemanytestingframeworks,therearealsomanyassertionframeworks,oneofwhichiscalledChai.Completedocumentationcanbefoundathttp://chaijs.com/.
Insteadofjustusingthebuilt-inassertionmoduleprovidedbyNode.js,wemaywanttouseamodulesuchasChaitoextendourpossibilities.
Chaihasthreesetsofinterfaces,should,expect,andassert.Inthischapter,wewillbecoveringexpect.
Whenusingexpect,youareusingnaturallanguagetodescribewhatyouwant;forexample,ifyouwantsomethingtoexist,youcansay,expect(x).to.existratherthanassert(!!x):
varExpect=require('chai').expect
varAssert=require('assert')
varvalue=1
Expect(value).to.exist
assert(!!value)
Usingnaturallanguagemakesthingsalotclearerforpeoplereadingyourtests.
Thislanguagecanbelinkedtogether;wehaveto,be,been,is,that,which,and,has,have,with,at,of,andsame,whichcanhelpustobuildsentenceslike:
Expect(value).to.be.ok.and.to.equal(1)
However,thesewordsareonlyforreliabilityandtheydon’tmodifytheresult.Therearealotofotherwordsthatcanbeusedtoassertthings,suchasnot,exists,ok,andmanymore.Youcanviewthemallathttp://chaijs.com/api/bdd/.
Someexamplesofchaiinuseare:
Expect(true).to.be.ok
Expect(false).to.not.be.ok
Expect(1).to.exists
Expect([]).to.be.empty
Expect('hi').to.equal('hi')
Expect(4).to.be.below(5)
Expect(5).to.be.above(4)
Expect(function(){}).to.be.instanceOf(Function)
![Page 144: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/144.jpg)
![Page 145: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/145.jpg)
StubbingmethodsIfitlookslikeaduck,swimslikeaduck,andquackslikeaduck,thenitprobablyisaduck.
Asyouwriteyourtestsyouwanttobeonlybetestingunitsofcode.Generallythiswillbeamethod,provideitsomeinput,andexpectanoutputofsomekind,orifitisavoidfunction,expectnothingtobereturned.
Withthisinmind,youhavetothinkofyourapplicationasbeinginasandboxedstatewhereitcan’ttalktotheoutsideworld.Forexample,itmightnotbeabletotalktoadatabaseormakeanykindofexternalrequest.Havingthisassumptionisgreatifyouaregoingto(andyouusuallyshould)implementcontinuousintegrationanddeployment.ItalsomeansthattherearenoexternalrequirementsforthemachineyouaretestingonexceptforNode.jsandthetestingframework,whichcouldjustbeapartofyourpackageanyway.
Unlessthemethodyouaretestingisrathersimpleanddoesn’thaveanyexternaldependencies,youwillprobablywanttomockthemethodsthatyouknowitisgoingtoexecute.AgreatmoduletodothisiscalledSinon.js;itallowsyoutocreatestubsandspiestomakesurethatthecorrectdatareturnsfromothermethodsandtoensurethattheywerecalledinthefirstplace.
sinonprovidesmanyhelpers,asmentionedbeforeandoneoftheseiscalledaspy.Aspyisusedmainlytojustwrapafunctiontoseewhatitsinputandoutputwas.Onceaspyhasbeenappliedtoafunction,totheoutsideworlditbehavesexactlythesame.
varSinon=require('sinon');
varreturnOriginal=function(value){
returnvalue;
}
varspy=Sinon.spy(returnOriginal);
result=spy(1);
console.log(result);//Logs1
Wecanuseaspytocheckifafunctionwascalled:
assert(spy.called)
Orwhatargumentswerepassedforeachcall:
assert.equal(spy.args[0][0],1)
Ifweprovidedspywithanobjectandamethodtoreplacethenwecanrestoretheoriginaloncewearefinished.Wewillusuallydothisintheteardownofourtest:
varobject={
spyOnMe:function(value){
returnvalue;
![Page 146: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/146.jpg)
}
}
Sinon.spy(object,'spyOnMe')
varresult=object.spyOnMe(1)
assert(result.called)
assert.equal(result.args[0][0],1)
object.spyOnMe.restore()
Wealsohaveastubfunction,whichinheritsallthefunctionalityofspybutinsteadofcallingtheoriginalfunctionitcompletelyreplacesit.
Thisissowecandefinethebehavior,forexample,whatitreturns:
varstub=Sinon.stub().returns(42)
console.log(stub())//logs42
Wecanalsodefineareturnvalueforasetofargumentspassed:
varstub=Sinon.stub()
stub.withArgs(1,2,3).returns(42)
stub.withArgs(3,4,5).returns(43)
console.log(stub(1,2,3))//logs42
console.log(stub(3,4,5))//logs43
Let’ssaywehadthissetofmethods:
functionUsers(){
}
Users.prototype.getUser=function(id){
returnDatabase.findUser(id);
}
Users.prototype.getNameForUser=function(id){
varuser=this.getUser(id);
returnuser.name;
}
module.exports=Users
Now,weonlycareaboutthescenariowhereauserisreturned,asthegetUserfunctionwillthrowanerrorifitcan’tfindit.Knowingthis,wejustwanttotestthatwhenauserisfounditreturnstheirname.
Thisisaperfectexampleofwhenwewanttostubamethod:
varSinon=require('sinon');
varUsers=require('../lib/users');
varAssert=require('assert');
it('shouldreturnausersname',function(){
varname='NodeJS';
varuser={name:name};
varstub=Sinon.stub().returns(user);
![Page 147: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/147.jpg)
varusers=newUsers();
users.getUser=stub;
varresult=users.getNameForUser(1);
assert.equal(result,name,'Namenotreturned');
});
Insteadofreplacingthefunctionwecanalsopassthefunctionusingthescope,replacingthiswiththeobjectwepassed;eitherwayissufficient.
varresult=users.getNameForUser.call(
{
getUser:stub
},
1
);
![Page 148: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/148.jpg)
![Page 149: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/149.jpg)
SummaryEverythingweneedtocreateaNode.jsapplicationisnowatourfingertips.Testingisjustoneofthosethingsthatareessentialtoanysuccessfulsoftware.Wecoveredusingmochaasatestingframeworkandchaiasanassertionframework.
Inthenextchapter,wewillcoverusinganotherlanguagewithNode.js,CoffeeScript!
![Page 150: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/150.jpg)
![Page 151: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/151.jpg)
Chapter10.UsingMoreThanJavaScriptThroughoutthisbookwehaveusedonlyJavaScript.Well,it’scalledNode.jsisn’tit?
However,thatdoesn’tmeanthatwecan’tuseotherlanguageswithit.WecanandaslongasitcompilestoJavaScriptyouaregoodtogo.
Thereisabiglistofcommonlanguagesthatareavailableat:https://github.com/jashkenas/coffeescript/wiki/list-of-languages-that-compile-to-JS.
Ifyouaremissingyourstronglytypedlanguageorjustwantaslightlydifferentsyntax,thentherewillsurelybeoneoptionoutthereforyousomewhere.
AcoupleofcommonlanguagesincludeCoffeeScriptandTypeScript,theyworkgreatwithNode.jsastheybothcompiletoJavaScript.Inthischapter,wewillcovertheusageofCoffeeScript.TypeScriptissimilarinusage;however,thesyntaxfollowsasimilarpathtoC#andJava.
![Page 152: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/152.jpg)
CoffeeScriptIt’sverysimpletoinstallandstartusingadditionallanguages.Let’shavealookatCoffeeScript:
WeneedtoinstallCoffeeScriptglobally,sothatwecanuseacommandsimilartonode:
[~]npminstall-gcoffee-script
Nowwecanruncoffee:
[~]coffee
>
ThesyntaxisverysimilartoJavaScript:
[~]coffee
>1+1
2
>console.log('Hello')
Hello
Insteadofusingthe.jsextension,weuse.coffee.
First,wewillcreateaCoffeeScriptfile:
/*index.coffee*/
console.log('HelloCoffeeScript!')
Thentorunit,allweneedtodoisusethecoffeecommand,similartothenodecommand:
[~/examples/example-25]coffeeindex.coffee
HelloCoffeScript!
Tocompileour.coffeefilesinto.js,wecanuse-c.Oncecompiled,wecanrunthemdirectlywithNode.js:
[~/examples/example-25]coffee-cindex.coffee
[~/examples/example-25]nodeindex.js
HelloCoffeeScript!
IfwehaveabunchofCoffeeScriptthatwewanttocompiletoJavaScriptallatonce,wecanusecoffee-c-o./lib./src.Thiswilltakeall.coffeefilesfrom./src,compilethemto.jsandthenoutputthemto./lib.
YouwillneedtocompileallyourfilesforotheruserstouseourCoffeeScriptcodealongsidetheirJavaScriptcode.ThealternativeistoincludeCoffeeScriptasadependencyandrequiretheregisterfileintoyourapplication,asshown:
/*index.js*/
require('coffee-script/register');
require('./other.coffee');
YoumayneedtodothisifdonotyouwishtocompileyourCoffeeScript,orifyouareusingatoolthatrequiresaJavaScriptfilesuchasGulporGrunt.
![Page 153: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/153.jpg)
TipToseetheequivalentsbetweenJavaScriptandCoffeeScriptyoucanusethesitehttp://js2.coffee/,itprovidesasimplewaytocomparethetwoonthefly.
CoffeeScriptisbasicallyjustJavaScript;however,ithastargetedreadabilityandsimplicity.WithsimplicityitalsotriestolimittheuseofthebadpartsofJavaScriptandexposesthegoodparts.
UsingCoffeeScriptisusuallygreatforbeginners,(andforexperts),asitusesEnglishlanguageratherthancomputerlanguage.Forexample,insteadofusing===(tripleequals)tocheckiftwovaluesequal,wecanjustusetheEnglishwordis.So,x===ybecomesxisy,whichmeansthatthereisnotranslatingrequiredwhenreading.
Alongwithis,thereareotherkeywords,suchasisnt,not,or,and,yesandno.
Usingthesekeywordsinsteadofsymboloperatorsgivesclaritytothereadersandprogrammers.TheCoffeeScripthassimilarformattingtoPythoninthewayfunctionsandcodeblocksaredeclared;theindentationindicateswhentheblockendsandbegins
![Page 154: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/154.jpg)
![Page 155: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/155.jpg)
CodeblocksandfunctionsInJavaScriptyouwillusuallygrouptogetherblocksusingcurlybraces,asshowninthefollowingexample:
if(true)
{
console.log('Itwastrue!')
}
WhereasinCoffeeScriptyouwillleaveoutallthecurlybraces,infactallthebracesareleftout:
iftrue
console.log('Itwastrue!')
Thesameistruewhendeclaringafunction,noticethatweareusinganarrowratherthanthekeywordfunction.Theparameterlistisonlyrequiredifyouwantnamedarguments:
func=->
console.log('Iexecuted')
CoffeeScripttriestoassumeasmuchaspossiblewhilestillgivingtheprogrammerenoughcontrol.
YoumayhavealsonoticedthatIdidn’tusethevarkeywordwhendeclaringafunction.Thisisbecauseitisimplicitlydeclared,asyoucanseebycompilingtheabovecodetoJavaScript:
varfunc;
func=function()
{
returnconsole.log('Iexecuted');
};
Youcanseeinthiscompiledcodethatthelaststatementinthefunctionisthereturnvalue,thismeansthatwedon’tneedtodeclarethereturnvalueandjustassumethatthelastvalueisreturned.Thismakesitverysimpletocreateonelinefunctions,suchas:
add=(a,b)->a+b
UnlikeJavaScript,youmayprovidedefaultargumentsforafunctionandthiscanbecomparedtoC#;however,it’snotlimitedtoonlyconstantsasitessentiallyexecutesthestatementwithinthefunction:
keys={}
func=(key,date=newDate)->
keys[key]=date
Youcanseethisbycompilingtheabovefunctionas:
varfunc,keys;
keys={};
func=function(key,date)
{
![Page 156: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/156.jpg)
if(date==null)
{
date=newDate();
}
returnkeys[key]=date;
};
Essentially,allCoffeeScriptdoesischeckifthevalueisnullorundefined.
![Page 157: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/157.jpg)
![Page 158: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/158.jpg)
TheexistentialoperatorYoucanchecktoseeifavalueisnullorundefinedusingtheexistentialoperator,whichcheckstoseeifthevalueexists.Thisisindicatedbyusingthequestionmarksymbolafteravariable;thestatementwillbetrueifthevalueexistsandotherwisefalse.
Tousethisinanexpression:
date=null
ifnotdate?
date=newDate()
console.log(date)
Youcanusethisasashorthandoperatoraswell,forexample:
date?=newDate()
console.log(date)
Theabovetwoexamplesofcodewillbehaveexactlythesameandwillactuallycompiletogivethesamecode:
vardate;
date=null;
if(date==null)
{
date=newDate();
}
Youmayalsousetheexistentialoperatortoensureavalueexistsbeforeaccessingapropertyofit.Forexample,ifyouwanttogetthetimefromadate,or-1ifthedatedoesn’texist:
getTime=(date=null)->date?.getTime()?-1
Givingdatethenullvalueshowsthatwedon’tmindifnovalueispassed:
Whenanobjectdoesn’texistandtheoperatorisusedthenthereturnedvalueisundefined,thismeansthatwecanusethesameoperatoragaintoreturnadefaultvalue.
![Page 159: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/159.jpg)
![Page 160: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/160.jpg)
ObjectsandarraysAlongwithalltheassumptionsthatCoffeeScripttriestomake,itsurelydoestrytoremovealltheun-neededsyntaxplainJavaScriptrequires.Anotherinstanceofthiscanbeseenwhiledefiningarraysandobjectsinwhichtheuseofanewlinedeclaresanewitem.Forexample,youwillusuallydefineanarrayas:
array=[
1,
2,
3
]
Thisstillworks;however,withCoffeeScriptyoucanleaveoutthecommasseparatingeachitem:
array=[
1
2
3
]
Youcanalsomixthetwostylestogether:
array=[
'a','b','c'
1,2,3
true,false
]
Youcandothesamewithobjects,suchas:
object={
foo:1
bar:2
}
Withobjectsyoucanevenleaveoutthecurlybracesanduseindentationtoshowthedifferencesintheobject:
object=
foo:1
bar:2
foobar:
another:3
key:4
ToloopanarrayinCoffeeScript,allyouneedtodoisusethefor…inloop,suchas:
forvalue,indexinarray
console.log(value,index)
continueiftypeofvalueis'string'
console.log('Valuewasnotastring')
Ifyoudonotwishtousetheindexofyouritem,yousimplydon’taskforit:
![Page 161: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/161.jpg)
forvalueinarray
console.log(value)
AswithJavaScriptloops,youcanusebreakandcontinuetocontroltheflow.
ToloopanobjectinCoffeeScriptyoucanusethefor…ofloop,thisisabitdifferentfromthefor…ofloopprovidedbyJavaScript:
forkey,valueofobject
console.log(key,value)
Aswiththefor…inloop,ifyoudon’twantthevalue,excludeit:
forkeyofobject
console.log(key)
Forbothtypesofloops,thenamingisirrelevant:
forkey,valueofobject
#Notethatthiswillletdatesandarraysthrough(etc)
continueunlessvalueinstanceofObject
fornestedKey,nestedValueofvalue
console.log(nestedKey,nestedValue)
![Page 162: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/162.jpg)
![Page 163: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/163.jpg)
ClassesUnlikeJavaScript,CoffeeScriptprovidesanaturalwaytodeclareclassesandinheritance.
TodefineaclassinJavaScript,youneedtodeclareafunctionfirst:
functionUser(username){
this.username=username;
}
Thenyouwilldeclaretheprototypemethods:
User.prototype.getUsername=function(){
returnthis.username;
}
Ifyouhaveastaticmethod,youcandefinethisonthefunctionratherthantheprototype:
User.createUser=function(username){
returnnewUser(username);
}
InCoffeeScriptyoucanusetheclasskeywordandgivetheclassaname.Youcanthendeclaretheconstructor,static,andinstance(prototype)methods:
classUser
@createUser:(username)->
returnnewUser(username)
constructor:(username)->
this.username=username
getUsername:->
returnthis.username
Usually,youplaceallyourstaticmethodsaboveyourconstructorsothattheystayseparatefromyourinstancemethods.Thisavoidsconfusion,youmayhavenoticedthatIdeclaredthestaticmethodcreateUserwitha@prefix,thisishowyoudefineastaticmethodinCoffeeScript.However,youcanalsousethetraditionalJavaScriptmethodofUser.createUser=->,eitherwaywillworkhere.
Thecodethatisrunwhentheinstanceisbeingcreatedorconstructediscalledtheconstructor.Thisisthesameterminologythatisusedinmanyotherlanguagessoitshouldbefamiliar.Aconstructorisessentiallyafunction.
Alltheinstancemethodsaredeclaredsimilarlytopropertiesofanobject.
Withclassescomesanothersymbol,[email protected],youcanuseittorefertothethiskeyword.Forexample,thegetUsernamemethodcanbewrittenas:
getUsername:->
return@username
Or,ifwewanttodropthereturnstatementandmakeitaoneliner:
![Page 164: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/164.jpg)
getUsername:->@username
The@symbolcanalsobeusedinparameterliststodeclarethatwewanttheinstancepropertytobesetasthepassedvalue.Forexample,ifwehadasetUsernamemethodwecaneitherdo:
setUsername:(username)->
@username=username
Orwecando:
setUsername:(@username)->
BoththemethodswillcompiletothesameJavaScriptcode.
Giventhefactthatwecanusethe@symbolinourparameterlist,wecanrefactorourconstructorfunctionto:
constructor:(@username)->
AnotheradvantageofusingCoffeeScriptclassisthatwecandefineinheritance.Todoso,allweneedtodoisusetheextendskeyword,thisissimilartootherlanguages.
Intheseexamples,wewanttohavetwoclasses,PersonandRobotthatextendthebaseUserclass.
Forourperson,wewanttobeabletogivethemanameandanagealongwiththeusernamethattheUserclassrequires.
First,weneedtodeclareourclass:
classPersonextendsUser
Thendeclareourconstructor.Inourconstructor,wewillcallthesuperfunction,thiswillexecutetheconstructoroftheparentclassUserandwewanttopasstheusernametoit,asshown:
constructor:(username,@name,@age)->
super(username)
Wethenaddtwomethods,getNameandgetAge:
getName:->@name
getAge:->@age
Next,wewilldothesameforRobot,exceptthistimeweonlywantausernameand@usage:
classRobotextendsUser
constructor:(username,@usage)–>
super(username)
getUsage:->@usage
Wecannowcreateinstancesofourclassesandcomparethem,asshownhere:
![Page 165: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/165.jpg)
![Page 166: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/166.jpg)
![Page 167: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/167.jpg)
SummaryCoffeeScripttriestomakegoodassumptionswithyourcode.ThishelpstoremovesomeproblemsthatJavaScriptdeveloperscomeacross.Forexample,thedifferencebetween==and===.
YoucanlearnmoreaboutthespecificsyntaxofCoffeeScriptathttp://coffeescript.org/.
Inthischapterwehavecoveredutilizinganotherlanguage.ThiscanhelpalleviatethestruggleswithJavaScript’sstyleorsyntaxforbeginners.Forpeoplewhoareusedtomorelanguagefeatures,thisisabigadvantageasithelpsremovethepitfallsthatpeopleusuallycomeacross.
![Page 168: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/168.jpg)
IndexA
argumentsabout/Arguments
authenticationbasicauthentication/Basicauthentication
![Page 169: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/169.jpg)
BBDD(BehaviorDrivenDevelopment)/InstallingmochaBearertoken
about/Bearertokensbunyan
reference/Logging
![Page 170: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/170.jpg)
Cchai
about/ChaiURL/Chai
CoffeeScriptabout/CoffeeScriptinstalling/CoffeeScriptreference/CoffeeScriptcodeblocks/Codeblocksandfunctionsfunctions/Codeblocksandfunctionsexistentialoperator,using/Theexistentialoperatorobjects/Objectsandarraysarrays/Objectsandarraysclasses/Classes
configurationJSONfiles/JSONfilesenvironmentalvariables/Environmentalvariablesarguments/Arguments
![Page 171: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/171.jpg)
Eenvironmentalvariables
about/Environmentalvariableserrorhandling
about/Errorhandlingexistentialoperator
about/Theexistentialoperator
![Page 172: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/172.jpg)
HHellorequireexample
about/HellorequireHTTPmethods
POST/IntroducingroutingGET/IntroducingroutingDELETE/Introducingrouting
![Page 173: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/173.jpg)
JJSONfiles
about/JSONfilesJSONWebToken(JWT)
about/BearertokensURL/Bearertokens
![Page 174: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/174.jpg)
LLevelDB
about/LevelDBlogging
about/Logging
![Page 175: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/175.jpg)
Mmethods
stubbing/Stubbingmethodsmocha
installing/Installingmochareference,forinterfaces/InstallingmochaURL/Installingmocha
MongoDBabout/MongoDB
MongoLababout/MongoDB
morganabout/Loggingreference/Logging
![Page 176: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/176.jpg)
NNode.js
settingup/SettingupURL/Settingup
npmabout/HellonpmURL/Hellonpmscriptsobject/Hellonpm
npmpackagescreating/Creatingnpmpackages
![Page 177: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/177.jpg)
OOAuth
about/OAuthURL/OAuth
![Page 178: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/178.jpg)
Rrouting
about/Introducingrouting
![Page 179: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/179.jpg)
SSinon.js/StubbingmethodsSocket.IO
rooms/Roomsauthentication/Authentication
spy/Stubbingmethodsstubfunction/Stubbingmethods
![Page 180: Node.js Essentials - the-eye.eu · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more Why subscribe? Free access for Packt](https://reader034.vdocuments.us/reader034/viewer/2022050520/5fa3cbac6ccbba2b2a297d2f/html5/thumbnails/180.jpg)
Ttry/catchfunction/Errorhandling