Table of Contents · Express is a Node.js Web Framework. Node.js is an amazing tool for building...

61

Transcript of Table of Contents · Express is a Node.js Web Framework. Node.js is an amazing tool for building...

Page 1: Table of Contents · Express is a Node.js Web Framework. Node.js is an amazing tool for building networking services and applications. Express builds on top of its features to provide
Page 2: Table of Contents · Express is a Node.js Web Framework. Node.js is an amazing tool for building networking services and applications. Express builds on top of its features to provide

TableofContentsTheExpressHandbook

Expressoverview

Requestparameters

Sendingaresponse

SendingaJSONresponse

ManageCookies

WorkwithHTTPheaders

Redirects

Routing

CORS

Templating

ThePugGuide

Middleware

Servingstaticfiles

Sendfiles

Sessions

Validatinginput

Sanitizinginput

Handlingforms

Fileuploadsinforms

AnExpressHTTPSserverwithaself-signedcertificate

SetupLet'sEncryptforExpress

2

Page 3: Table of Contents · Express is a Node.js Web Framework. Node.js is an amazing tool for building networking services and applications. Express builds on top of its features to provide

TheExpressHandbookTheExpressHandbookfollowsthe80/20rule:learnin20%ofthetimethe80%ofatopic.

Ifindthisapproachgivesawell-roundedoverview.ThisbookdoesnottrytocovereverythingunderthesunrelatedtoExpress.Ifyouthinksomespecifictopicshouldbeincluded,tellme.

YoucanreachmeonTwitter@flaviocopes.

Ihopethecontentsofthisbookwillhelpyouachievewhatyouwant:learnthebasicsExpress.

ThisbookiswrittenbyFlavio.Ipublishwebdevelopmenttutorialseverydayonmywebsiteflaviocopes.com.

Enjoy!

TheExpressHandbook

3

Page 4: Table of Contents · Express is a Node.js Web Framework. Node.js is an amazing tool for building networking services and applications. Express builds on top of its features to provide

ExpressoverviewExpressisaNode.jsWebFramework.Node.jsisanamazingtoolforbuildingnetworkingservicesandapplications.ExpressbuildsontopofitsfeaturestoprovideeasytousefunctionalitythatsatisfytheneedsoftheWebServerusecase.

ExpressisaNode.jsWebFramework.

Node.jsisanamazingtoolforbuildingnetworkingservicesandapplications.

ExpressbuildsontopofitsfeaturestoprovideeasytousefunctionalitythatsatisfytheneedsoftheWebServerusecase.

It'sOpenSource,free,easytoextend,veryperformant,andhaslotsandlotsofpre-builtpackagesyoucanjustdropinanduse,toperformallkindofthings.

InstallationYoucaninstallExpressintoanyprojectwithnpm:

Expressoverview

4

Page 5: Table of Contents · Express is a Node.js Web Framework. Node.js is an amazing tool for building networking services and applications. Express builds on top of its features to provide

npminstallexpress--save

orYarn:

yarnaddexpress

Bothcommandswillalsoworkinanemptydirectory,tostartupyourprojectfromscratch,although npmdoesnotcreatea package.jsonfileatall,andYarncreatesabasicone.

Justrun npminitor yarninitifyou'restartinganewprojectfromscratch.

HelloWorldWe'rereadytocreateourfirstExpressWebServer.

Hereissomecode:

constexpress=require('express')

constapp=express()

app.get('/',(req,res)=>res.send('HelloWorld!'))

app.listen(3000,()=>console.log('Serverready'))

Savethistoan index.jsfileinyourprojectrootfolder,andstarttheserverusing

nodeindex.js

Youcanopenthebrowsertoport3000onlocalhostandyoushouldseethe HelloWorld!message.

LearnthebasicsofExpressbyunderstandingtheHelloWorldcodeThose4linesofcodedoalotbehindthescenes.

First,weimportthe expresspackagetothe expressvalue.

Weinstantiateanapplicationbycallingits app()method.

Oncewehavetheapplicationobject,wetellittolistenforGETrequestsonthe /path,usingthe get()method.

Expressoverview

5

Page 6: Table of Contents · Express is a Node.js Web Framework. Node.js is an amazing tool for building networking services and applications. Express builds on top of its features to provide

ThereisamethodforeveryHTTPverb: get(), post(), put(), delete(), patch():

app.get('/',(req,res)=>{/**/})

app.post('/',(req,res)=>{/**/})

app.put('/',(req,res)=>{/**/})

app.delete('/',(req,res)=>{/**/})

app.patch('/',(req,res)=>{/**/})

Thosemethodsacceptacallbackfunction,whichiscalledwhenarequestisstarted,andweneedtohandleit.

Wepassinanarrowfunction:

(req,res)=>res.send('HelloWorld!')

Expresssendsustwoobjectsinthiscallback,whichwecalled reqand res,thatrepresenttheRequestandtheResponseobjects.

RequestistheHTTPrequest.Itcangiveusalltheinfoaboutthat,includingtherequestparameters,theheaders,thebodyoftherequest,andmore.

ResponseistheHTTPresponseobjectthatwe'llsendtotheclient.

Whatwedointhiscallbackistosendthe'HelloWorld!'stringtotheclient,usingtheResponse.send()method.

Thismethodsetsthatstringasthebody,anditclosestheconnection.

Thelastlineoftheexampleactuallystartstheserver,andtellsittolistenonport 3000.Wepassinacallbackthatiscalledwhentheserverisreadytoacceptnewrequests.

Expressoverview

6

Page 7: Table of Contents · Express is a Node.js Web Framework. Node.js is an amazing tool for building networking services and applications. Express builds on top of its features to provide

RequestparametersAhandyreferencetoalltherequestobjectpropertiesandhowtousethem

RequestparametersImentionedhowtheRequestobjectholdsalltheHTTPrequestinformation.

Thesearethemainpropertiesyou'lllikelyuse:

Property Description

.app holdsareferencetotheExpressappobject

.baseUrl thebasepathonwhichtheappresponds

.body containsthedatasubmittedintherequestbody(mustbeparsedandpopulatedmanuallybeforeyoucanaccessit)

.cookies containsthecookiessentbytherequest(needsthe cookie-parsermiddleware)

.hostname theserverhostname

.ip theserverIP

.method theHTTPmethodused

.params theroutenamedparameters

.path theURLpath

.protocol therequestprotocol

.query anobjectcontainingallthequerystringsusedintherequest

.secure trueiftherequestissecure(usesHTTPS)

.signedCookies containsthesignedcookiessentbytherequest(needsthe cookie-parsermiddleware)

.xhr trueiftherequestisanXMLHttpRequest

HowtoretrievetheGETquerystringparametersusingExpressThequerystringisthepartthatcomesaftertheURLpath,andstartswithanexclamationmark ?.

Requestparameters

7

Page 8: Table of Contents · Express is a Node.js Web Framework. Node.js is an amazing tool for building networking services and applications. Express builds on top of its features to provide

Example:

?name=flavio

Multiplequeryparameterscanbeaddedusing &:

?name=flavio&age=35

HowdoyougetthosequerystringvaluesinExpress?

Expressmakesitveryeasybypopulatingthe Request.queryobjectforus:

constexpress=require('express')

constapp=express()

app.get('/',(req,res)=>{

console.log(req.query)

})

app.listen(8080)

Thisobjectisfilledwithapropertyforeachqueryparameter.

Iftherearenoqueryparams,it'sanemptyobject.

Thismakesiteasytoiterateonitusingthefor...inloop:

for(constkeyinreq.query){

console.log(key,req.query[key])

}

Thiswillprintthequerypropertykeyandthevalue.

Youcanaccesssinglepropertiesaswell:

req.query.name//flavio

req.query.age//35

HowtoretrievethePOSTquerystringparametersusingExpressPOSTqueryparametersaresentbyHTTPclientsforexamplebyforms,orwhenperformingaPOSTrequestsendingdata.

Requestparameters

8

Page 9: Table of Contents · Express is a Node.js Web Framework. Node.js is an amazing tool for building networking services and applications. Express builds on top of its features to provide

Howcanyouaccessthisdata?

IfthedatawassentasJSON,using Content-Type:application/json,youwillusetheexpress.json()middleware:

constexpress=require('express')

constapp=express()

app.use(express.json())

IfthedatawassentasJSON,using Content-Type:application/x-www-form-urlencoded,youwillusethe express.urlencoded()middleware:

constexpress=require('express')

constapp=express()

app.use(express.urlencoded())

