![Page 1: Node.js Essentials - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/html5/thumbnails/1.jpg)
![Page 2: Node.js Essentials - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/html5/thumbnails/2.jpg)
![Page 3: Node.js Essentials - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/html5/thumbnails/3.jpg)
Node.jsEssentials
![Page 4: Node.js Essentials - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/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 - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/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 - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/html5/thumbnails/6.jpg)
Theexistentialoperator
Objectsandarrays
Classes
Summary
Index
![Page 7: Node.js Essentials - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/html5/thumbnails/7.jpg)
![Page 8: Node.js Essentials - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/html5/thumbnails/8.jpg)
Node.jsEssentials
![Page 9: Node.js Essentials - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/html5/thumbnails/9.jpg)
![Page 10: Node.js Essentials - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/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 - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/html5/thumbnails/11.jpg)
![Page 12: Node.js Essentials - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/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 - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/html5/thumbnails/13.jpg)
![Page 14: Node.js Essentials - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/html5/thumbnails/14.jpg)
AbouttheAuthorFabianCookisanexperiencedJavaScriptdeveloperwholivesinHawkesBay,NewZealand.HebeganworkingwithJavaandC#veryearlyinhislife,whichleadtousingNode.jsinanopensourcecontext.HeisnowcurrentlyworkingforaNewZealandISP,knownasNOWNZwheretheyareutilizingthefullpowerofNode.js,DockerandCoreOS.
![Page 15: Node.js Essentials - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/html5/thumbnails/15.jpg)
![Page 16: Node.js Essentials - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/html5/thumbnails/16.jpg)
AbouttheReviewerGlennGeenenisaNode.jsdeveloperwithabackgroundingameandmobiledevelopment.HehasmostlyworkedasaniOSconsultantbeforebecomingaNode.jsconsultantforhiscompany,GeenenTijd.
![Page 17: Node.js Essentials - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/html5/thumbnails/17.jpg)
![Page 18: Node.js Essentials - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/html5/thumbnails/18.jpg)
www.PacktPub.com
![Page 19: Node.js Essentials - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/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 - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/html5/thumbnails/20.jpg)
Whysubscribe?FullysearchableacrosseverybookpublishedbyPacktCopyandpaste,print,andbookmarkcontentOndemandandaccessibleviaawebbrowser
![Page 21: Node.js Essentials - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/html5/thumbnails/21.jpg)
FreeaccessforPacktaccountholdersIfyouhaveanaccountwithPacktatwww.PacktPub.com,youcanusethistoaccessPacktLibtodayandview9entirelyfreebooks.Simplyuseyourlogincredentialsforimmediateaccess.
![Page 22: Node.js Essentials - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/html5/thumbnails/22.jpg)
![Page 23: Node.js Essentials - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/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 - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/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 - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/html5/thumbnails/25.jpg)
![Page 26: Node.js Essentials - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/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 - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/html5/thumbnails/27.jpg)
![Page 28: Node.js Essentials - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/html5/thumbnails/28.jpg)
WhothisbookisforThebookwillbehelpfultoanybodywhowantstohaveknowledgeofNode.js(whatNode.jsisabout,howtouseit,whereit’susefulandwhentouseit).Familiaritywithserver-sideandNode.jsisaprerequisite.
![Page 29: Node.js Essentials - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/html5/thumbnails/29.jpg)
![Page 30: Node.js Essentials - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/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 - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/html5/thumbnails/31.jpg)
![Page 32: Node.js Essentials - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/html5/thumbnails/32.jpg)
ReaderfeedbackFeedbackfromourreadersisalwayswelcome.Letusknowwhatyouthinkaboutthisbook—whatyoulikedormayhavedisliked.Readerfeedbackisimportantforustodeveloptitlesthatyoureallygetthemostoutof.
Tosendusgeneralfeedback,simplysendane-mailto<[email protected]>,andmentionthebooktitleviathesubjectofyourmessage.
Ifthereisatopicthatyouhaveexpertiseinandyouareinterestedineitherwritingorcontributingtoabook,seeourauthorguideonwww.packtpub.com/authors.
![Page 33: Node.js Essentials - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/html5/thumbnails/33.jpg)
![Page 34: Node.js Essentials - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/html5/thumbnails/34.jpg)
CustomersupportNowthatyouaretheproudownerofaPacktbook,wehaveanumberofthingstohelpyoutogetthemostfromyourpurchase.
![Page 35: Node.js Essentials - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/html5/thumbnails/35.jpg)
DownloadingtheexamplecodeYoucandownloadtheexamplecodefilesforallPacktbooksyouhavepurchasedfromyouraccountathttp://www.packtpub.com.Ifyoupurchasedthisbookelsewhere,youcanvisithttp://www.packtpub.com/supportandregistertohavethefilese-maileddirectlytoyou.
![Page 36: Node.js Essentials - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/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 - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/html5/thumbnails/37.jpg)
PiracyPiracyofcopyrightmaterialontheInternetisanongoingproblemacrossallmedia.AtPackt,wetaketheprotectionofourcopyrightandlicensesveryseriously.Ifyoucomeacrossanyillegalcopiesofourworks,inanyform,ontheInternet,pleaseprovideuswiththelocationaddressorwebsitenameimmediatelysothatwecanpursuearemedy.
Pleasecontactusat<[email protected]>withalinktothesuspectedpiratedmaterial.
Weappreciateyourhelpinprotectingourauthors,andourabilitytobringyouvaluablecontent.
![Page 38: Node.js Essentials - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/html5/thumbnails/38.jpg)
QuestionsYoucancontactusat<[email protected]>ifyouarehavingaproblemwithanyaspectofthebook,andwewilldoourbesttoaddressit.
![Page 39: Node.js Essentials - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/html5/thumbnails/39.jpg)
![Page 40: Node.js Essentials - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/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 - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/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 - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/html5/thumbnails/42.jpg)
![Page 43: Node.js Essentials - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/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 - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/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 - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/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 - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/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 - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/html5/thumbnails/47.jpg)
>util.log('Thisisprettycoolaswell')
01Jan00:00:00-Thisisprettycoolaswell
![Page 48: Node.js Essentials - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/html5/thumbnails/48.jpg)
![Page 49: Node.js Essentials - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/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 - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/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 - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/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 - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/html5/thumbnails/52.jpg)
![Page 53: Node.js Essentials - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/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 - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/html5/thumbnails/54.jpg)
![Page 55: Node.js Essentials - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/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 - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/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 - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/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 - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/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 - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/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 - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/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 - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/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 - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/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 - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/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 - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/html5/thumbnails/64.jpg)
![Page 65: Node.js Essentials - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/html5/thumbnails/65.jpg)
SummaryNowwehaveeverythingweneedtomakesomeprettycoolservices.WecannowcreateanHTTPfromscratch,routeourrequests,andcreateaRESTfulinterface.
ThiswillhelpyouwiththecreationofcompleteNode.JSservices.Inthenextchapter,wewillcoverauthentication.
![Page 66: Node.js Essentials - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/html5/thumbnails/66.jpg)
![Page 67: Node.js Essentials - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/html5/thumbnails/67.jpg)
Chapter3.AuthenticationWecannowcreateRESTfulAPIs,butwedon’twanteveryonetoaccesseverythingweexpose.Wewanttheroutestobesecureandtobeabletotrackwhoisdoingwhat.
Passportisagreatmoduleandanothermiddlewarethathelpsusauthenticaterequests.
PassportexposesasimpleAPIforproviderstoexpandonandcreatestrategiestoauthenticateusers.Atthetimeofwriting,thereare307officiallysupportedstrategies;however,thereisnoreasonwhyyoucan’twriteyourownstrategyandpublishitforotherstouse.
![Page 68: Node.js Essentials - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/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 - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/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 - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/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 - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/html5/thumbnails/71.jpg)
![Page 72: Node.js Essentials - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/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 - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/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 - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/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 - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/html5/thumbnails/75.jpg)
[~]$curl-XGEThttp://localhost:8080/userinfo\
-H'Authorization:Bearer<token>'
{"id":1,"username":"foo"}
![Page 76: Node.js Essentials - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/html5/thumbnails/76.jpg)
![Page 77: Node.js Essentials - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/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 - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/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 - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/html5/thumbnails/79.jpg)
![Page 80: Node.js Essentials - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/html5/thumbnails/80.jpg)
SummaryWecannowauthenticateusers;thisisgreataswecannowfigureoutwhothepeopleareandthenlimittheuserstocertainresources.
Inthenextchapterwewillcoverdebugging,wemayneedtouseitifourusersaren’tbeingauthenticated.
![Page 81: Node.js Essentials - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/html5/thumbnails/81.jpg)
![Page 82: Node.js Essentials - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/html5/thumbnails/82.jpg)
Chapter4.DebuggingAtsomepointinyourjourneywithNode.js,itisinevitablethatyouwillhavetodebugsomenastybugs.So,let’sexpectthembeforehandandplanforthatday.
![Page 83: Node.js Essentials - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/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 - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/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 - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/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 - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/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 - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/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 - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/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 - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/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 - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/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 - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/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 - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/html5/thumbnails/92.jpg)
![Page 93: Node.js Essentials - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/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 - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/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 - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/html5/thumbnails/95.jpg)
![Page 96: Node.js Essentials - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/html5/thumbnails/96.jpg)
SummaryInthischapterwehavecoveredafewpost-mortemdebuggingmethodstohelpusuncoverbugsincludinglogging,namingpractices,andsufficienterrorhandling.
Inthenextchapter,wewillcoverconfigurationofourapplications.
![Page 97: Node.js Essentials - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/html5/thumbnails/97.jpg)
![Page 98: Node.js Essentials - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/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 - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/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 - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/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 - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/html5/thumbnails/101.jpg)
![Page 102: Node.js Essentials - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/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 - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/html5/thumbnails/103.jpg)
![Page 104: Node.js Essentials - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/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 - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/html5/thumbnails/105.jpg)
![Page 106: Node.js Essentials - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/html5/thumbnails/106.jpg)
SummaryThat’sallforconfiguration.Inthischapteryoulearnedaboutthethreemethodsthatyoucanusetocreateadynamicapplication.Welearnedthatweshouldnameourconfigurationkeysinawaythatwecanidentifywhatthevaluesarechangingtoandhowtheywillaffectourapplication.Wealsolearnedabouthowwecanpasssimpleargumentstoourapplicationusingenvironmentalvariablesandargv.
Withthisinformation,wecanmoveforwardtoconnectingandutilizingdatabasesinthenextchapter.
![Page 107: Node.js Essentials - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/html5/thumbnails/107.jpg)
![Page 108: Node.js Essentials - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/html5/thumbnails/108.jpg)
Chapter6.LevelDBandNoSQLInthischapter,wewillcovertwovariationsofdatabasesthatcanbeusedwithNode.js;oneprovidesaverylightweightandsimplesetoffeatures,whiletheothergivesusmoreflexibilityandageneral-purposesetoffeatures.Inthischapter,wearegoingtocoverLevelDBandMongoDB
![Page 109: Node.js Essentials - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/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 - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/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 - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/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 - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/html5/thumbnails/112.jpg)
![Page 113: Node.js Essentials - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/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 - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/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 - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/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 - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/html5/thumbnails/116.jpg)
![Page 117: Node.js Essentials - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/html5/thumbnails/117.jpg)
SummaryNowwehaveplaceswherewecanstoreourdata.Ononeendwehaveasimplekey/valuestorethatprovidesuswithasuper-convenientwaytostoredataandontheotherendwehaveafeaturefulldatabasethatprovidesuswithafullsetofqueryoperators.
Boththesedatabaseswillhelpusinthenextchaptersaswemoveclosertocreatingourfullstackapplication.
InthenextchapterwewillcoverSocket.IO,areal-timecommunicationframeworkbuiltontopofWebSockets.
![Page 118: Node.js Essentials - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/html5/thumbnails/118.jpg)
![Page 119: Node.js Essentials - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/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 - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/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 - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/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 - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/html5/thumbnails/122.jpg)
aswellasreconnectingifneeded.Thistakesallthepainoutofusingsockets,aswehavenoneofthesetroubles.
![Page 123: Node.js Essentials - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/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 - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/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 - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/html5/thumbnails/125.jpg)
![Page 126: Node.js Essentials - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/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 - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/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 - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/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 - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/html5/thumbnails/129.jpg)
![Page 130: Node.js Essentials - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/html5/thumbnails/130.jpg)
SummarySocket.IObringsamazingcapabilitiestoourapplications.Wecannowinstantlycommunicatewithothers,eitherindividuallyorbybroadcastinginaroom.Withtheabilitytoidentifyusers,wecanrecordmessagesorthehistoryofthatuser,readytobeservedupbyaRESTfulAPI.
Wearenowreadytobuildreal-timeapplications!
![Page 131: Node.js Essentials - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/html5/thumbnails/131.jpg)
![Page 132: Node.js Essentials - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/html5/thumbnails/132.jpg)
Chapter8.CreatingandDeployingPackagesNowthatwehaveallofthepiecesthatareneededtocreateNode.jsapplicationsandservers,wewillnowfocusmoreonsharingourmodulesandcontributingtotheeco-system.
Allthepackagesonnpmhavebeenuploaded,maintained,andcontributedbysomeoneinthecommunity,solet’shavealookathowwecandothesameourselves.
![Page 133: Node.js Essentials - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/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 - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/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 - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/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 - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/html5/thumbnails/136.jpg)
![Page 137: Node.js Essentials - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/html5/thumbnails/137.jpg)
SummaryLookslikewearegettingclosertobeingreadywithallthingsaboutNode.js.Weknownowhowtosetup,debug,develop,anddistributeoursoftware.
Inthenextchapter,wewillcoveronemoreconceptweneedtoknowabout:unittesting.
![Page 138: Node.js Essentials - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/html5/thumbnails/138.jpg)
![Page 139: Node.js Essentials - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/html5/thumbnails/139.jpg)
Chapter9.UnitTestingWehavecomethisfarbuthaven’tdoneanytesting!That’snotverygood,isit?Usually,ifnotalways,testingisamajorconcerninsoftwaredevelopment.Inthischapter,wewillcoverunittestingconceptswithNode.
TherearemanytestingframeworksforNode.jsandinthischapterwewillbecoveringMocha.
![Page 140: Node.js Essentials - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/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 - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/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 - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/html5/thumbnails/142.jpg)
![Page 143: Node.js Essentials - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/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 - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/html5/thumbnails/144.jpg)
![Page 145: Node.js Essentials - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/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 - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/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 - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/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 - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/html5/thumbnails/148.jpg)
![Page 149: Node.js Essentials - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/html5/thumbnails/149.jpg)
SummaryEverythingweneedtocreateaNode.jsapplicationisnowatourfingertips.Testingisjustoneofthosethingsthatareessentialtoanysuccessfulsoftware.Wecoveredusingmochaasatestingframeworkandchaiasanassertionframework.
Inthenextchapter,wewillcoverusinganotherlanguagewithNode.js,CoffeeScript!
![Page 150: Node.js Essentials - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/html5/thumbnails/150.jpg)
![Page 151: Node.js Essentials - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/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 - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/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 - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/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 - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/html5/thumbnails/154.jpg)
![Page 155: Node.js Essentials - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/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 - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/html5/thumbnails/156.jpg)
if(date==null)
{
date=newDate();
}
returnkeys[key]=date;
};
Essentially,allCoffeeScriptdoesischeckifthevalueisnullorundefined.
![Page 157: Node.js Essentials - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/html5/thumbnails/157.jpg)
![Page 158: Node.js Essentials - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/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 - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/html5/thumbnails/159.jpg)
![Page 160: Node.js Essentials - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/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 - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/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 - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/html5/thumbnails/162.jpg)
![Page 163: Node.js Essentials - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/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 - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/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 - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/html5/thumbnails/165.jpg)
![Page 166: Node.js Essentials - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/html5/thumbnails/166.jpg)
![Page 167: Node.js Essentials - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/html5/thumbnails/167.jpg)
SummaryCoffeeScripttriestomakegoodassumptionswithyourcode.ThishelpstoremovesomeproblemsthatJavaScriptdeveloperscomeacross.Forexample,thedifferencebetween==and===.
YoucanlearnmoreaboutthespecificsyntaxofCoffeeScriptathttp://coffeescript.org/.
Inthischapterwehavecoveredutilizinganotherlanguage.ThiscanhelpalleviatethestruggleswithJavaScript’sstyleorsyntaxforbeginners.Forpeoplewhoareusedtomorelanguagefeatures,thisisabigadvantageasithelpsremovethepitfallsthatpeopleusuallycomeacross.
![Page 168: Node.js Essentials - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/html5/thumbnails/168.jpg)
IndexA
argumentsabout/Arguments
authenticationbasicauthentication/Basicauthentication
![Page 169: Node.js Essentials - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/html5/thumbnails/169.jpg)
BBDD(BehaviorDrivenDevelopment)/InstallingmochaBearertoken
about/Bearertokensbunyan
reference/Logging
![Page 170: Node.js Essentials - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/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 - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/html5/thumbnails/171.jpg)
Eenvironmentalvariables
about/Environmentalvariableserrorhandling
about/Errorhandlingexistentialoperator
about/Theexistentialoperator
![Page 172: Node.js Essentials - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/html5/thumbnails/172.jpg)
HHellorequireexample
about/HellorequireHTTPmethods
POST/IntroducingroutingGET/IntroducingroutingDELETE/Introducingrouting
![Page 173: Node.js Essentials - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/html5/thumbnails/173.jpg)
JJSONfiles
about/JSONfilesJSONWebToken(JWT)
about/BearertokensURL/Bearertokens
![Page 174: Node.js Essentials - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/html5/thumbnails/174.jpg)
LLevelDB
about/LevelDBlogging
about/Logging
![Page 175: Node.js Essentials - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/html5/thumbnails/175.jpg)
Mmethods
stubbing/Stubbingmethodsmocha
installing/Installingmochareference,forinterfaces/InstallingmochaURL/Installingmocha
MongoDBabout/MongoDB
MongoLababout/MongoDB
morganabout/Loggingreference/Logging
![Page 176: Node.js Essentials - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/html5/thumbnails/176.jpg)
NNode.js
settingup/SettingupURL/Settingup
npmabout/HellonpmURL/Hellonpmscriptsobject/Hellonpm
npmpackagescreating/Creatingnpmpackages
![Page 177: Node.js Essentials - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/html5/thumbnails/177.jpg)
OOAuth
about/OAuthURL/OAuth
![Page 178: Node.js Essentials - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/html5/thumbnails/178.jpg)
Rrouting
about/Introducingrouting
![Page 179: Node.js Essentials - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/html5/thumbnails/179.jpg)
SSinon.js/StubbingmethodsSocket.IO
rooms/Roomsauthentication/Authentication
spy/Stubbingmethodsstubfunction/Stubbingmethods
![Page 180: Node.js Essentials - luzala.orgluzala.org/Node.js Essentials.pdf · Node.js Essentials Credits About the Author About the Reviewer Support files, eBooks, discount offers, and more](https://reader034.vdocument.in/reader034/viewer/2022051806/5fff07b2eba6014ff025c2cd/html5/thumbnails/180.jpg)
Ttry/catchfunction/Errorhandling