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