Inbothcasesyoucanaccessthedatabyreferencingitfrom Request.body:

app.post('/form',(req,res)=>{

constname=req.body.name

})

Note:olderExpressversionsrequiredtheuseofthe body-parsermoduletoprocessPOSTdata.ThisisnolongerthecaseasofExpress4.16(releasedinSeptember2017)andlaterversions.

Requestparameters

9

Page 10: Table of Contents · Express is a Node.js Web Framework. Node.js is an amazing tool for building networking services and applications. Express builds on top of its features to provide

SendingaresponseHowtosendaresponsebacktotheclientusingExpress

IntheHelloWorldexampleweusedthe Response.send()methodtosendasimplestringasaresponse,andtoclosetheconnection:

(req,res)=>res.send('HelloWorld!')

Ifyoupassinastring,itsetsthe Content-Typeheaderto text/html.

ifyoupassinanobjectoranarray,itsetsthe application/json Content-Typeheader,andparsesthatparameterintoJSON.

send()automaticallysetsthe Content-LengthHTTPresponseheader.

send()alsoautomaticallyclosestheconnection.

Useend()tosendanemptyresponse

Analternativewaytosendtheresponse,withoutanybody,it'sbyusingthe Response.end()method:

res.end()

SettheHTTPresponsestatus

Usethe Response.status():

res.status(404).end()

or

res.status(404).send('Filenotfound')

sendStatus()isashortcut:

res.sendStatus(200)

//===res.status(200).send('OK')

res.sendStatus(403)

//===res.status(403).send('Forbidden')

Sendingaresponse

10

Page 11: Table of Contents · Express is a Node.js Web Framework. Node.js is an amazing tool for building networking services and applications. Express builds on top of its features to provide

res.sendStatus(404)

//===res.status(404).send('NotFound')

res.sendStatus(500)

//===res.status(500).send('InternalServerError')

Sendingaresponse

11

Page 12: Table of Contents · Express is a Node.js Web Framework. Node.js is an amazing tool for building networking services and applications. Express builds on top of its features to provide

SendingaJSONresponseHowtoserveJSONdatausingtheNode.jsExpresslibrary

WhenyoulistenforconnectionsonarouteinExpress,thecallbackfunctionwillbeinvokedoneverynetworkcallwithaRequestobjectinstanceandaResponseobjectinstance.

Example:

app.get('/',(req,res)=>res.send('HelloWorld!'))

Hereweusedthe Response.send()method,whichacceptsanystring.

YoucansendJSONtotheclientbyusing Response.json(),ausefulmethod.

Itacceptsanobjectorarray,andconvertsittoJSONbeforesendingit:

res.json({username:'Flavio'})

SendingaJSONresponse

12

Page 13: Table of Contents · Express is a Node.js Web Framework. Node.js is an amazing tool for building networking services and applications. Express builds on top of its features to provide

ManageCookiesHowtousethe`Response.cookie()`methodtomanipulateyourcookies

Usethe Response.cookie()methodtomanipulateyourcookies.

Examples:

res.cookie('username','Flavio')

Thismethodacceptsathirdparameterwhichcontainsvariousoptions:

res.cookie('username','Flavio',{domain:'.flaviocopes.com',path:'/administrator',sec

ure:true})

res.cookie('username','Flavio',{expires:newDate(Date.now()+900000),httpOnly:true

})

Themostusefulparametersyoucansetare:

Value Description

domain thecookiedomainname

expiressetthecookieexpirationdate.Ifmissing,or0,thecookieisasessioncookie

httpOnly setthecookietobeaccessibleonlybythewebserver.SeeHttpOnly

maxAge settheexpirytimerelativetothecurrenttime,expressedinmilliseconds

path thecookiepath.Defaultsto/

secure MarksthecookieHTTPSonly

signed setthecookietobesigned

sameSite Valueof SameSite

Acookiecanbeclearedwith

res.clearCookie('username')

ManageCookies

13

Page 14: Table of Contents · Express is a Node.js Web Framework. Node.js is an amazing tool for building networking services and applications. Express builds on top of its features to provide

WorkwithHTTPheadersLearnhowtoaccessandchangeHTTPheadersusingExpress

AccessHTTPheadersvaluesfromarequestYoucanaccessalltheHTTPheadersusingthe Request.headersproperty:

app.get('/',(req,res)=>{

console.log(req.headers)

})

Usethe Request.header()methodtoaccessoneindividualrequestheadervalue:

app.get('/',(req,res)=>{

req.header('User-Agent')

})

ChangeanyHTTPheadervalueofaresponseYoucanchangeanyHTTPheadervalueusing Response.set():

res.set('Content-Type','text/html')

ThereisashortcutfortheContent-Typeheaderhowever:

res.type('.html')

//=>'text/html'

res.type('html')

//=>'text/html'

res.type('json')

//=>'application/json'

res.type('application/json')

//=>'application/json'

res.type('png')

//=>image/png:

WorkwithHTTPheaders

14

Page 15: Table of Contents · Express is a Node.js Web Framework. Node.js is an amazing tool for building networking services and applications. Express builds on top of its features to provide

WorkwithHTTPheaders

15

Page 16: Table of Contents · Express is a Node.js Web Framework. Node.js is an amazing tool for building networking services and applications. Express builds on top of its features to provide

RedirectsHowtoredirecttootherpagesserver-side

RedirectsarecommoninWebDevelopment.YoucancreatearedirectusingtheResponse.redirect()method:

res.redirect('/go-there')

Thiscreatesa302redirect.

A301redirectismadeinthisway:

res.redirect(301,'/go-there')

Youcanspecifyanabsolutepath( /go-there),anabsoluteurl( https://anothersite.com),arelativepath( go-there)orusethe ..togobackonelevel:

res.redirect('../go-there')

res.redirect('..')

YoucanalsoredirectbacktotheRefererHTTPheadervalue(defaultingto /ifnotset)using

res.redirect('back')

Redirects

16

Page 17: Table of Contents · Express is a Node.js Web Framework. Node.js is an amazing tool for building networking services and applications. Express builds on top of its features to provide

RoutingRoutingistheprocessofdeterminingwhatshouldhappenwhenaURLiscalled,oralsowhichpartsoftheapplicationshouldhandleaspecificincomingrequest.

RoutingistheprocessofdeterminingwhatshouldhappenwhenaURLiscalled,oralsowhichpartsoftheapplicationshouldhandleaspecificincomingrequest.

IntheHelloWorldexampleweusedthiscode

app.get('/',(req,res)=>{/**/})

ThiscreatesaroutethatmapsaccessingtherootdomainURL /usingtheHTTPGETmethodtotheresponsewewanttoprovide.

Namedparameters

Whatifwewanttolistenforcustomrequests,maybewewanttocreateaservicethatacceptsastring,andreturnsthatuppercase,andwedon'twanttheparametertobesentasaquerystring,butpartoftheURL.Weusenamedparameters:

app.get('/uppercase/:theValue',(req,res)=>res.send(req.params.theValue.toUpperCase()))

Ifwesendarequestto /uppercase/test,we'llget TESTinthebodyoftheresponse.

YoucanusemultiplenamedparametersinthesameURL,andtheywillallbestoredinreq.params.

Usearegularexpressiontomatchapath

Youcanuseregularexpressionstomatchmultiplepathswithonestatement:

app.get(/post/,(req,res)=>{/**/})

willmatch /post, /post/first, /thepost, /posting/something,andsoon.

Routing

17

Page 18: Table of Contents · Express is a Node.js Web Framework. Node.js is an amazing tool for building networking services and applications. Express builds on top of its features to provide

CORSHowtoallowcrosssiterequestsbysettingupCORS

AJavaScriptapplicationrunninginthebrowsercanusuallyonlyaccessHTTPresourcesonthesamedomain(origin)thatservesit.

Loadingimagesorscripts/stylesalwaysworks,butXHRandFetchcallstoanotherserverwillfail,unlessthatserverimplementsawaytoallowthatconnection.

ThiswayiscalledCORS,Cross-OriginResourceSharing.

AlsoloadingWebFontsusing @font-facehassame-originpolicybydefault,andotherlesspopularthings(likeWebGLtexturesand drawImageresourcesloadedintheCanvasAPI).

OneveryimportantthingthatneedsCORSisESModules,recentlyintroducedinmodernbrowsers.

Ifyoudon'tsetupaCORSpolicyontheserverthatallowstoserve3rdpartorigins,therequestwillfail.

Fetchexample:

XHRexample:

CORS

18

Page 19: Table of Contents · Express is a Node.js Web Framework. Node.js is an amazing tool for building networking services and applications. Express builds on top of its features to provide

ACross-Originresourcefailsifit's:

toadifferentdomaintoadifferentsubdomaintoadifferentporttoadifferentprotocol

andit'sthereforyoursecurity,topreventmalicioususerstoexploittheWebPlatform.

Butifyoucontrolboththeserverandtheclient,youhaveallthegoodreasonstoallowthemtotalktoeachother.

How?

Itdependsonyourserver-sidestack.

BrowsersupportPrettygood(basicallyallexceptIE<10):

ExamplewithExpressIfyouareusingNode.jsandExpressasaframework,usetheCORSmiddlewarepackage.

Here'sasimpleimplementationofanExpressNode.jsserver:

constexpress=require('express')

constapp=express()

CORS

19

Page 20: Table of Contents · Express is a Node.js Web Framework. Node.js is an amazing tool for building networking services and applications. Express builds on top of its features to provide

app.get('/without-cors',(req,res,next)=>{

res.json({msg:'ۘ noCORS,noparty!'})

})

constserver=app.listen(3000,()=>{

console.log('Listeningonport%s',server.address().port)

})

Ifyouhit /without-corswithafetchrequestfromadifferentorigin,it'sgoingtoraisetheCORSissue.

Allyouneedtodotomakethingsworkoutistorequirethe corspackagelinkedabove,andpassitinasamiddlewarefunctiontoanendpointrequesthandler:

constexpress=require('express')

constcors=require('cors')

constapp=express()

app.get('/with-cors',cors(),(req,res,next)=>{

res.json({msg:'WHOAHwithCORSitworks!ث ʦ '})

})

/*therestoftheapp*/

ImadeasimpleGlitchexample.Hereistheclientworking,andhere'sitscode:https://glitch.com/edit/#!/flavio-cors-client.

ThisistheNode.jsExpressserver:https://glitch.com/edit/#!/flaviocopes-cors-example-express

NotehowtherequestthatfailsbecauseitdoesnothandletheCORSheadingscorrectlyisstillreceived,asyoucanseeintheNetworkpanel,whereyoufindthemessagetheserversent:

CORS

20

Page 21: Table of Contents · Express is a Node.js Web Framework. Node.js is an amazing tool for building networking services and applications. Express builds on top of its features to provide

AllowonlyspecificoriginsThisexamplehasaproblemhowever:ANYrequestwillbeacceptedbytheserverascross-origin.

AsyoucanseeintheNetworkpanel,therequestthatpassedhasaresponseheader access-control-allow-origin:*:

Youneedtoconfiguretheservertoonlyallowoneorigintoserve,andblockalltheothers.

Usingthesame corsNodelibrary,here'showyouwoulddoit:

constcors=require('cors')

constcorsOptions={

origin:'https://yourdomain.com'

}

app.get('/products/:id',cors(corsOptions),(req,res,next)=>{

//...

})

Youcanservemoreaswell:

constwhitelist=['http://example1.com','http://example2.com']

constcorsOptions={

origin:function(origin,callback){

if(whitelist.indexOf(origin)!==-1){

callback(null,true)

}else{

callback(newError('NotallowedbyCORS'))

}

}

}

CORS

21

Page 22: Table of Contents · Express is a Node.js Web Framework. Node.js is an amazing tool for building networking services and applications. Express builds on top of its features to provide

PreflightTherearesomerequeststhatarehandledina"simple"way.All GETrequestsbelongtothisgroup.

Alsosome POSTand HEADrequestsdoaswell.

POSTrequestsarealsointhisgroup,iftheysatisfytherequirementofusingaContent-Typeof

application/x-www-form-urlencoded

multipart/form-data

text/plain

Allotherrequestsmustrunthroughapre-approvalphase,calledpreflight.Thebrowserdoesthistodetermineifithasthepermissiontoperformanaction,byissuingan OPTIONSrequest.

Apreflightrequestcontainsafewheadersthattheserverwillusetocheckpermissions(irrelevantfieldsomitted):

OPTIONS/the/resource/you/request

Access-Control-Request-Method:POST

Access-Control-Request-Headers:origin,x-requested-with,accept

Origin:https://your-origin.com

Theserverwillrespondwithsomethinglikethis(irrelevantfieldsomitted):

HTTP/1.1200OK

Access-Control-Allow-Origin:https://your-origin.com

Access-Control-Allow-Methods:POST,GET,OPTIONS,DELETE

WecheckedforPOST,buttheservertellsuswecanalsoissueotherHTTPrequesttypesforthatparticularresource.

FollowingtheNode.jsExpressexampleabove,theservermustalsohandletheOPTIONSrequest:

varexpress=require('express')

varcors=require('cors')

varapp=express()

//allowOPTIONSonjustoneresource

app.options('/the/resource/you/request',cors())

//allowOPTIONSonallresources

app.options('*',cors())

CORS

22

Page 23: Table of Contents · Express is a Node.js Web Framework. Node.js is an amazing tool for building networking services and applications. Express builds on top of its features to provide

CORS

23

Page 24: Table of Contents · Express is a Node.js Web Framework. Node.js is an amazing tool for building networking services and applications. Express builds on top of its features to provide

TemplatingExpressiscapableofhandlingserver-sidetemplateengines.Templateenginesallowustoadddatatoaview,andgenerateHTMLdynamically.

Expressiscapableofhandlingserver-sidetemplateengines.

Templateenginesallowustoadddatatoaview,andgenerateHTMLdynamically.

ExpressusesJadeasthedefault.JadeistheoldversionofPug,specificallyPug1.0.

ThenamewaschangedfromJadetoPugduetoatrademarkissuein2016,whentheprojectreleasedversion2.YoucanstilluseJade,akaPug1.0,butgoingforward,it'sbesttousePug2.0

AlthoughthelastversionofJadeis3yearsold(atthetimeofwriting,summer2018),it'sstillthedefaultinExpressforbackwardcompatibilityreasons.

Inanynewproject,youshouldusePugoranotherengineofyourchoice.TheofficialsiteofPugishttps://pugjs.org/.

Youcanusemanydifferenttemplateengines,includingPug,Handlebars,Mustache,EJSandmore.

UsingPugTousePugwemustfirstinstallit:

npminstallpug

andwheninitializingtheExpressapp,weneedtosetit:

constexpress=require('express')

constapp=express()

app.set('viewengine','pug')

Wecannowstartwritingourtemplatesin .pugfiles.

Createanaboutview:

app.get('/about',(req,res)=>{

res.render('about')

})

Templating

24

Page 25: Table of Contents · Express is a Node.js Web Framework. Node.js is an amazing tool for building networking services and applications. Express builds on top of its features to provide

andthetemplatein views/about.pug:

pHellofromFlavio

Thistemplatewillcreatea ptagwiththecontent HellofromFlavio.

Youcaninterpolateavariableusing

app.get('/about',(req,res)=>{

res.render('about',{name:'Flavio'})

})

pHellofrom#{name}

ThisisaveryshortintroductiontoPug,inthecontextofusingitwithExpress.LookatthePugguideformoreinformationonhowtousePug.

IfyouareusedtotemplateenginesthatuseHTMLandinterpolatevariables,likeHandlebars(describednext),youmightrunintoissues,especiallywhenyouneedtoconvertexistingHTMLtoPug.ThisonlineconverterfromHTMLtoJade(whichisverysimilar,butalittledifferentthanPug)willbeagreathelp:https://jsonformatter.org/html-to-jade

AlsoseethedifferencesbetweenJadeandPug

UsingHandlebarsLet'stryanduseHandlebarsinsteadofPug.

Youcaninstallitusing npminstallhbs.

Putan about.hbstemplatefileinthe views/folder:

Hellofrom{{name}}

andthenusethisExpressconfigurationtoserveiton /about:

constexpress=require('express')

constapp=express()

consthbs=require('hbs')

app.set('viewengine','hbs')

app.set('views',path.join(__dirname,'views'))

app.get('/about',(req,res)=>{

Templating

25

Page 26: Table of Contents · Express is a Node.js Web Framework. Node.js is an amazing tool for building networking services and applications. Express builds on top of its features to provide

res.render('about',{name:'Flavio'})

})

app.listen(3000,()=>console.log('Serverready'))

YoucanalsorenderaReactapplicationserver-side,usingthe express-react-viewspackage.

Startwith npminstallexpress-react-viewsreactreact-dom.

Nowinsteadofrequiring hbswerequire express-react-viewsandusethatastheengine,using jsxfiles:

constexpress=require('express')

constapp=express()

app.set('viewengine','jsx')

app.engine('jsx',require('express-react-views').createEngine())

app.get('/about',(req,res)=>{

res.render('about',{name:'Flavio'})

})

app.listen(3000,()=>console.log('Serverready'))

Justputan about.jsxfilein views/,andcalling /aboutshouldpresentyouan"HellofromFlavio"string:

constReact=require('react')

classHelloMessageextendsReact.Component{

render(){

return<div>Hellofrom{this.props.name}</div>

}

}

module.exports=HelloMessage

Templating

26

Page 27: Table of Contents · Express is a Node.js Web Framework. Node.js is an amazing tool for building networking services and applications. Express builds on top of its features to provide

ThePugGuideHowtousethePugtemplatingengine

IntroductiontoPugHowdoesPuglooklikeInstallPugSetupPugtobethetemplateengineinExpressYourfirstPugtemplateInterpolatingvariablesinPugInterpolateafunctionreturnvalueAddingidandclassattributestoelementsSetthedoctypeMetatagsAddingscriptsandstylesInlinescriptsLoopsConditionalsSetvariablesIncrementingvariablesAssigningvariablestoelementvaluesIteratingovervariablesIncludingotherPugfilesDefiningblocksExtendingabasetemplateComments

VisibleInvisible

IntroductiontoPugWhatisPug?It'satemplateengineforserver-sideNode.jsapplications.

Expressiscapableofhandlingserver-sidetemplateengines.Templateenginesallowustoadddatatoaview,andgenerateHTMLdynamically.

Pugisanewnameforanoldthing.It'sJade2.0.

ThePugGuide

27

Page 28: Table of Contents · Express is a Node.js Web Framework. Node.js is an amazing tool for building networking services and applications. Express builds on top of its features to provide

ThenamewaschangedfromJadetoPugduetoatrademarkissuein2016,whentheprojectreleasedversion2.YoucanstilluseJade,akaPug1.0,butgoingforward,it'sbesttousePug2.0

AlsoseethedifferencesbetweenJadeandPug

ExpressusesJadeasthedefault.JadeistheoldversionofPug,specificallyPug1.0.

AlthoughthelastversionofJadeis3yearsold(atthetimeofwriting,summer2018),it'sstillthedefaultinExpressforbackwardcompatibilityreasons.

Inanynewproject,youshouldusePugoranotherengineofyourchoice.TheofficialsiteofPugishttps://pugjs.org/.

HowdoesPuglooklike

pHellofromFlavio

Thistemplatewillcreatea ptagwiththecontent HellofromFlavio.

Asyoucansee,Pugisquitespecial.Ittakesthetagnameasthefirstthinginaline,andtherestisthecontentthatgoesinsideit.

IfyouareusedtotemplateenginesthatuseHTMLandinterpolatevariables,likeHandlebars(describednext),youmightrunintoissues,especiallywhenyouneedtoconvertexistingHTMLtoPug.ThisonlineconverterfromHTMLtoJade(whichisverysimilar,butalittledifferentthanPug)willbeagreathelp:https://jsonformatter.org/html-to-jade

InstallPugInstallingPugisassimpleasrunning npminstall:

npminstallpug

SetupPugtobethetemplateengineinExpressandwheninitializingtheExpressapp,weneedtosetit:

constexpress=require('express')

constapp=express()

app.set('viewengine','pug')

ThePugGuide

28

Page 29: Table of Contents · Express is a Node.js Web Framework. Node.js is an amazing tool for building networking services and applications. Express builds on top of its features to provide

app.set('views',path.join(__dirname,'views'))

YourfirstPugtemplateCreateanaboutview:

app.get('/about',(req,res)=>{

res.render('about')

})

andthetemplatein views/about.pug:

pHellofromFlavio

Thistemplatewillcreatea ptagwiththecontent HellofromFlavio.

InterpolatingvariablesinPugYoucaninterpolateavariableusing

app.get('/about',(req,res)=>{

res.render('about',{name:'Flavio'})

})

pHellofrom#{name}

InterpolateafunctionreturnvalueYoucaninterpolateafunctionreturnvalueusing

app.get('/about',(req,res)=>{

res.render('about',{getName:()=>'Flavio'})

})

pHellofrom#{getName()}

Addingidandclassattributestoelements

ThePugGuide

29

Page 30: Table of Contents · Express is a Node.js Web Framework. Node.js is an amazing tool for building networking services and applications. Express builds on top of its features to provide

p#title

p.title

Setthedoctype

doctypehtml

Metatags

html

head

meta(charset='utf-8')

meta(http-equiv='X-UA-Compatible',content='IE=edge')

meta(name='description',content='Somedescription')

meta(name='viewport',content='width=device-width,initial-scale=1')

Addingscriptsandstyles

html

head

script(src="script.js")

script(src='//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js')

link(rel='stylesheet',href='css/main.css')

Inlinescripts

scriptalert('test')

script

(function(b,o,i,l,e,r){b.GoogleAnalyticsObject=l;b[l]||(b[l]=

function(){(b[l].q=b[l].q||[]).push(arguments)});b[l].l=+newDate;

e=o.createElement(i);r=o.getElementsByTagName(i)[0];

e.src='//www.google-analytics.com/analytics.js';

r.parentNode.insertBefore(e,r)}(window,document,'script','ga'));

ga('create','UA-XXXXX-X');ga('send','pageview');

Loops

ThePugGuide

30

Page 31: Table of Contents · Express is a Node.js Web Framework. Node.js is an amazing tool for building networking services and applications. Express builds on top of its features to provide

ul

eachcolorin['Red','Yellow','Blue']

li=color

ul

eachcolor,indexin['Red','Yellow','Blue']

li='Colornumber'+index+':'+color

Conditionals

ifname

h2Hellofrom#{name}

else

h2Hello

else-ifworkstoo:

ifname

h2Hellofrom#{name}

elseifanotherName

h2Hellofrom#{anotherName}

else

h2Hello

SetvariablesYoucansetvariablesinPugtemplates:

-varname='Flavio'

-varage=35

-varroger={name:'Roger'}

-vardogs=['Roger','Syd']

IncrementingvariablesYoucanincrementanumericvariableusing ++:

age++

Assigningvariablestoelementvalues

ThePugGuide

31

Page 32: Table of Contents · Express is a Node.js Web Framework. Node.js is an amazing tool for building networking services and applications. Express builds on top of its features to provide

p=name

span.age=age

IteratingovervariablesYoucanuse foror each.Thereisnodifference.

fordogindogs

li=dog

ul

eachdogindogs

li=dog

Youcanuse .lengthtogetthenumberofitems:

pThereare#{values.length}

whileisanotherkindofloop:

-varn=0;

ul

whilen<=5

li=n++

IncludingotherPugfilesInaPugfileyoucanincludeotherPugfiles:

includeotherfile.pug

DefiningblocksAwellorganizedtemplatesystemwilldefineabasetemplate,andthenalltheothertemplatesextendfromit.

ThePugGuide

32

Page 33: Table of Contents · Express is a Node.js Web Framework. Node.js is an amazing tool for building networking services and applications. Express builds on top of its features to provide

Thewayapartofatemplatecanbeextendedisbyusingblocks:

html

head

script(src="script.js")

script(src='//ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js')

link(rel='stylesheet',href='css/main.css')

blockhead

body

blockbody

h1Homepage

pwelcome

Inthiscaseoneblock, body,hassomecontent,while headdoesnot. headisintendedtobeusedtoaddadditionalcontenttotheheading,whilethe bodycontentismadetobeoverriddenbyotherpages.

ExtendingabasetemplateAtemplatecanextendabasetemplatebyusingthe extendskeyword:

extendshome.pug

Oncethisisdone,youneedtoredefineblocks.Allthecontentofthetemplatemustgointoblocks,otherwisetheenginedoesnotknowwheretoputthem.

Example:

extendshome.pug

blockbody

h1Anotherpage

pHey!

ul

liSomething

liSomethingelse

Youcanredefineoneormoreblocks.Theonesnotredefinedwillbekeptwiththeoriginaltemplatecontent.

CommentsCommentsinPugcanbeoftwotypes:visibleornotvisibleintheresultingHTML.

ThePugGuide

33

Page 34: Table of Contents · Express is a Node.js Web Framework. Node.js is an amazing tool for building networking services and applications. Express builds on top of its features to provide

Visible

Inline:

//somecomment

Block:

//

some

comment

Invisible

Inline:

//-somecomment

Block:

//-

some

comment

ThePugGuide

34

Page 35: Table of Contents · Express is a Node.js Web Framework. Node.js is an amazing tool for building networking services and applications. Express builds on top of its features to provide

MiddlewareAmiddlewareisafunctionthathooksintotheroutingprocess,andperformssomeoperationatsomepoint,dependingonwhatitwanttodo.

Amiddlewareisafunctionthathooksintotheroutingprocess,andperformssomeoperationatsomepoint,dependingonwhatitwanttodo.

It'scommonlyusedtoedittherequestorresponseobjects,orterminatetherequestbeforeitreachestheroutehandlercode.

It'saddedtotheexecutionstacklikethis:

app.use((req,res,next)=>{/**/})

Thisissimilartodefiningaroute,butinadditiontotheRequestandResponseobjectsinstances,wealsohaveareferencetothenextmiddlewarefunction,whichweassigntothevariable next.

Wealwayscall next()attheendofourmiddlewarefunction,topasstheexecutiontothenexthandler,unlesswewanttoprematurelyendtheresponse,andsenditbacktotheclient.

Youtypicallyusepre-mademiddleware,intheformof npmpackages.Abiglistoftheavailableonesishere.

Oneexampleis cookie-parser,whichisusedtoparsethecookiesintothe req.cookiesobject.Youinstallitusing npminstallcookie-parserandyoucanuseitlikethis:

constexpress=require('express')

constapp=express()

constcookieParser=require('cookie-parser')

app.get('/',(req,res)=>res.send('HelloWorld!'))

app.use(cookieParser())

app.listen(3000,()=>console.log('Serverready'))

Youcanalsosetamiddlewarefunctiontorunforspecificroutesonly,notforall,byusingitasthesecondparameteroftheroutedefinition:

constmyMiddleware=(req,res,next)=>{

/*...*/

next()

}

app.get('/',myMiddleware,(req,res)=>res.send('HelloWorld!'))

Middleware

35

Page 36: Table of Contents · Express is a Node.js Web Framework. Node.js is an amazing tool for building networking services and applications. Express builds on top of its features to provide

Ifyouneedtostoredatathat'sgeneratedinamiddlewaretopassitdowntosubsequentmiddlewarefunctions,ortotherequesthandler,youcanusethe Request.localsobject.Itwillattachthatdatatothecurrentrequest:

req.locals.name='Flavio'

Middleware

36

Page 37: Table of Contents · Express is a Node.js Web Framework. Node.js is an amazing tool for building networking services and applications. Express builds on top of its features to provide

ServingstaticfilesHowtoservestaticassetsdirectlyfromafolderinExpress

It'scommontohaveimages,CSSandmoreina publicsubfolder,andexposethemtotherootlevel:

constexpress=require('express')

constapp=express()

app.use(express.static('public'))

/*...*/

app.listen(3000,()=>console.log('Serverready'))

Ifyouhavean index.htmlfilein public/,thatwillbeservedifyounowhittherootdomainURL( http://localhost:3000)

Servingstaticfiles

37

Page 38: Table of Contents · Express is a Node.js Web Framework. Node.js is an amazing tool for building networking services and applications. Express builds on top of its features to provide

SendfilesExpressprovidesahandymethodtotransferafileasattachment:`Response.download()`

Expressprovidesahandymethodtotransferafileasattachment: Response.download().

Onceauserhitsaroutethatsendsafileusingthismethod,browserswillprompttheuserfordownload.

The Response.download()methodallowsyoutosendafileattachedtotherequest,andthebrowserinsteadofshowingitinthepage,itwillsaveittodisk.

app.get('/',(req,res)=>res.download('./file.pdf'))

Inthecontextofanapp:

constexpress=require('express')

constapp=express()

app.get('/',(req,res)=>res.download('./file.pdf'))

app.listen(3000,()=>console.log('Serverready'))

Youcansetthefiletobesentwithacustomfilename:

res.download('./file.pdf','user-facing-filename.pdf')

Thismethodprovidesacallbackfunctionwhichyoucanusetoexecutecodeoncethefilehasbeensent:

res.download('./file.pdf','user-facing-filename.pdf',(err)=>{

if(err){

//handleerror

return

}else{

//dosomething

}

})

Sendfiles

38

Page 39: Table of Contents · Express is a Node.js Web Framework. Node.js is an amazing tool for building networking services and applications. Express builds on top of its features to provide

SessionsHowtousesessionstoidentifyusersacrossrequests

BydefaultExpressrequestsaresequentialandnorequestcanbelinkedtoeachother.Thereisnowaytoknowifthisrequestcomesfromaclientthatalreadyperformedarequestpreviously.

Userscannotbeidentifiedunlessusingsomekindofmechanismthatmakesitpossible.

That'swhatsessionsare.

Whenimplemented,everyuserofyouAPIorwebsitewillbeassignedauniquesession,andthisallowsyoutostoretheuserstate.

We'llusethe express-sessionmodule,whichismaintainedbytheExpressteam.

Youcaninstallitusing

npminstallexpress-session

andonceyou'redone,youcaninstantiateitinyourapplicationwith

constsession=require('express-session')

Thisisamiddleware,soyouinstallitinExpressusing

constexpress=require('express')

constsession=require('express-session')

constapp=express()

app.use(session(

'secret':'343ji43j4n3jn4jk3n'

))

Afterthisisdone,alltherequeststotheapproutesarenowusingsessions.

secretistheonlyrequiredparameter,buttherearemanymoreyoucanuse.Itshouldbearandomlyuniquestringforyouapplication.

Thesessionisattachedtotherequest,soyoucanaccessitusing req.sessionhere:

app.get('/',(req,res,next)=>{

//req.session

}

Sessions

39

Page 40: Table of Contents · Express is a Node.js Web Framework. Node.js is an amazing tool for building networking services and applications. Express builds on top of its features to provide

Thisobjectcanbeusedtogetdataoutofthesession,andalsotosetdata:

req.session.name='Flavio'

console.log(req.session.name)//'Flavio'

ThisdataisserializedasJSONwhenstored,soyouaresafetousenestedobjects.

Youcanusesessionstocommunicatedatatomiddlewarethat'sexecutedlater,ortoretrieveitlaterononsubsequentrequests.

Whereisthesessiondatastored?itdependsonhowyousetupthe express-sessionmodule.

Itcanstoresessiondatain

memory,notmeantforproductionadatabaselikeMySQLorMongoamemorycachelikeRedisorMemcached

Thereisabiglistof3rdpackagesthatimplementawidevarietyofdifferentcompatiblecachingstoresinhttps://github.com/expressjs/session

Allsolutionsstorethesessionidinacookie,andkeepthedataserver-side.Theclientwillreceivethesessionidinacookie,andwillsenditalongwitheveryHTTPrequest.

We'llreferencethatserver-sidetoassociatethesessionidwiththedatastoredlocally.

Memoryisthedefault,itrequiresnospecialsetuponyourpart,it'sthesimplestthingbutit'smeantonlyfordevelopmentpurposes.

ThebestchoiceisamemorycachelikeRedis,forwhichyouneedtosetupitsowninfrastructure.

AnotherpopularpackagetomanagesessionsinExpressis cookie-session,whichhasabigdifference:itstoresdataclient-sideinthecookie.Idonotrecommenddoingthatbecausestoringdataincookiesmeansthatit'sstoredclient-side,andsentbackandforthineverysinglerequestmadebytheuser.It'salsolimitedinsize,asitcanonlystore4kilobytesofdata.Cookiesalsoneedtobesecured,butbydefaulttheyarenot,sincesecureCookiesarepossibleonHTTPSsitesandyouneedtoconfigurethemifyouhaveproxies.

Sessions

40

Page 41: Table of Contents · Express is a Node.js Web Framework. Node.js is an amazing tool for building networking services and applications. Express builds on top of its features to provide

ValidatinginputLearnhowtovalidateanydatacominginasinputinyourExpressendpoints

SayyouhaveaPOSTendpointthatacceptsthename,emailandageparameters:

constexpress=require('express')

constapp=express()

app.use(express.json())

app.post('/form',(req,res)=>{

constname=req.body.name

constemail=req.body.email

constage=req.body.age

})

Howdoyouserver-sidevalidatethoseresultstomakesure

nameisastringofatleast3characters?emailisarealemail?ageisanumber,between0and110?

ThebestwaytohandlevalidatinganykindofinputcomingfromoutsideinExpressisbyusingthe express-validatorpackage:

npminstallexpress-validator

Yourequirethe checkobjectfromthepackage:

const{check}=require('express-validator/check')

Wepassanarrayof check()callsasthesecondargumentofthe post()call.Everycheck()callacceptstheparameternameasargument:

app.post('/form',[

check('name').isLength({min:3}),

check('email').isEmail(),

check('age').isNumeric()

],(req,res)=>{

constname=req.body.name

constemail=req.body.email

constage=req.body.age

})

Validatinginput

41

Page 42: Table of Contents · Express is a Node.js Web Framework. Node.js is an amazing tool for building networking services and applications. Express builds on top of its features to provide

NoticeIused

isLength()

isEmail()

isNumeric()

Therearemanymoreofthesemethods,allcomingfromvalidator.js,including:

contains(),checkifvaluecontainsthespecifiedvalueequals(),checkifvalueequalsthespecifiedvalueisAlpha()

isAlphanumeric()

isAscii()

isBase64()

isBoolean()

isCurrency()

isDecimal()

isEmpty()

isFQDN(),isafullyqualifieddomainname?isFloat()

isHash()

isHexColor()

isIP()

isIn(),checkifthevalueisinanarrayofallowedvaluesisInt()

isJSON()

isLatLong()

isLength()

isLowercase()

isMobilePhone()

isNumeric()

isPostalCode()

isURL()

isUppercase()

isWhitelisted(),checkstheinputagainstawhitelistofallowedcharacters

Youcanvalidatetheinputagainstaregularexpressionusing matches().

Datescanbecheckedusing

isAfter(),checkiftheentereddateisaftertheoneyoupassisBefore(),checkiftheentereddateisbeforetheoneyoupassisISO8601()

Validatinginput

42

Page 43: Table of Contents · Express is a Node.js Web Framework. Node.js is an amazing tool for building networking services and applications. Express builds on top of its features to provide

isRFC3339()

Forexactdetailsonhowtousethosevalidators,refertohttps://github.com/chriso/validator.js#validators.

Allthosecheckscanbecombinedbypipingthem:

check('name')

.isAlpha()

.isLength({min:10})

Ifthereisanyerror,theserverautomaticallysendsaresponsetocommunicatetheerror.Forexampleiftheemailisnotvalid,thisiswhatwillbereturned:

{

"errors":[{

"location":"body",

"msg":"Invalidvalue",

"param":"email"

}]

}

Thisdefaulterrorcanbeoverriddenforeachcheckyouperform,using withMessage():

check('name')

.isAlpha()

.withMessage('Mustbeonlyalphabeticalchars')

.isLength({min:10})

.withMessage('Mustbeatleast10charslong')

Whatifyouwanttowriteyourownspecial,customvalidator?Youcanusethe customvalidator.

Inthecallbackfunctionyoucanrejectthevalidationeitherbythrowinganexception,orbyreturningarejectedpromise:

app.post('/form',[

check('name').isLength({min:3}),

check('email').custom(email=>{

if(alreadyHaveEmail(email)){

thrownewError('Emailalreadyregistered')

}

}),

check('age').isNumeric()

],(req,res)=>{

constname=req.body.name

constemail=req.body.email

constage=req.body.age

})

Validatinginput

43

Page 44: Table of Contents · Express is a Node.js Web Framework. Node.js is an amazing tool for building networking services and applications. Express builds on top of its features to provide

Thecustomvalidator:

check('email').custom(email=>{

if(alreadyHaveEmail(email)){

thrownewError('Emailalreadyregistered')

}

})

canberewrittenas

check('email').custom(email=>{

if(alreadyHaveEmail(email)){

returnPromise.reject('Emailalreadyregistered')

}

})

Validatinginput

44

Page 45: Table of Contents · Express is a Node.js Web Framework. Node.js is an amazing tool for building networking services and applications. Express builds on top of its features to provide

SanitizinginputYou'veseenhowtovalidateinputthatcomesfromtheoutsideworldtoyourExpressapp.

There'sonethingyouquicklylearnwhenyourunapublic-facingserver:nevertrusttheinput.

Evenifyousanitizeandmakesurethatpeoplecan'tenterweirdthingsusingclient-sidecode,you'llstillbesubjecttopeopleusingtools(evenjustthebrowserdevtools)toPOSTdirectlytoyourendpoints.

Orbotstryingeverypossiblecombinationofexploitknowntohumans.

Whatyouneedtodoissanitizingyourinput.

The express-validatorpackageyoualreadyusetovalidateinputcanalsoconvenientlyusedtoperformsanitization.

SayyouhaveaPOSTendpointthatacceptsthename,emailandageparameters:

constexpress=require('express')

constapp=express()

app.use(express.json())

app.post('/form',(req,res)=>{

constname=req.body.name

constemail=req.body.email

constage=req.body.age

})

Youmightvalidateitusing:

constexpress=require('express')

constapp=express()

app.use(express.json())

app.post('/form',[

check('name').isLength({min:3}),

check('email').isEmail(),

check('age').isNumeric()

],(req,res)=>{

constname=req.body.name

constemail=req.body.email

constage=req.body.age

})

Youcanaddsanitizationbypipingthesanitizationmethodsafterthevalidationones:

Sanitizinginput

45

Page 46: Table of Contents · Express is a Node.js Web Framework. Node.js is an amazing tool for building networking services and applications. Express builds on top of its features to provide

app.post('/form',[

check('name').isLength({min:3}).trim().escape(),

check('email').isEmail().normalizeEmail(),

check('age').isNumeric().trim().escape()

],(req,res)=>{

//...

})

HereIusedthemethods:

trim()trimscharacters(whitespacebydefault)atthebeginningandattheendofastringescape()replaces <, >, &, ', "and /withtheircorrespondingHTMLentitiesnormalizeEmail()canonicalizesanemailaddress.Acceptsseveraloptionstolowercaseemailaddressesorsubaddresses(e.g. [email protected])

Othersanitizationmethods:

blacklist()removecharactersthatappearintheblacklistwhitelist()removecharactersthatdonotappearinthewhitelistunescape()replacesHTMLencodedentitieswith <, >, &, ', "and /ltrim()liketrim(),butonlytrimscharactersatthestartofthestringrtrim()liketrim(),butonlytrimscharactersattheendofthestringstripLow()removeASCIIcontrolcharacters,whicharenormallyinvisible

Forceconversiontoaformat:

toBoolean()converttheinputstringtoaboolean.Everythingexceptfor'0','false'and''returnstrue.Instrictmodeonly'1'and'true'returntruetoDate()converttheinputstringtoadate,ornulliftheinputisnotadatetoFloat()converttheinputstringtoafloat,orNaNiftheinputisnotafloattoInt()converttheinputstringtoaninteger,orNaNiftheinputisnotaninteger

Likewithcustomvalidators,youcancreateacustomsanitizer.

Inthecallbackfunctionyoujustreturnthesanitizedvalue:

constsanitizeValue=value=>{

//sanitize...

}

app.post('/form',[

check('value').customSanitizer(value=>{

returnsanitizeValue(value)

}),

],(req,res)=>{

constvalue=req.body.value

})

Sanitizinginput

46

Page 47: Table of Contents · Express is a Node.js Web Framework. Node.js is an amazing tool for building networking services and applications. Express builds on top of its features to provide

Sanitizinginput

47

Page 48: Table of Contents · Express is a Node.js Web Framework. Node.js is an amazing tool for building networking services and applications. Express builds on top of its features to provide

HandlingformsHowtoprocessformsusingExpress

ThisisanexampleofanHTMLform:

<formmethod="POST"action="/submit-form">

<inputtype="text"name="username"/>

<inputtype="submit"/>

</form>

Whentheuserpressthesubmitbutton,thebrowserwillautomaticallymakea POSTrequesttothe /submit-formURLonthesameoriginofthepage,sendingthedataitcontains,encodedas application/x-www-form-urlencoded.Inthiscase,theformdatacontainstheusernameinputfieldvalue.

Formscanalsosenddatausingthe GETmethod,butthevastmajorityoftheformsyou'llbuildwilluse POST.

TheformdatawillbesentinthePOSTrequestbody.

Toextractit,youwillusethe express.urlencoded()middleware,providedbyExpress:

constexpress=require('express')

constapp=express()

app.use(express.urlencoded())

Nowyouneedtocreatea POSTendpointonthe /submit-formroute,andanydatawillbeavailableon Request.body:

app.post('/submit-form',(req,res)=>{

constusername=req.body.username

//...

res.end()

})

Don'tforgettovalidatethedatabeforeusingit,using express-validator.

Handlingforms

48

Page 49: Table of Contents · Express is a Node.js Web Framework. Node.js is an amazing tool for building networking services and applications. Express builds on top of its features to provide

FileuploadsinformsHowtomanagestoringandhandlingfilesuploadedviaforms,inExpress

ThisisanexampleofanHTMLformthatallowsausertouploadafile:

<formmethod="POST"action="/submit-form">

<inputtype="file"name="document"/>

<inputtype="submit"/>

</form>

Whentheuserpressthesubmitbutton,thebrowserwillautomaticallymakea POSTrequesttothe /submit-formURLonthesameoriginofthepage,sendingthedataitcontains,notencodedas application/x-www-form-urlencodedasanormalform,butas multipart/form-data.

Server-side,handlingmultipartdatacanbetrickyanderrorprone,sowearegoingtouseautilitylibrarycalledformidable.Here'stheGitHubrepo,ithasover4000starsandwellmaintained.

Youcaninstallitusing:

npminstallformidable

TheninyourNode.jsfile,includeit:

constexpress=require('express')

constapp=express()

constformidable=require('formidable')

Nowinthe POSTendpointonthe /submit-formroute,weinstantiateanewFormidableformusing formidable.IncomingFrom():

app.post('/submit-form',(req,res)=>{

newformidable.IncomingFrom()

})

Afterdoingso,weneedtoparsetheform.Wecandososynchronouslybyprovidingacallback,whichmeansallfilesareprocessed,andonceformidableisdone,itmakesthemavailable:

app.post('/submit-form',(req,res)=>{

newformidable.IncomingFrom().parse(req,(err,fields,files)=>{

if(err){

Fileuploadsinforms

49

Page 50: Table of Contents · Express is a Node.js Web Framework. Node.js is an amazing tool for building networking services and applications. Express builds on top of its features to provide

console.error('Error',err)

throwerr

}

console.log('Fields',fields)

console.log('Files',files)

files.map(file=>{

console.log(file)

})

})

})

Oryoucanuseeventsinsteadofacallback,tobenotifiedwheneachfileisparsed,andotherevents,likeendingprocessing,receivinganon-filefield,oranerroroccurred:

app.post('/submit-form',(req,res)=>{

newformidable.IncomingFrom().parse(req)

.on('field',(name,field)=>{

console.log('Field',name,field)

})

.on('file',(name,file)=>{

console.log('Uploadedfile',name,file)

})

.on('aborted',()=>{

console.error('Requestabortedbytheuser')

})

.on('error',(err)=>{

console.error('Error',err)

throwerr

})

.on('end',()=>{

res.end()

})

})

Whateverwayyouchoose,you'llgetoneormoreFormidable.Fileobjects,whichgiveyouinformationaboutthefileuploaded.Thesearesomeofthemethodsyoucancall:

file.size,thefilesizeinbytesfile.path,thepaththisfileiswrittentofile.name,thenameofthefilefile.type,theMIMEtypeofthefile

Thepathdefaultstothetemporaryfolderandcanbemodifiedifyoulistentothe fileBeginevent:

app.post('/submit-form',(req,res)=>{

newformidable.IncomingFrom().parse(req)

.on('fileBegin',(name,file)=>{

form.on('fileBegin',(name,file)=>{

file.path=__dirname+'/uploads/'+file.name

})

Fileuploadsinforms

50

Page 51: Table of Contents · Express is a Node.js Web Framework. Node.js is an amazing tool for building networking services and applications. Express builds on top of its features to provide

})

.on('file',(name,file)=>{

console.log('Uploadedfile',name,file)

})

//...

})

Fileuploadsinforms

51

Page 52: Table of Contents · Express is a Node.js Web Framework. Node.js is an amazing tool for building networking services and applications. Express builds on top of its features to provide

AnExpressHTTPSserverwithaself-signedcertificateHowtocreateaself-signedHTTPScertificateforNode.jstotestappslocally

TobeabletoserveasiteonHTTPSfromlocalhostyouneedtocreateaself-signedcertificate.

Aself-signedcertificatewillbeenoughtoestablishasecureHTTPSconnection,althoughbrowserswillcomplainthatthecertificateisself-signedandassuchit'snottrusted.It'sgreatfordevelopmentpurposes.

TocreatethecertificateyoumusthaveOpenSSLinstalledonyoursystem.

Youmighthaveitinstalledalready,justtestbytyping opensslinyourterminal.

Ifnot,onaMacyoucaninstallitusing brewinstallopensslifyouuseHomebrew.OtherwisesearchonGoogle"howtoinstallopensslon".

OnceOpenSSLisinstalled,runthiscommand:

opensslreq-nodes-new-x509-keyoutserver.key-outserver.cert

Itwillasyouafewquestions.Thefirstisthecountryname:

Generatinga1024bitRSAprivatekey

...........++++++

.........++++++

writingnewprivatekeyto'server.key'

-----

Youareabouttobeaskedtoenterinformationthatwillbeincorporatedintoyourcertifi

caterequest.

WhatyouareabouttoenteriswhatiscalledaDistinguishedNameoraDN.

Therearequiteafewfieldsbutyoucanleavesomeblank

Forsomefieldstherewillbeadefaultvalue,

Ifyouenter'.',thefieldwillbeleftblank.

-----

CountryName(2lettercode)[AU]:

Thenyourstateorprovince:

StateorProvinceName(fullname)[Some-State]:

yourcity:

AnExpressHTTPSserverwithaself-signedcertificate

52

Page 53: Table of Contents · Express is a Node.js Web Framework. Node.js is an amazing tool for building networking services and applications. Express builds on top of its features to provide

LocalityName(eg,city)[]:

andyourorganizationname:

OrganizationName(eg,company)[InternetWidgitsPtyLtd]:

OrganizationalUnitName(eg,section)[]:

Youcanleavealloftheseempty.

Justremembertosetthisto localhost:

CommonName(e.g.serverFQDNorYOURname)[]:localhost

andtoaddyouremailaddress:

EmailAddress[]:

That'sit!Nowyouhave2filesinthefolderwhereyouranthiscommand:

server.certistheself-signedcertificatefileserver.keyistheprivatekeyofthecertificate

BothfileswillbeneededtoestablishtheHTTPSconnection,anddependingonhowyouaregoingtosetupyourserver,theprocesstousethemwillbedifferent.

Thosefilesneedtobeputinaplacereachablebytheapplication,thenyouneedtoconfiguretheservertousethem.

Thisisanexampleusingthe httpscoremoduleandExpress:

consthttps=require('https')

constapp=express()

app.get('/',(req,res)=>{

res.send('HelloHTTPS!')

})

https.createServer({},app).listen(3000,()=>{

console.log('Listening...')

})

withoutaddingthecertificate,ifIconnectto https://localhost:3000thisiswhatthebrowserwillshow:

AnExpressHTTPSserverwithaself-signedcertificate

53

Page 54: Table of Contents · Express is a Node.js Web Framework. Node.js is an amazing tool for building networking services and applications. Express builds on top of its features to provide

Withthecertificateinplace:

constfs=require('fs')

//...

https.createServer({

key:fs.readFileSync('server.key'),

cert:fs.readFileSync('server.cert')

},app).listen(3000,()=>{

console.log('Listening...')

})

Chromewilltellusthecertificateisinvalid,sinceit'sself-signed,andwillaskustoconfirmtocontinue,buttheHTTPSconnectionwillwork:

AnExpressHTTPSserverwithaself-signedcertificate

54

Page 55: Table of Contents · Express is a Node.js Web Framework. Node.js is an amazing tool for building networking services and applications. Express builds on top of its features to provide

AnExpressHTTPSserverwithaself-signedcertificate

55

Page 56: Table of Contents · Express is a Node.js Web Framework. Node.js is an amazing tool for building networking services and applications. Express builds on top of its features to provide

SetupLet'sEncryptforExpressHowtosetupHTTPSusingthepopularfreesolutionLet'sEncrypt

IfyourunaNode.jsapplicationonyourownVPS,youneedtomanagegettinganSSLcertificate.

TodaythestandardfordoingthisistouseLet'sEncryptandCertbot,atoolfromEFF,akaElectronicFrontierFoundation,theleadingnonprofitorganizationfocusedonprivacy,freespeech,andingeneralcivillibertiesinthedigitalworld.

Thesearethestepswe'llfollow:

InstallCertbotGeneratetheSSLcertificateusingCertbotAllowExpresstoservestaticfilesConfirmthedomainObtainthecertificateSetuptherenewal

InstallCertbotThoseinstructionsassumeyouareusingUbuntu,DebianoranyotherLinuxdistributionthatuses apt-get:

sudoadd-aptrepositoryppa:certbot/certbot

sudoapt-getupdate

sudoapt-getinstallcertbot

YoucanalsoinstallCertbotonaMactotest:

brewinstallcertbot

butyouwillneedtolinkthattoarealdomainname,inorderforittobeuseful.

GeneratetheSSLcertificateusingCertbotNowthatCertbotisinstalled,youcaninvokeittogeneratethecertificate.Youmustrunthisasroot:

SetupLet'sEncryptforExpress

56

Page 57: Table of Contents · Express is a Node.js Web Framework. Node.js is an amazing tool for building networking services and applications. Express builds on top of its features to provide

certbotcertonly--manual

orcallsudo

sudocertbotcertonly--manual

Theinstallerwillaskyouthedomainofyourwebsite.

Thisistheprocessindetail.

Itasksfortheemail

➜sudocertbotcertonly--manualPassword:XXXXXXXXXXXXXXXXXX

Savingdebuglogto/var/log/letsencrypt/letsencrypt.log

Pluginsselected:Authenticatormanual,InstallerNone

Enteremailaddress(usedforurgentrenewalandsecuritynotices)(Enter'c'to

cancel):[email protected]

ItaskstoaccepttheToS:

PleasereadtheTermsofServiceat

https://letsencrypt.org/documents/LE-SA-v1.2-November-15-2017.pdf.Youmust

agreeinordertoregisterwiththeACMEserverat

https://acme-v02.api.letsencrypt.org/directory

(A)gree/(C)ancel:A

Itaskstosharetheemailaddress

WouldyoubewillingtoshareyouremailaddresswiththeElectronicFrontier

Foundation,afoundingpartneroftheLet'sEncryptprojectandthenon-profit

organizationthatdevelopsCertbot?We'dliketosendyouemailaboutourwork

encryptingtheweb,EFFnews,campaigns,andwaystosupportdigitalfreedom.

----------------------------------------

(Y)es/(N)o:Y

AndfinallywecanenterthedomainwherewewanttousetheSSLcertificate:

Pleaseenterinyourdomainname(s)(commaand/orspaceseparated)(Enter'c'

tocancel):copesflavio.com

Itasksifit'soktologyourIP:

Obtaininganewcertificate

Performingthefollowingchallenges:

SetupLet'sEncryptforExpress

57

Page 58: Table of Contents · Express is a Node.js Web Framework. Node.js is an amazing tool for building networking services and applications. Express builds on top of its features to provide

http-01challengeforcopesflavio.com

----------------------------------------

NOTE:TheIPofthismachinewillbepubliclyloggedashavingrequestedthis

certificate.Ifyou'rerunningcertbotinmanualmodeonamachinethatisnot

yourserver,pleaseensureyou'reokaywiththat.

AreyouOKwithyourIPbeinglogged?

----------------------------------------

(Y)es/(N)o:y

Andfinallywegettotheverificationphase!

----------------------------------------

Createafilecontainingjustthisdata:

TS_oZ2-ji23jrio3j2irj3iroj_U51u1o0x7rrDY2E.1DzOo_voCOsrpddP_2kpoek2opeko2pke-UAPb21sW1c

AndmakeitavailableonyourwebserveratthisURL:

http://copesflavio.com/.well-known/acme-challenge/TS_oZ2-ji23jrio3j2irj3iroj_U51u1o0x7rrDY

2E

Nowlet'sleaveCertbotaloneforacoupleminutes.

Weneedtoverifyweownthedomain,bycreatingafilenamed TS_oZ2-ji23jrio3j2irj3iroj_U51u1o0x7rrDY2Einthe .well-known/acme-challenge/folder.Payattention!TheweirdstringIjustpastedchangeeverysingletime.

You'llneedtocreatethefolderandthefile,sincetheydonotexistbydefault.

InthisfileyouneedtoputthecontentthatCertbotprinted:

TS_oZ2-ji23jrio3j2irj3iroj_U51u1o0x7rrDY2E.1DzOo_voCOsrpddP_2kpoek2opeko2pke-UAPb21sW1c

Asforthefilename,thisstringisuniqueeachtimeyourunCertbot.

AllowExpresstoservestaticfilesInordertoservethatfilefromExpress,youneedtoenableservingstaticfiles.Youcancreatea staticfolder,andaddtherethe .well-knownsubfolder,thenconfigureExpresslikethis:

constexpress=require('express')

constapp=express()

//...

SetupLet'sEncryptforExpress

58

Page 59: Table of Contents · Express is a Node.js Web Framework. Node.js is an amazing tool for building networking services and applications. Express builds on top of its features to provide

app.use(express.static(__dirname+'/static',{dotfiles:'allow'}))

//...

The dotfilesoptionismandatoryotherwise .well-known,whichisadotfileasitstartswithadot,won'tbemadevisible.Thisisasecuritymeasure,becausedotfilescancontainsensitiveinformationandtheyarebetteroffpreservedbydefault.

ConfirmthedomainNowruntheapplicationandmakesurethefileisreachablefromthepublicinternet,andgobacktoCertbot,whichisstillrunning,andpressENTERtogoonwiththescript.

ObtainthecertificateThat'sit!Ifallwentwell,Certbotcreatedthecertificate,andtheprivatekey,andmadethemavailableinafolderonyourcomputer(anditwilltellyouwhichfolder,ofcourse).

Nowcopy/pastethepathsintoyourapplication,tostartusingthemtoserveyourrequests:

constfs=require('fs')

consthttps=require('https')

constapp=express()

app.get('/',(req,res)=>{

res.send('HelloHTTPS!')

})

https.createServer({

key:fs.readFileSync('/etc/letsencrypt/path/to/key.pem'),

cert:fs.readFileSync('/etc/letsencrypt/path/to/cert.pem'),

ca:fs.readFileSync('/etc/letsencrypt/path/to/chain.pem')

},app).listen(443,()=>{

console.log('Listening...')

})

NotethatImadethisserverlistenonport443,soyouneedtorunitwithrootpermissions.

Also,theserverisexclusivelyrunninginHTTPS,becauseIused https.createServer().YoucanalsorunanHTTPserveralongsidethis,byrunning:

http.createServer(app).listen(80,()=>{

console.log('Listening...')

})

https.createServer({

SetupLet'sEncryptforExpress

59

Page 60: Table of Contents · Express is a Node.js Web Framework. Node.js is an amazing tool for building networking services and applications. Express builds on top of its features to provide

key:fs.readFileSync('/etc/letsencrypt/path/to/key.pem'),

cert:fs.readFileSync('/etc/letsencrypt/path/to/cert.pem'),

ca:fs.readFileSync('/etc/letsencrypt/path/to/chain.pem')

},app).listen(443,()=>{

console.log('Listening...')

})

SetuptherenewalTheSSLcertificateisnotgoingtobevalidfor90days.Youneedtosetupanautomatedsystemforrenewingit.

How?Usingacronjob.

Acronjobisawaytoruntaskseveryintervaloftime.Itcanbeeeryweek,everyminute,everymonth.

Inourcasewe'llruntherenewalscripttwiceperday,asrecommendedintheCertbotdocumentation.

Firstfindouttheabsolutepathof certbotonyousystem.Iuse typecertbotonmacOStogetit,andinmycaseit's /usr/local/bin/certbot.

Here'sthescriptweneedtorun:

certbotrenew

Thisisthecronjobentry:

0*/12***root/usr/local/bin/certbotrenew>/dev/null2>&1

Itmeansrunitevery12hours,everyday:at00:00andat12:00.

Tip:Igeneratedthislineusinghttps://crontab-generator.org/

Addthisscripttoyourcrontab,byusingthecommand:

envEDITOR=picocrontab-e

Thisopensthe picoeditor(youcanchoosetheoneyouprefer).Youentertheline,save,andthecronjobisinstalled.

Oncethisisdone,youcanseethelistofcronjobsactiveusing

crontab-l

SetupLet'sEncryptforExpress

60

Page 61: Table of Contents · Express is a Node.js Web Framework. Node.js is an amazing tool for building networking services and applications. Express builds on top of its features to provide

SetupLet'sEncryptforExpress

61