327

Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write

  • Upload
    others

  • View
    7

  • Download
    0

Embed Size (px)

Citation preview

Page 1: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write

11

12

121

122

123

124

125

13

131

132

133

134

135

136

137

138

14

141

142

143

144

145

15

151

152

153

154

155

156

16

161

162

163

164

165

166

167

17

171

TableofContentsIntroduction

GoEnvironmentConfiguration

Installation

$GOPATHandworkspace

Gocommands

Godevelopmenttools

Summary

Gobasicknowledge

HelloGo

Gofoundation

Controlstatementsandfunctions

struct

Object-oriented

interface

Concurrency

Summary

Webfoundation

Webworkingprinciples

Buildasimplewebserver

HowGoworkswithweb

Getintohttppackage

Summary

HTTPForm

Processforminputs

Validationofinputs

Crosssitescripting

Duplicatesubmissions

Fileupload

Summary

Database

databasesqlinterface

HowtouseMySQL

HowtouseSQLite

HowtousePostgreSQL

HowtousebeedbORM

NOSQL

Summary

Datastorageandsession

Sessionandcookies

2

172

173

174

175

18

181

182

183

184

185

186

187

19

191

192

193

194

195

110

1101

1102

1103

1104

1105

1106

1107

111

1111

1112

1113

1114

112

1121

1122

1123

1124

113

1131

1132

1133

1134

1135

HowtousesessioninGo

Sessionstorage

Preventhijackofsession

Summary

Textfiles

XML

JSON

Regexp

Templates

Files

Strings

Summary

Webservices

Sockets

WebSocket

REST

RPC

Summary

Securityandencryption

CSRFattacks

Filterinputs

XSSattacks

SQLinjection

Passwordstorage

Encryptanddecryptdata

Summary

Internationalizationandlocalization

Timezone

Localizedresources

Internationalsites

Summary

Errorhandlingdebuggingandtesting

Errorhandling

DebuggingbyusingGDB

Writetestcases

Summary

Deploymentandmaintenance

Logs

Errorsandcrashes

Deployment

Backupandrecovery

Summary

3

114

1141

1142

1143

1144

1145

1146

115

1151

1152

1153

1154

1155

1156

1157

116

117

Buildawebframework

Projectprogram

Customizedrouters

Designcontrollers

Logsandconfigurations

Adddeleteandupdateblogs

Summary

Developwebframework

Staticfiles

Session

Form

Uservalidation

Multi-languagesupport

pprof

Summary

References

preface

4

BuildWebApplicationwithGolangPurpose

BecauseIminterestedinwebapplicationdevelopmentIusedmyfreetimetowritethisbookasanopensourceversionItdoesntmeanthatIhaveaverygoodabilitytobuildwebapplicationsIwouldliketosharewhatIvedonewithGoinbuildingwebapplications

ForthoseofyouwhoareworkingwithPHPPythonRubyyouwilllearnhowtobuildawebapplicationwithGoForthoseofyouwhoareworkingwithCC++youwillknowhowthewebworks

IbelievethepurposeofstudyingissharingwithothersThehappiestthinginmylifeissharingeverythingIveknownwithmorepeople

Donate

AliPay

alipay

EnglishDonatedonate

CommunityQQ群386056972

BBShttpgocnio

Acknowledgments四月份平民AprilCitizen(reviewcode)洪瑞琦HongRuiqi(reviewcode)边疆BianJiang(writetheconfigurationsaboutVimandEmacsforGodevelopment)欧林猫OlingCat(reviewcode)吴文磊WenleiWu(providesomepictures)北极星Polaris(reviewwholebook)雨痕RainTrail(reviewchapter2and3)

LicenseThisbookislicensedundertheCCBY-SA30LicensethecodeislicensedunderaBSD3-ClauseLicenseunlessotherwisespecified

GetStarted

Index

Introduction

5

Introduction

6

1GoEnvironmentConfigurationWelcometotheworldofGoletsstartexploring

Goisafast-compiledgarbage-collectedconcurrentsystemsprogramminglanguageIthasthefollowingadvantages

CompilesalargeprojectwithinafewsecondsProvidesasoftwaredevelopmentmodelthatiseasytoreasonaboutavoidingmostoftheproblemsassociatedwithC-styleheaderfilesIsastaticlanguagethatdoesnothavelevelsinitstypesystemsousersdonotneedtospendmuchtimedealingwithrelationsbetweentypesItismorelikealightweightobject-orientedlanguagePerformsgarbagecollectionItprovidesbasicsupportforconcurrencyandcommunicationDesignedformulti-corecomputers

GoisacompiledlanguageItcombinesthedevelopmentefficiencyofinterpretedordynamiclanguageswiththesecurityofstaticlanguagesItisgoingtobethelanguageofchoiceformodernmulti-corecomputerswithnetworkingForthesepurposestherearesomeproblemsthatneedtoinherentlyberesolvedatthelevelofthelanguageofchoicesuchasarichlyexpressivelightweighttypesystemanativeconcurrencymodelandstrictlyregulatedgarbagecollectionForquitesometimenopackagesortoolshaveemergedthathaveaimedtosolvealloftheseproblemsinapragmaticfashionthuswasbornthemotivationfortheGolanguage

InthischapterIwillshowyouhowtoinstallandconfigureyourownGodevelopmentenvironment

LinksDirectoryNextsectionInstallation

GoEnvironmentConfiguration

7

11Installation

ThreewaystoinstallGoTherearemanywaystoconfiguretheGodevelopmentenvironmentonyourcomputerandyoucanchoosewhicheveroneyoulikeThethreemostcommonwaysareasfollows

OfficialinstallationpackagesTheGoteamprovidesconvenientinstallationpackagesinWindowsLinuxMacandotheroperatingsystemsThisisprobablytheeasiestwaytogetstartedYoucangettheinstallersfromtheGolangDownloadPage

InstallityourselffromsourcecodePopularwithdeveloperswhoarefamiliarwithUnix-likesystems

Usingthird-partytoolsTherearemanythird-partytoolsandpackagemanagersforinstallingGolikeapt-getinUbuntuandhomebrewforMac

IncaseyouwanttoinstallmorethanoneversionofGoonacomputeryoushouldtakealookatatoolcalledGVMItisthebesttoolIveseensofarforaccomplishingthistaskotherwiseyoudhavetodealwithityourself

InstallfromsourcecodeTocompileGo15andupwardsyouonlyneedthepreviousversionofGoasGohasachievedbootstrappingYouonlyneedGotocompileGo

TocompileGo14downwardsyouwillneedaCcompilerassomepartsofGoarestillwritteninPlan9CandATampTassembler

OnaMacifyouhaveinstalledXcodeyoualreadyhavethecompiler

OnUnix-likesystemsyouneedtoinstallgccorasimilarcompilerForexampleusingthepackagemanagerapt-get(includedwithUbuntu)onecaninstalltherequiredcompilersasfollows

sudoapt-getinstallgcclibc6-dev

OnWindowsyouneedtoinstallMinGWinordertoinstallgccDontforgettoconfigureyourenvironmentvariablesaftertheinstallationhascompleted(EverythingthatlookslikethismeansitscommentedbyatranslatorIfyouareusing64-bitWindowsyoushouldinstallthe64-bitversionofMinGW)

AtthispointexecutethefollowingcommandstoclonetheGosourcecodeandcompileit(ItwillclonethesourcecodetoyourcurrentdirectorySwitchyourworkpathbeforeyoucontinueThismaytakesometime)

gitclonehttpsgogooglesourcecomgo

cdgosrc

allbash

AsuccessfulinstallationwillendwiththemessageALLTESTSPASSED

OnWindowsyoucanachievethesamebyrunningallbat

IfyouareusingWindowstheinstallationpackagewillsetyourenvironmentvariablesautomaticallyInUnix-likesystemsyouneedtosetthesevariablesmanuallyasfollows(IfyourGoversionisgreaterthan10youdonthavetoset$GOBINanditwillautomaticallyberelatedtoyour$GOROOTbinwhichwewilltalkaboutinthenextsection)

Installation

8

exportGOROOT=$HOMEgo

exportGOBIN=$GOROOTbin

exportPATH=$PATH$GOROOTbin

Ifyouseethefollowinginformationonyourscreenyoureallset

Figure11Informationafterinstallingfromsourcecode

OnceyouseetheusageinformationofGoitmeansyouhavesuccessfullyinstalledGoonyourcomputerIfitsaysnosuchcommandcheckthatyour$PATHenvironmentvariablecontainstheinstallationpathofGo

UsingthestandardinstallationpackagesGohasone-clickinstallationpackagesforeverysupportedoperatingsystemThesepackageswillinstallGoinusrlocalgo(cGoinWindows)bydefaultOfcoursethiscanbemodifiedbutyoualsoneedtochangealltheenvironmentvariablesmanuallyasIveshownabove

Howtocheckifyouroperatingsystemis32-bitor64-bit

Ournextstepdependsonyouroperatingsystemtypesowehavetocheckitbeforewedownloadthestandardinstallationpackages

IfyouareusingWindowspressWin+RandthenrunthecommandtoolTypethesysteminfocommandanditwillshowyousomeusefulsysteminformationFindthelinethatsayssystemtype-ifyouseex64-basedPCthatmeansyouroperatingsystemis64-bit32-bitotherwise

Istronglyrecommenddownloadingthe64-bitpackageifyouareaMacuserasGonolongersupportspure32-bitprocessorsonMacOSX

Linuxuserscantypeuname-aintheterminaltoseesysteminformationA64-bitoperatingsystemwillshowthefollowing

ltsomedescriptiongtx86_64x86_64x86_64GNULinux

somemachinessuchasUbuntu1004willshowasfollowing

x86_64GNULinux

32-bitoperatingsystemsinsteadshow

ltsomedescriptiongti686i686i386GNULinux

Mac

Gotothedownloadpagechoosego142darwin-386pkg(Thelaterversionhasno32-bitdownload)for32-bitsystemsandgo183darwin-amd64pkgfor64-bitsystemsGoingallthewaytotheendbyclickingnext~gobinwillbeaddedtoyoursystems$PATHafteryoufinishtheinstallationNowopentheterminalandtypegoYoushouldseethesameoutputshowninfigure11

Linux

Gotothedownloadpagechoosego183linux-386targzfor32-bitsystemsandgo183linux-amd64targzfor64-bitsystemsSupposeyouwanttoinstallGointhe$GO_INSTALL_DIRpathUncompressthetargztoyourchosenpathusingthecommandtarzxvfgo183linux-amd64targz-C$GO_INSTALL_DIRThensetyour$PATHwiththefollowingexportPATH=$PATH$GO_INSTALL_DIRgobinNowjustopentheterminalandtypegoYoushouldnowseethesameoutputdisplayedinfigure11

Installation

9

Windows

Gotothedownloadpagechoosego183windows-386msifor32-bitsystemsandgo183windows-amd64msifor64-bitsystemsGoingallthewaytotheendbyclickingnextcgobinwillbeaddedtopathNowjustopenacommandlinewindowandtypegoYoushouldnowseethesameoutputdisplayedinfigure11

Usethird-partytools

GVM

GVMisaGomulti-versioncontroltooldevelopedbyathird-partylikervmforrubyItsquiteeasytouseInstallgvmbytypingthefollowingcommandsinyourterminal

bashltlt(curl-s-S-Lhttpsrawgithubcommoovwebgvmmasterbinscriptsgvm-installer)

ThenweinstallGousingthefollowingcommands

gvminstallgo183

gvmusego183

Aftertheprocesshasfinishedyoureallset

apt-get

UbuntuisthemostpopulardesktopreleaseversionofLinuxItusesapt-gettomanagepackagesWecaninstallGousingthefollowingcommands

sudoadd-apt-repositoryppagophersgo

sudoapt-getupdate

sudoapt-getinstallgolang-go

wget

wgethttpsstoragegoogleapiscomgolanggo183linux-amd64targz

sudotar-xzfgo183linux-amd64targz-Cusrlocal

Goenvironment

exportGOROOT=usrlocalgo

exportGOBIN=$GOROOTbin

exportPATH=$PATH$GOBIN

exportGOPATH=$HOMEgopath

Startingfromgo18TheGOPATHenvironmentvariablenowhasadefaultvalueifitisunsetItdefaultsto$HOMEgoonUnixandUSERPROFILEgoonWindows

HomebrewHomebrewisasoftwaremanagementtoolcommonlyusedinMactomanagepackagesJusttypethefollowingcommandstoinstallGo

1 InstallHomebrew

usrbinruby-e$(curl-fsSLhttpsrawgithubusercontentcomHomebrewinstallmasterinstall)

Installation

10

1 InstallGo

brewupdateampampbrewupgrade

brewinstallgo

LinksDirectoryPrevioussectionGoenvironmentconfigurationNextsection$GOPATHandworkspace

Installation

11

12$GOPATHandworkspace

$GOPATHGotakesauniqueapproachtomanagethecodefileswiththeintroductionofa$GOPATHdirectorywhichcontainsallthegocodeinthemachineNotethatthisisdifferentfromthe$GOROOTenvironmentvariablewhichstateswheregoisinstalledonthemachineWehavetodefinethe$GOPATHvariablebeforeusingthelanguageinnixsystemsthereisafilecalledprofileweneedtoappendthebelowexportstatementtothefileTheconceptbehindgopathisanovelonewherewecanlinktoanygocodeatanyinstantoftimewithoutambiguity

Startingfromgo18theGOPATHenvironmentvariablenowhasadefaultvalueifitisunsetItdefaultsto$HOMEgoonUnixandUSERPROFILEgoonWindows

InUnix-likesystemsthevariableshouldbeusedlikethis

exportGOPATH=$HOMEmygo

InWindowsyouneedtocreateanewenvironmentvariablecalledGOPATHthensetitsvaluetocmygo(Thisvaluedependsonwhereyourworkspaceislocated)

ItsOKtohavemorethanonepath(workspace)in$GOPATHbutrememberthatyouhavetouse(inWindows)tobreakthemupAtthispointgogetwillsavethecontenttoyourfirstpathin$GOPATHItishighlyrecommendedtonothavemultiplesversionstheworstcaseistocreateafolderbythenameofyourprojectrightinside$GOPATHitbreakseverythingthatthecreatorswerewishingtochangeinprogrammingwiththecreationofgolanguagebecausewhenyoucreateafolderinside$GOPATHyouwillreferenceyourpackagesasdirectlyasandthisbreaksalltheapplicationswhichwillimportyourpackagebecausethegogetwontfindyourpackagePleasefollowconventionsthereisareasonconventionsarecreated

In$GOPATHyoumusthavethreefoldersasfollows

srcforsourcefileswhosesuffixisgocgspkgforcompiledfileswhosesuffixisabinforexecutablefiles

InthisbookIusemygoasmyonlypathin$GOPATH

PackagedirectoryCreatepackagesourcefilesandfolderslike$GOPATHsrcmymathsqrtgo(mymathisthepackagename)(Authorusesmymathashispackagenameandthesamenameforthefolderthatcontainsthepackagesourcefiles)

EverytimeyoucreateapackageyoushouldcreateanewfolderinthesrcdirectorywiththenotableexceptionofmainforwhichmainfoldercreationisoptionalFoldernamesareusuallythesameasthepackagethatyouaregoingtouseYoucanhavemulti-leveldirectoriesifyouwanttoForexampleifyoucreatethedirectory$GOPATHsrcgithubcomastaxiebeedbthenthepackagepathwouldbegithubcomastaxiebeedbThepackagenamewillbethelastdirectoryinyourpathwhichisbeedbinthiscase

Executefollowingcommands(Nowauthorgoesbacktotalkexamples)

cd$GOPATHsrc

mkdirmymath

Createanewfilecalledsqrtgotypethefollowingcontenttoyourfile

$GOPATHandworkspace

12

Sourcecodeof$GOPATHsrcmymathsqrtgo

packagemymath

funcSqrt(xfloat64)float64

z=00

fori=0ilt1000i++

z-=(zz-x)(2x)

returnz

NowmypackagedirectoryhasbeencreatedanditscodehasbeenwrittenIrecommendthatyouusethesamenameforyourpackagesastheircorrespondingdirectoriesandthatthedirectoriescontainallofthepackagesourcefiles

CompilepackagesWevealreadycreatedourpackageabovebuthowdowecompileitforpracticalpurposesTherearetwowaystodothis

1 Switchyourworkpathtothedirectoryofyourpackagethenexecutethegoinstallcommand2 Executetheabovecommandexceptwithafilenamelikegoinstallmymath

Aftercompilingwecanopenthefollowingfolder

cd$GOPATHpkg$GOOS_$GOARCH

youcanseethefilewasgenerated

mymatha

ThefilewhosesuffixisaisthebinaryfileofourpackageHowdoweuseit

Obviouslyweneedtocreateanewapplicationtouseit

Createanewapplicationpackagecalledmathapp

cd$GOPATHsrc

mkdirmathapp

cdmathapp

vimmaingo

Writethefollowingcontenttomaingo

$GOPATHsrcmathappmaingosourcecode

packagemain

import(

mymath

fmt

)

funcmain()

fmtPrintf(HelloworldSqrt(2)=vnmymathSqrt(2))

Tocompilethisapplicationyouneedtoswitchtotheapplicationdirectorywhichinthiscaseis$GOPATHsrcmathappthenexecutethegoinstallcommandNowyoushouldseeanexecutablefilecalledmathappwasgeneratedinthedirectory$GOPATHbinTorunthisprogramusethemathappcommandYoushouldseethefollowingcontentinyourterminal

HelloworldSqrt(2)=1414213562373095

$GOPATHandworkspace

13

InstallremotepackagesGohasatoolforinstallingremotepackageswhichisacommandcalledgogetItsupportsmostopensourcecommunitiesincludingGithubGoogleCodeBitBucketandLaunchpad

gogetgithubcomastaxiebeedb

Youcanusegoget-uhelliptoupdateyourremotepackagesanditwillautomaticallyinstallallthedependentpackagesaswell

ThistoolwillusedifferentversioncontroltoolsfordifferentopensourceplatformsForexamplegitforGithubandhgforGoogleCodeThereforeyouhavetoinstalltheseversioncontroltoolsbeforeyouusegoget

Afterexecutingtheabovecommandsthedirectorystructureshouldlooklikefollowing

$GOPATH

src

|-githubcom

|-astaxie

|-beedb

pkg

|--$GOOS_$GOARCH

|-githubcom

|-astaxie

|-beedba

Actuallygogetclonessourcecodetothe$GOPATHsrcofthelocalfilesystemthenexecutesgoinstall

Youcanuseremotepackagesinthesamewaythatweuselocalpackages

importgithubcomastaxiebeedb

DirectorycompletestructureIfyouvefollowedalloftheabovestepsyourdirectorystructureshouldnowlooklikethefollowing

bin

mathapp

pkg

$GOOS_$GOARCHsuchasdarwin_amd64linux_amd64

mymatha

githubcom

astaxie

beedba

src

mathapp

maingo

mymath

sqrtgo

githubcom

astaxie

beedb

beedbgo

utilgo

Nowyouareabletoseethedirectorystructureclearlybincontainsexecutablefilespkgcontainscompiledfilesandsrccontainspackagesourcefiles

(TheformatofenvironmentvariablesinWindowsisGOPATHhoweverthisbookmainlyfollowstheUnix-stylesoWindowsusersneedtoreplacetheseyourself)

$GOPATHandworkspace

14

LinksDirectoryPrevioussectionInstallationNextsectionGocommands

$GOPATHandworkspace

15

13Gocommands

GocommandsTheGolanguagecomeswithacompletesetofcommandoperationtoolsYoucanexecutethegocommandontheterminaltoseethem

Figure13Gocommanddisplaysdetailedinformation

TheseareallusefulforusLetsseehowtousesomeofthem

gobuildThiscommandisforcompilingtestsItwillcompilepackagesanddependenciesifitsnecessary

Ifthepackageisnotthemainpackagesuchasmymathinsection12nothingwillbegeneratedafteryouexecutegobuildIfyouneedthepackagefileain$GOPATHpkgusegoinstallinsteadIfthepackageisthemainpackageitwillgenerateanexecutablefileinthesamefolderIfyouwantthefiletobegeneratedin$GOPATHbinusegoinstallorgobuild-o$PATH_HEREaexeIftherearemanyfilesinthefolderbutyoujustwanttocompileoneofthemyoushouldappendthefilenameaftergobuildForexamplegobuildagogobuildwillcompileallthefilesinthefolderYoucanalsoassignthenameofthefilethatwillbegeneratedForinstanceinthemathappproject(insection12)usinggobuild-oastaxieexewillgenerateastaxieexeinsteadofmathappexeThedefaultnameisyourfoldername(non-mainpackage)orthefirstsourcefilename(mainpackage)

(AccordingtoTheGoProgrammingLanguageSpecificationpackagenamesshouldbethenameafterthewordpackageinthefirstlineofyoursourcefilesItdoesnthavetobethesameasthefoldernameandtheexecutablefilenamewillbeyourfoldernamebydefault)

gobuildignoresfileswhosenamesstartwith_orIfyouwanttohavedifferentsourcefilesforeveryoperatingsystemyoucannamefileswiththesystemnameasasuffixSupposetherearesomesourcefilesforloadingarraysTheycouldbenamedasfollows

array_linuxgo|array_darwingo|array_windowsgo|array_freebsdgo

gobuildchoosestheonethatsassociatedwithyouroperatingsystemForexampleitonlycompilesarray_linuxgoinLinuxsystemsandignoresalltheothers

gocleanThiscommandisforcleaningfilesthataregeneratedbycompilersincludingthefollowingfiles

_objolddirectoryofobjectleftbyMakefiles

_testolddirectoryoftestleftbyMakefiles

_testmaingoolddirectoryofgotestleftbyMakefiles

testoutolddirectoryoftestleftbyMakefiles

buildoutolddirectoryoftestleftbyMakefiles

[568ao]objectfilesleftbyMakefiles

DIR(exe)generatedbygobuild

DIRtest(exe)generatedbygotest-c

MAINFILE(exe)generatedbygobuildMAINFILEgo

Gocommands

16

IusuallyusethiscommandtocleanupmyfilesbeforeIuploadmyprojecttoGithubTheseareusefulforlocaltestsbutuselessforversioncontrol

gofmtandgofmtThepeoplewhoareworkingwithCC++shouldknowthatpeoplearealwaysarguingaboutwhichcodestyleisbetterKampR-styleorANSI-styleHoweverinGothereisonlyonecodestylewhichisenforcedForexampleleftbracesmustonlybeinsertedattheendoflinesandtheycannotbeontheirownlinesotherwiseyouwillgetcompileerrorsFortunatelyyoudonthavetoremembertheserulesgofmtdoesthisjobforyouJustexecutethecommandgofmtltFilenamegtgointerminalIdontusethiscommandverymuchbecauseIDEsusuallyexecutethiscommandautomaticallywhenyousavesourcefilesIwilltalkmoreaboutIDEsinthenextsection

gofmtisjustanaliaswhichrunsthecommandgofmt-l-wonthepackagesnamedbytheimportpaths

Weusuallyusegofmt-winsteadofgofmtThelatterwillnotrewriteyoursourcefilesafterformattingcodegofmt-wsrcformatsthewholeproject

gogetThiscommandisforgettingremotepackagesSofaritsupportsBitBucketGithubGoogleCodeandLaunchpadThereareactuallytwothingsthathappenafterweexecutethiscommandThefirstthingisthatGodownloadsthesourcecodethenexecutesgoinstallBeforeyouusethiscommandmakesureyouhaveinstalledalloftherelatedtools

BitBucket(MercurialGit)

Github(git)

GoogleCode(GitMercurialSubversion)

Launchpad(Bazaar)

InordertousethiscommandyouhavetoinstallthesetoolscorrectlyDontforgettoupdatethe$PATHvariableBythewayitalsosupportscustomizeddomainnamesUsegohelpimportpathformoredetailsaboutthis

goinstallThiscommandcompilesallpackagesandgeneratesfilesthenmovesthemto$GOPATHpkgor$GOPATHbin

gotestThiscommandloadsallfileswhosenameinclude_testgoandgeneratestestfilesthenprintsinformationthatlookslikethefollowing

okarchivetar0011s

FAILarchivezip0022s

okcompressgzip0033s

IttestsallyourtestfilesbydefaultUsecommandgohelptestflagformoredetails

godocManypeoplesaythatwedontneedanythird-partydocumentationforprogramminginGo(actuallyIvemadeaCHMalready)Gohasapowerfultooltomanagedocumentationnatively

Gocommands

17

SohowdowelookuppackageinformationindocumentationForinstanceifyouwanttogetmoredetailsaboutthebuiltinpackageusethegodocbuiltincommandSimilarlyusethegodocnethttpcommandtolookupthehttppackagedocumentationIfyouwanttoseemoredetailsaboutspecificfunctionsusethegodocfmtPrintfandgodoc-srcfmtPrintfcommandstoviewthesourcecode

Executethegodoc-http=8080commandthenopen1270018080inyourbrowserYoushouldseealocalizedgolangorgItcannotonlyshowthestandardpackagesinformationbutalsopackagesinyour$GOPATHpkgItsgreatforpeoplewhoaresufferingfromtheGreatFirewallofChina

OthercommandsGoprovidesmorecommandsthanthosewevejusttalkedabout

gofixupgradecodefromanoldversionbeforego1toanewversionaftergo1

goversiongetinformationaboutyourversionofGo

goenvviewenvironmentvariablesaboutGo

golistlistallinstalledpackages

goruncompiletemporaryfilesandruntheapplication

TherearealsomoredetailsaboutthecommandsthatIvetalkedaboutYoucanusegohelpltcommandgttolookthemup

LinksDirectoryPrevioussection$GOPATHandworkspaceNextsectionGodevelopmenttools

Gocommands

18

GodevelopmenttoolsInthissectionImgoingtoshowyouafewIDEsthatcanhelpyoubecomeamoreefficientprogrammerwithcapabilitiessuchasintelligentcodecompletionandauto-formattingTheyareallcross-platformsothestepsIwillbeshowingyoushouldnotbeverydifferentevenifyouarenotusingthesameoperatingsystem

LiteIDELiteIDEisanopensourcelightweightIDEfordevelopingGoprojectsonlydevelopedbyvisualfc

Figure14MainpanelofLiteIDE

LiteIDEfeatures

Cross-platformWindowsLinuxMacOS

Cross-compileManagemultiplecompileenvironmentsSupportscross-compilationofGo

ProjectmanagementstandardDocumentationviewbasedon$GOPATHCompilationsystembasedon$GOPATHAPIdocumentationindexbasedon$GOPATH

GosourcecodeeditorCodeoutliningFullsupportofgocodeGodocumentationviewandAPIindexViewcodeexpressionusingF1FunctiondeclarationjumpusingF2GdbsupportAuto-formatwithgofmt

OthersMulti-languagePluginsystemTexteditorthemesSyntaxsupportbasedonKateintelligentcompletionbasedonfull-textCustomizedshortcutsMarkdownsupport

Real-timepreviewCustomizedCSSExportHTMLandPDFConvertandmergetoHTMLandPDF

LiteIDEinstallationInstallLiteIDE

Downloadpage

Godevelopmenttools

19

Sourcecode

YouneedtoinstallGofirstthendownloadtheversionappropriateforyouroperatingsystemDecompressthepackagetodirectlyuseit

Installgocode

Youhavetoinstallgocodeinordertouseintelligentcompletion

goget-ugithubcomnsfgocode

Compilationenvironment

SwitchconfigurationinLiteIDEtosuityouroperatingsystemInWindowsandusingthe64-bitversionofGoyoushouldchoosewin64astheconfigurationenvironmentinthetoolbarThenchooseOptionsfindLiteEnvintheleftlistandopenfilewin64envintherightlist

GOROOT=cgo

GOBIN=

GOARCH=amd64

GOOS=windows

CGO_ENABLED=1

PATH=GOBINGOROOTbinPATH

ReplaceGOROOT=cgotoyourGoinstallationpathsaveitIfyouhaveMinGW64addcMinGW64bintoyourpathenvironmentvariableforcgosupport

InLinuxandusingthe64-bitversionofGoyoushouldchooselinux64astheconfigurationenvironmentinthetoolbarThenchooseOptionsfindLiteEnvintheleftlistandopenthelinux64envfileintherightlist

GOROOT=$HOMEgo

GOBIN=

GOARCH=amd64

GOOS=linux

CGO_ENABLED=1

PATH=$GOBIN$GOROOTbin$PATH

ReplaceGOROOT=$HOMEgotoyourGoinstallationpathsaveit

$GOPATH$GOPATHisthepaththatcontainsalistofprojectsOpenthecommandtool(orpressCtrl+`inLiteIDE)thentypegohelpgopathformoredetailsItsveryeasytoviewandchange$GOPATHinLiteIDEFollowView-SetupGOPATHtoviewandchangethesevalues

SublimeTextHereImgoingtointroduceyoutheSublimeText3(Sublimeforshort)+GoSublime+gocodeLetmeexplainwhy

Intelligentcompletion

Figure15Sublimeintelligentcompletion

Auto-formatsourcefilesProjectmanagement

Godevelopmenttools

20

Figure16Sublimeprojectmanagement

Syntaxhighlight

FreetrialforeverwithnofunctionallimitationsYoumaybepromptedonceinawhiletoremindyoutopurchasealicensebutyoucansimplyignoreitifyouwishOfcourseifyoudofindthatitenhancesyourproductivityandyoureallyenjoyusingitpleasepurchaseacopyofitandsupportitscontinueddevelopment

FirstdownloadtheversionofSublimesuitableforyouroperatingsystem

1 PressCtrl+`openthecommandtoolandinputthefollowingcommands

ApplicabletoSublimeText3

importurllibrequestospf=PackageControlsublime-packageipp=sublimeinstalled_packages_path()urllibrequesti

nstall_opener(urllibrequestbuild_opener(urllibrequestProxyHandler()))open(ospathjoin(ipppf)wb)write(urlli

brequesturlopen(httpsublimewbondnet+pfreplace(20))read())

ApplicabletoSublimeText2

importurllib2ospf=PackageControlsublime-packageipp=sublimeinstalled_packages_path()osmakedirs(ipp)ifnotos

pathexists(ipp)elseNoneurllib2install_opener(urllib2build_opener(urllib2ProxyHandler()))open(ospathjoin(ipp

pf)wb)write(urllib2urlopen(httpsublimewbondnet+pfreplace(20))read())print(PleaserestartSubl

imeTexttofinishinstallation)

RestartSublimeTextwhentheinstallationhasfinishedYoushouldthenfinda`PackageControl`optioninthePref

erencesmenu

[](images14sublime3pngraw=true)

Figure17SublimePackageControl

1 ToinstallGoSublimeSidebarEnhancementsandGoBuildpressCtrl+Shift+ptoopenPackageControlthentypepcip(shortforPackageControlInstallPackage)

Figure18SublimeInstallPackages

NowtypeinGoSublimepressOKtoinstallthepackageandrepeatthesamestepsforinstallingSidebarEnhancementsandGoBuildOnceagainrestarttheeditorwhenitcompletestheinstallation

2 ToverifythattheinstallationissuccessfulopenSublimethenopenthemaingofiletoseeifithasthepropersyntaxhighlightingTypeimporttoseeifcodecompletionpromptsappearAftertypingimportfmttypefmtanywhereaftertheimportdeclarationtoseewhetherornotintelligentcodecompletionforfunctionswassuccessfullyenabled

Ifeverythingisfineyoureallset

Ifnotcheckyour$PATHagainOpenaterminaltypegocodeIfitdoesnotrunyour$PATHwasnotconfiguredcorrectly

VimVimisapopulartexteditorforprogrammerswhichevolvedfromitsslimmerpredecessorViIthasfunctionsforintelligentcompletioncompilationandjumpingtoerrors

vim-goisvimaboveanopen-sourcegolanguageusingthemostextensivedevelopmentenvironmentplug-ins

Thepluginaddressgithubcomfatihvim-go

Godevelopmenttools

21

VimpluginmanagementarethemainstreamPathogenandVundleButtheaspectsthereofaredifferentPathogenistosolveeachplug-inaftertheinstallationoffilesscatteredtomultipledirectoriesandpoormanagementoftheexistenceVundleistosolvetheautomaticsearchanddownloadplug-insexistThesetwoplug-inscanbeusedsimultaneously

1InstallVundle

mkdir~vimbundle

gitclonehttpsgithubcomgmarikVundlevimgit~vimbundleVundlevim

EditvimrcVundletherelevantconfigurationwillbeplacedinthebeginning(RefertotheVundledocumentationfordetails)

setnocompatiblebeiMprovedrequired

filetypeoffrequired

settheruntimepathtoincludeVundleandinitialize

setrtp+=~vimbundleVundlevim

callvundlebegin()

letVundlemanageVundlerequired

PlugingmarikVundlevim

AllofyourPluginsmustbeaddedbeforethefollowingline

callvundleend()required

filetypepluginindentonrequired

2InstallVim-go

Edit~vimrcAddalinebetweenvundlebeginandvundleend

Pluginfatihvim-go

ExecutedwithinVimPluginInstall

3InstallYCM(YourCompleteMe)toAutoCompleteAddalineto~vimrc

PluginValloricYouCompleteMe

ExecutedwithinVimPluginInstall

Figure18VimintelligentcompletionforGo

1 SyntaxhighlightingforGo

cp-r$GOROOTmiscvim~vim

2 Enablingsyntaxhighlighting

filetypepluginindenton

syntaxon

3 Installgocode

goget-ugithubcomnsfgocode

gocodewillbeinstalledin$GOBINasdefault

Godevelopmenttools

22

4 Configuregocode

~cd$GOPATHsrcgithubcomnsfgocodevim

~updatesh

~gocodesetpropose-builtinstrue

propose-builtinstrue

~gocodesetlib-pathhomebordergocodepkglinux_amd64

lib-pathhomebordergocodepkglinux_amd64

~gocodeset

propose-builtinstrue

lib-pathhomebordergocodepkglinux_amd64

Explanationofgocodeconfiguration

propose-builtinsspecifieswhetherornottoopenintelligentcompletionfalsebydefaultlib-pathgocodeonlysearchesforpackagesin$GOPATHpkg$GOOS_$GOARCHand$GOROOTpkg$GOOS_$GOARCHThissettingcanbeusedtoaddadditionalpaths

5 CongratulationsTryemaingotoexperiencetheworldofGo

EmacsEmacsistheso-calledWeaponofGodSheisnotonlyaneditorbutalsoapowerfulIDE

Figure110EmacsmainpanelofGoeditor

1 Syntaxhighlighting

cp$GOROOTmiscemacs~emacsd

2 Installgocode

goget-ugithubcomnsfgocode

gocodewillbeinstalledin$GOBINasdefault

3 Configuregocode

~cd$GOPATHsrcgithubcomnsfgocodevim

~updatebash

~gocodesetpropose-builtinstrue

propose-builtinstrue

~gocodesetlib-pathhomebordergocodepkglinux_amd64

lib-pathhomebordergocodepkglinux_amd64

~gocodeset

propose-builtinstrue

lib-pathhomebordergocodepkglinux_amd64

4 InstallAutoCompletionDownloadanduncompress

~makeinstallDIR=$HOMEemacsdauto-complete

Configure~emacsfile

Godevelopmenttools

23

auto-complete

(requireauto-complete-config)

(add-to-listac-dictionary-directories~emacsdauto-completeac-dict)

(ac-config-default)

(local-set-key(kbdM-)semantic-complete-analyze-inline)

(local-set-keysemantic-complete-self-insert)

(local-set-keygtsemantic-complete-self-insert)

Followthislinkformoredetails

5 Configureemacs

golangmode

(requirego-mode-load)

(requirego-autocomplete)

speedbar

(speedbar1)

(speedbar-add-supported-extensiongo)

(add-hook

go-mode-hook

(lambda()

gocode

(auto-complete-mode1)

(setqac-sources(ac-source-go))

ImenuampSpeedbar

(setqimenu-generic-expression

((type^type([^tnrf])1)

(func^func()1)))

(imenu-add-to-menubarIndex)

Outlinemode

(make-local-variableoutline-regexp)

(setqoutline-regexp|[^rnf][^rnf]|pack|func|impo|cons|var|type|tt)

(outline-minor-mode1)

(local-set-keyM-aoutline-previous-visible-heading)

(local-set-keyM-eoutline-next-visible-heading)

Menubar

(requireeasymenu)

(defconstgo-hooked-menu

(Gotools

[Gorunbuffergot]

[Goreformatbuffergo-fmt-buffert]

[Gocheckbuffergo-fix-buffert]))

(easy-menu-define

go-added-menu

(current-local-map)

Gotools

go-hooked-menu)

Other

(setqshow-trailing-whitespacet)

))

helperfunction

(defungo()

runcurrentbuffer

(interactive)

(compile(concatgorun(buffer-file-name))))

helperfunction

(defungo-fmt-buffer()

rungofmtoncurrentbuffer

(interactive)

(ifbuffer-read-only

(progn

(ding)

(messageBufferisreadonly))

(let((p(line-number-at-pos))

(filename(buffer-file-name))

(old-max-mini-window-heightmax-mini-window-height))

(show-all)

(if(get-bufferGoReformatErrors)

Godevelopmenttools

24

(progn

(delete-windows-onGoReformatErrors)

(kill-bufferGoReformatErrors)))

(setqmax-mini-window-height1)

(if(=0(shell-command-on-region(point-min)(point-max)gofmtGoReformatOutputnilGoRefor

matErrorst))

(progn

(erase-buffer)

(insert-buffer-substringGoReformatOutput)

(goto-char(point-min))

(forward-line(1-p)))

(with-current-bufferGoReformatErrors

(progn

(goto-char(point-min))

(while(re-search-forwardltstandardinputgtnilt)

(replace-matchfilename))

(goto-char(point-min))

(compilation-mode))))

(setqmax-mini-window-heightold-max-mini-window-height)

(delete-windows-onGoReformatOutput)

(kill-bufferGoReformatOutput))))

helperfunction

(defungo-fix-buffer()

rungofixoncurrentbuffer

(interactive)

(show-all)

(shell-command-on-region(point-min)(point-max)gotoolfix-diff))

6 CongratulationsyouredoneSpeedbarisclosedbydefault-removethecommentsymbolsintheline(speedbar1)toenablethisfeatureoryoucanuseitthroughM-xspeedbar

EclipseEclipseisalsoagreatdevelopmenttoolIllshowyouhowtouseittowriteGoprograms

Figure11EclipsemainpanelforeditingGo

1 DownloadandinstallEclipse2 DownloadgoclipsehttpcodegooglecompgoclipsewikiInstallationInstructions3 Downloadgocode

gocodeinGithub

httpsgithubcomnsfgocode

YouneedtoinstallgitinWindowsusuallyweusemsysgit

Installgocodeinthecommandtool

goget-ugithubcomnsfgocode

Youcaninstallfromsourcecodeifyoulike

4 DownloadandinstallMinGW5 Configureplugins

Windows-gtPreferences-gtGo

(1)ConfigureGocompiler

Godevelopmenttools

25

Figure112GoSettinginEclipse

(2)Configuregocode(optional)setgocodepathtowherethegocodeexeis

Figure113gocodeSetting

(3)Configuregdb(optional)setgdbpathtowherethegdbexeis

Figure114gdbSetting

6 Checktheinstallation

CreateanewGoprojectandhellogofileasfollowing

Figure115Createanewprojectandfile

Testinstallationasfollows(youneedtotypecommandinconsoleinEclipse)

Figure116TestGoprograminEclipse

IntelliJIDEAPeoplewhohaveworkedwithJavashouldbefamiliarwiththisIDEItsupportsGosyntaxhighlightingandintelligentcodecompletionimplementedbyaplugin

1 DownloadIDEAthereisnodifferencebetweentheUltimateandCommunityeditions

2 InstalltheGopluginChooseFile-Setting-PluginsthenclickBrowserrepo

3 Searchgolangdoubleclickdownloadandinstallandwaitforthedownloadtocomplete

ClickApplythenrestart

4 NowyoucancreateaGoproject

InputthepositionofyourGosdkinthenextstep-basicallyitsyour$GOROOT

(SeeablogpostforsetupanduseIntelliJIDEAwithGostepbystep)

VisualStudioVSCodeThisisanawesometexteditorreleasedasopensourcecrossplatformmyMicrosoftwhichtakesthedevelopmentexperiencetoawholenewlevelhttpscodevisualstudiocomIthaseverythingamoderntexteditorisexpectedtohaveanddespitebeingbasedonthesamebackendthatatomioisbaseditisveryfast

ItworkswithWindowsMacLinuxIthasgopackagebuiltitprovidescodelinting

Godevelopmenttools

26

AtomAtomisanawesometexteditorreleasedasopensourcecrossplatformbuiltonElectronandbasedoneverythingweloveaboutourfavoriteeditorsWedesignedittobedeeplycustomizablebutstillapproachableusingthedefaultconfiguration

Downloadhttpsatomio

GoglandGoglandisthecodenameforanewcommercialIDEbyJetBrainsaimedatprovidinganergonomicenvironmentforGodevelopment

Theofficialversionisnotyetreleased

Downloadhttpswwwjetbrainscomgo

LinksDirectoryPrevioussectionGocommandsNextsectionSummary

Godevelopmenttools

27

15SummaryInthischapterwetalkedabouthowtoinstallGousingthreedifferentmethodsincludingfromsourcecodethestandardpackageandviathird-partytoolsThenweshowedyouhowtoconfiguretheGodevelopmentenvironmentmainlycoveringhowtosetupyour$GOPATHAfterthatweintroducedsomestepsforcompilinganddeployingGoprogramsWethencoveredGocommandsincludingthecompileinstallformatandtestcommandsFinallytherearemanypowerfultoolstodevelopGoprogramssuchasLiteIDESublimeTextVSCodeAtomGoglangVimEmacsEclipseIntelliJIDEAetcYoucanchooseanyoneyoulikeexploringtheworldofGo

LinksDirectoryPrevioussectionGodevelopmenttoolsNextchapterGobasicknowledge

Summary

28

2GobasicknowledgeGoisacompiledsystemprogramminglanguageanditbelongstotheC-familyHoweveritscompilationspeedismuchfasterthanotherC-familylanguagesIthasonly25keywordsevenlessthanthe26lettersoftheEnglishalphabetLetstakealookatthesekeywordsbeforewegetstarted

breakdefaultfuncinterfaceselect

casedefergomapstruct

chanelsegotopackageswitch

constfallthroughifrangetype

continueforimportreturnvar

InthischapterImgoingtoteachyousomebasicGoknowledgeYouwillfindouthowconcisetheGoprogramminglanguageisandthebeautifuldesignofthelanguageProgrammingcanbeveryfuninGoAfterwecompletethischapteryoullbefamiliarwiththeabovekeywords

LinksDirectoryPreviouschapterChapter1SummaryNextsectionHelloGo

Gobasicknowledge

29

WhatmakesGodifferentfromotherlanguagesTheGoprogramminglanguagewascreatedwithonegoalinmindtobeabletobuildscalableweb-applicationsforlargescaleaudiencesinalargeteamSothatisthereasontheymadethelanguageasstandardizedaspossiblehencethegofmttoolandthestrictusageguidelinestothelanguagewasforthesakeofnothavingtwofactionsinthedeveloperbaseinotherlanguagestherearereligiouswarsonwheretokeeptheopeningbrace

publicstaticvoidmain()

or

publicstaticvoidmain()

orforpythonshouldweuse4spacesor6spacesoratabortwotabsandotheruserpreferencesIfyouknowpythonthenyoumightbeawareofPEP8whichisasetofguidelinesabouthowtowriteelegantcode

WhilethismightseemtobeashallowproblemwhenthecodebasegrowsandmoreandmorepeopleworkonthesamecodebaseitisbecomesincreasinglydifficulttomaintainthecodesbeautyWeliveinaworldwhererobotscandriveacarsoweshouldntjustwritecodeweshouldwriteelegantcode

ForotherlanguagestherearemanyvariableswhenitcomestowritingcodeEverylanguageisgoodforitsusecasebutGoisalittlespecialbecauseitwasdesignedatacompanywhichistheverysynonymoftheInternet(anddistributedcomputing)TypicallyinordertooptimizeprogramsdeveloperschoosetowriteJavaoverPythonandC++overJavabutalmostallavailablelanguageswidelyinusewerewrittendecadesagowhen1GBstoragewasmuchpricierNowstorageandcomputingisrelativelycheapandcomputersaregettingmultiplescoresbuttheoldlanguagesarenotharnessingconcurrencyinawaythatgodoesItsnotbecausethoselanguagesarebadutilizingconcurrencywasntarelevantusecasewhiletheolderlanguagesevolved

TomitigatealltheproblemsthatGooglefacedwithcurrenttoolstheywroteasystemslanguagecalledGowhichyouareabouttolearnTherearemanyadvantagestousinggolangandtherearedisadvantagestooforeverycoinhasbothsidesOneofthesignificantimprovementsinincodeformattingGooglehasdesignedthelanguagetoavoiddebatesoncodeformattingGocodewrittenbyanyoneintheworld(assumingtheyknowandusegofmt)willlookexactlythesameThiswontseemtomatteruntilyouworkinateamAlsowhenthecompanyusesautomatedcoderevieworsomeotherfancytechniquetheformattedcodemaybreakinotherlanguageswhichdonthavestrictandstandardformattingrulesbutnotingo

Gowasdesignedwithconcurrencyinmindpleasenotethatparallelism=concurrencythereisanamazingpostbyRobPikeonthegolangblogyouwillfinditthereitiswortharead

AnotherveryimportantchangethatistheconceptofGOPATHGonearethedayswhenyouhadtocreateafoldercalledcodeandthencreateworkspacesforeclipseandwhatnotNowyouhavetokeeponefoldertreeforgocodewhichwillbeupdatedbythepackagemanagerautomaticallyItisalsorecommendedtocreatefolderswitheitheracustomdomainorthegithubdomainforexampleIcreatedataskmanagerusinggolangsoIcreatedasetoffolders~gosrcgithubcomthewhitetulipTasks

NoteInnixsystems~standsforhomedirectorywhichisthewindowsequivalentofCUsersusernameNowthe~goistheuniverseforthegocodeinyourmachineThisisasignificantimprovementoverotherlanguageswecanstorethecodeefficientlywithouthasslesWhileitmightseemstrangeatfirstthisapproachmakealotofsensethantheridiculouspackagenamesiepackagenamesgeneratedforotherlanguagesusingreversedomains

NoteAlongwithsrctherearetwofolderspkgwhichisforpackagesandbinwhichisforbinary

HelloGo

30

ThisGOPATHadvantageisntjustrestrictedtostoringcodeinparticularfolderWhenyouhavecreatedfivepackagesforyourprojectyoudonthavetoimportthemlikeimportdbInsteadyoucanuseimportgithubcomthewhitetulipTasksdbsothatwhenexecutinggogetonmyrepothegotoolwillfindthepackagefromgithubcompathifitwasntdownloadedinitiallyThisstandardizesalotofscrewedupthingsintheprogrammingdiscipline(lt--Toremoveandreplacewithactualexplanationofwhythisisbetter)

Whiletheremaybesomefoundedcomplaintsthatgocreatorshaveignoredalllanguageresearchdonesincethepast30yrsyoucannotcreateaproductoralanguagewhicheveryonewillfallinlovewithTherearealwayssomeortheotherusecasesorconstraintswhichthecreatorsshouldconsiderConsideringalltheadvantagesatleastforwebdevelopmentIdonotthinkanylanguagegetsclosetotheadvantageswhichgohasevenifyouignoreallthatIsaidaboveGoisacompiledlanguagewhichmeansinproductionyouwonthavetosetupaJVMoravirtualenvandwillinsteadhaveasinglestaticbinaryLikeanicingonacakeallthemodernlibrariesareinthestandardlibrarysuchasthehttpliballowingyoutocreatewebappsingolangwithoutusingathirdpartywebframework

21HelloGoBeforewestartbuildinganapplicationinGoweneedtolearnhowtowriteasimpleprogramYoucantexpecttobuildabuildingwithoutfirstknowinghowtobuilditsfoundationThereforewearegoingtolearnthebasicsyntaxtorunsomesimpleprogramsinthissection

ProgramAccordingtointernationalpracticebeforeyoulearnhowtoprograminsomelanguagesyouwillwanttoknowhowtowriteaprogramtoprintHelloworld

AreyoureadyLetsGo

packagemain

importfmt

funcmain()

fmtPrintf(Helloworldor你好世界orΚαλημέρακόσμεorこんにちは世界n)

Itprintsfollowinginformation

Helloworldor你好世界orΚαλημέρακόσμεorこんにちは世界

ExplanationOnethingthatyoushouldknowinthefirstisthatGoprogramsarecomposedbypackage

packageltpkgNamegt(Inthiscaseispackagemain)tellsusthissourcefilebelongstomainpackageandthekeywordmaintellsusthispackagewillbecompiledtoaprograminsteadofpackagefileswhoseextensionsarea

Everyexecutableprogramhasoneandonlyonemainpackageandyouneedanentryfunctioncalledmainwithoutanyargumentsorreturnvaluesinthemainpackage

InordertoprintHelloworldhellipwecalledafunctioncalledPrintfThisfunctioniscomingfromfmtpackagesoweimportthispackageinthethirdlineofsourcecodewhichisimportfmt

ThewaytothinkaboutpackagesinGoissimilartoPythonandtherearesomeadvantagesModularity(breakupyourprogramintomanymodules)andreusability(everymodulecanbereusedinmanyprograms)Wejusttalkedaboutconceptsregardingpackagesandwewillmakeourownpackageslater

HelloGo

31

OnthefifthlineweusethekeywordfunctodefinethemainfunctionThebodyofthefunctionisinsideofjustlikeCC++andJava

AsyoucanseetherearenoargumentsWewilllearnhowtowritefunctionswithargumentsinjustasecondandyoucanalsohavefunctionsthathavenoreturnvalueorhaveseveralreturnvalues

OnthesixthlinewecalledthefunctionPrintfwhichisfromthepackagefmtThiswascalledbythesyntaxltpkgNamegtltfuncNamegtwhichisverylikePython-style

Aswementionedinchapter1thepackagesnameandthenameofthefolderthatcontainsthatpackagecanbedifferentHeretheltpkgNamegtcomesfromthenameinpackageltpkgNamegtnotthefoldersname

Youmaynoticethattheexampleabovecontainsmanynon-ASCIIcharactersThepurposeofshowingthisistotellyouthatGosupportsUTF-8bydefaultYoucanuseanyUTF-8characterinyourprograms

EachgofileisinsomepackageandthatpackageshouldbeadistinctfolderintheGOPATHbutmainisaspecialpackagewhichdoesntrequireamainfolderThisisoneaspectwhichtheyleftoutforstandardizationButshouldyouchoosetomakeamainfolderthenyouhavetoensurethatyourunthebinaryproperlyAlsoonegocodecanthavemorethanonemaingofile

~gosrcgithubcomthewhitetulipTasksmain$gobuild~gosrcgithubcomthewhitetulipTasks$mainmain

thethinghereisthatwhenyourcodeisusingsomestaticfilesorsomethingelsethenyououghttorunthebinaryfromtherootoftheapplicationasweseeinthesecondlineaboveIamrunningthemainbinaryoutsidethemainpackagesometimesyoumightwonderwhyyourapplicationisntworkingthenthismightbeoneofthepossibleproblemspleasekeepthisinmind

Onethingyouwillnoticehereisthatgodoesntseetousesemicolonstoendastatementwellitdoesjustthereisaminorcatchtheprogrammerisntexpectedtoputsemicolonsthecompileraddssemicolonstothegocodewhenitcompileswhichisthereasonthatthis(thankfully)isasyntaxerror

funcmain()

becausethecompileraddsasemicolonattheendofmain()whichisasyntaxerrorandasstatedaboveithelpsavoidreligiouswarsiwishtheycombinevimandemacsandcreateauniversaleditorwhichllhelpsavesomemorewarsButfornowwelllearnGo

ConclusionGousespackage(likemodulesinPython)toorganizeprogramsThefunctionmainmain()(thisfunctionmustbeinthemainpackage)istheentrypointofanyprogramGostandardizeslanguageandmostoftheprogrammingmethodologysavingtimeofdeveloperswhichtheydhavewastedinreligiouswarsTherecanbeonlyonemainpackageandonlyonemainfunctioninsideagomainpackageGosupportsUTF-8charactersbecauseoneofthecreatorsofGoisacreatorofUTF-8soGohassupportedmultiplelanguagesfromthetimeitwasborn

LinksDirectoryPrevioussectionGobasicknowledgeNextsectionGofoundation

HelloGo

32

HelloGo

33

22GofoundationInthissectionwearegoingtoteachyouhowtodefineconstantsvariableswithelementarytypesandsomeskillsinGoprogramming

DefinevariablesTherearemanyformsofsyntaxthatcanbeusedtodefinevariablesinGo

ThekeywordvaristhebasicformtodefinevariablesnoticethatGoputsthevariabletypeafterthevariablename

defineavariablewithnameldquovariableNamerdquoandtypetype

varvariableNametype

Definemultiplevariables

definethreevariableswhichtypesaretype

varvname1vname2vname3type

Defineavariablewithinitialvalue

defineavariablewithnameldquovariableNamerdquotypetypeandvaluevalue

varvariableNametype=value

Definemultiplevariableswithinitialvalues

Definethreevariableswithtypetypeandinitializetheirvalues

vname1isv1vname2isv2vname3isv3

varvname1vname2vname3type=v1v2v3

DoyouthinkthatitstootedioustodefinevariablesusethewayaboveDontworrybecausetheGoteamhasalsofoundthistobeaproblemThereforeifyouwanttodefinevariableswithinitialvalueswecanjustomitthevariabletypesothecodewilllooklikethisinstead

Definethreevariableswithouttypetypeandinitializetheirvalues

vname1isv1vname2isv2vname3isv3

varvname1vname2vname3=v1v2v3

WellIknowthisisstillnotsimpleenoughforyouLetsseehowwefixit

Definethreevariableswithouttypetypeandwithoutkeywordvarandinitializetheirvalues

vname1isv1vname2isv2vname3isv3

vname1vname2vname3=v1v2v3

NowitlooksmuchbetterUse=toreplacevarandtypethisiscalledashortassignmentIthasonelimitationthisformcanonlybeusedinsideofafunctionsYouwillgetcompileerrorsifyoutrytouseitoutsideoffunctionbodiesThereforeweusuallyusevartodefineglobalvariables

Gofoundation

34

_(blank)isaspecialvariablenameAnyvaluethatisgiventoitwillbeignoredForexamplewegive35tobanddiscard34(ThisexamplejustshowyouhowitworksItlooksuselessherebecauseweoftenusethissymbolwhenwegetfunctionreturnvalues)

_b=3435

IfyoudontusevariablesthatyouvedefinedinyourprogramthecompilerwillgiveyoucompilationerrorsTrytocompilethefollowingcodeandseewhathappens

packagemain

funcmain()

variint

ConstantsSo-calledconstantsarethevaluesthataredeterminedduringcompiletimeandyoucannotchangethemduringruntimeInGoyoucanusenumberbooleanorstringastypesofconstants

Defineconstantsasfollows

constconstantName=value

youcanassigntypeofconstantsifitsnecessary

constPifloat32=31415926

Moreexamples

constPi=31415926

consti=10000

constMaxThread=10

constprefix=astaxie_

Elementarytypes

Boolean

InGoweusebooltodefineavariableasbooleantypethevaluecanonlybetrueorfalseandfalsewillbethedefaultvalue(Youcannotconvertvariablestypebetweennumberandboolean)

samplecode

varisActiveboolglobalvariable

varenableddisabled=truefalseomittypeofvariables

functest()

varavailableboollocalvariable

valid=falsebriefstatementofvariable

available=trueassignvaluetovariable

Numericaltypes

IntegertypesincludebothsignedandunsignedintegertypesGohasintanduintatthesametimetheyhavesamelengthbutspecificlengthdependsonyouroperatingsystemTheyuse32-bitin32-bitoperatingsystemsand64-bitin64-bitoperatingsystemsGoalsohastypesthathavespecificlengthincludingruneint8int16int32int64byteuint8uint16uint32uint64Notethatruneisaliasofint32andbyteisaliasofuint8

Gofoundation

35

Oneimportantthingyoushouldknowthatyoucannotassignvaluesbetweenthesetypesthisoperationwillcausecompileerrors

varaint8

varbint32

c=a+b

Althoughint32hasalongerlengththanint8andhasthesametypeasintyoucannotassignvaluesbetweenthem(cwillbeassertedastypeinthere)

Floattypeshavethefloat32andfloat64typesandnotypecalledfloatThelatteroneisthedefaulttypeifusingbriefstatement

ThatsallNoGosupportscomplexnumbersaswellcomplex128(witha64-bitrealand64-bitimaginarypart)isthedefaulttypeifyouneedasmallertypethereisonecalledcomplex64(witha32-bitrealand32-bitimaginarypart)ItsformisRE+IMiwhereREisrealpartandIMisimaginarypartthelastiistheimaginarynumberThereisaexampleofcomplexnumber

varccomplex64=5+5i

output(5+5i)

fmtPrintf(Valueisvc)

String

WejusttalkedabouthowGousestheUTF-8charactersetStringsarerepresentedbydoublequotesorbackticks `

samplecode

varfrenchHellostringbasicformtodefinestring

varemptyStringstring=defineastringwithemptystring

functest()

noyesmaybe=noyesmaybebriefstatement

japaneseHello=Ohaiou

frenchHello=Bonjourbasicformofassignvalues

ItsimpossibletochangestringvaluesbyindexYouwillgeterrorswhenyoucompilethefollowingcode

varsstring=hello

s[0]=c

WhatifIreallywanttochangejustonecharacterinastringTrythefollowingcode

s=hello

c=[]byte(s)convertstringto[]bytetype

c[0]=c

s2=string(c)convertbacktostringtype

fmtPrintf(sns2)

Youusethe+operatortocombinetwostrings

s=hello

m=world

a=s+m

fmtPrintf(sna)

andalso

Gofoundation

36

s=hello

s=c+s[1]youcannotchangestringvaluesbyindexbutyoucangetvaluesinstead

fmtPrintf(sns)

WhatifIwanttohaveamultiple-linestring

m=`hello

world`

willnotescapeanycharactersinastring

ErrortypesGohasoneerrortypeforpurposeofdealingwitherrormessagesThereisalsoapackagecallederrorstohandleerrors

err=errorsNew(emitmachodwarfelfheadercorrupted)

iferr=nil

fmtPrint(err)

Underlyingdatastructure

ThefollowingpicturecomesfromanarticleaboutGodatastructureinRussCoxsBlogAsyoucanseeGoutilizesblocksofmemorytostoredata

Figure21Gounderlyingdatastructure

Someskills

Definebygroup

Ifyouwanttodefinemultipleconstantsvariablesorimportpackagesyoucanusethegroupform

Basicform

importfmt

importos

consti=100

constpi=31415

constprefix=Go_

variint

varpifloat32

varprefixstring

Groupform

Gofoundation

37

import(

fmt

os

)

const(

i=100

pi=31415

prefix=Go_

)

var(

iint

pifloat32

prefixstring

)

Unlessyouassignthevalueofconstantisiotathefirstvalueofconstantinthegroupconst()willbe0IffollowingconstantsdontassignvaluesexplicitlytheirvalueswillbethesameasthelastoneIfthevalueoflastconstantisiotathevaluesoffollowingconstantswhicharenotassignedareiotaalso

iotaenumerate

Gohasonekeywordcallediotathiskeywordistomakeenumitbeginswith0increasedby1

const(

x=iotax==0

y=iotay==1

z=iotaz==2

wIfthereisnoexpressionaftertheconstantsnameitusesthelastexpression

soitssayingw=iotaimplicitlyThereforew==3andyandzbothcanomit=iotaaswell

)

constv=iotaonceiotameetskeyword`const`itresetsto`0`sov=0

const(

efg=iotaiotaiotae=0f=0g=0valuesofiotaaresameinoneline

)

Somerules

ThereasonthatGoisconcisebecauseithassomedefaultbehaviors

AnyvariablethatbeginswithacapitallettermeansitwillbeexportedprivateotherwiseThesameruleappliesforfunctionsandconstantsnopublicorprivatekeywordexistsinGo

arrayslicemap

array

arrayisanarrayobviouslywedefineoneasfollows

vararr[n]type

in[n]typenisthelengthofthearraytypeisthetypeofitselementsLikeotherlanguagesweuse[]togetorsetelementvalueswithinarrays

Gofoundation

38

vararr[10]intanarrayoftype[10]int

arr[0]=42arrayis0-based

arr[1]=13assignvaluetoelement

fmtPrintf(Thefirstelementisdnarr[0])

getelementvalueitreturns42

fmtPrintf(Thelastelementisdnarr[9])

itreturnsdefaultvalueof10thelementinthisarraywhichis0inthiscase

Becauselengthisapartofthearraytype[3]intand[4]intaredifferenttypessowecannotchangethelengthofarraysWhenyouusearraysasargumentsfunctionsgettheircopiesinsteadofreferencesIfyouwanttousereferencesyoumaywanttousesliceWelltalkaboutlater

Itspossibletouse=whenyoudefinearrays

a=[3]int123defineanintarraywith3elements

b=[10]int123

defineaintarraywith10elementsofwhichthefirstthreeareassigned

Therestofthemusethedefaultvalue0

c=[]int456use`hellip`toreplacethelengthparameterandGowillcalculateitforyou

YoumaywanttousearraysasarrayselementsLetsseehowtodothis

defineatwo-dimensionalarraywith2elementsandeachelementhas4elements

doubleArray=[2][4]int[4]int1234[4]int5678

Thedeclarationcanbewrittenmoreconciselyasfollows

easyArray=[2][4]int12345678

Arrayunderlyingdatastructure

Figure22Multidimensionalarraymappingrelationship

sliceInmanysituationsthearraytypeisnotagoodchoice-forinstancewhenwedontknowhowlongthearraywillbewhenwedefineitThusweneedadynamicarrayThisiscalledsliceinGo

sliceisnotreallyadynamicarrayItsareferencetypeslicepointstoanunderlyingarraywhosedeclarationissimilartoarraybutdoesntneedlength

justlikedefininganarraybutthistimeweexcludethelength

varfslice[]int

Thenwedefineasliceandinitializeitsdata

slice=[]byteabcd

slicecanredefineexistingslicesorarrayssliceusesarray[ij]toslicewhereiisthestartindexandjisendindexbutnoticethatarray[j]willnotbeslicedsincethelengthofthesliceisj-i

Gofoundation

39

defineanarraywith10elementswhosetypesarebytes

varar=[10]byteabcdefghij

definetwosliceswithtype[]byte

varab[]byte

apointstoelementsfrom3rdto5thinarrayar

a=ar[25]

nowahaselementsar[2]ar[3]andar[4]

bisanothersliceofarrayar

b=ar[35]

nowbhaselementsar[3]andar[4]

NoticethedifferencesbetweensliceandarraywhenyoudefinethemWeuse[hellip]toletGocalculatelengthbutuse[]todefinesliceonly

Theirunderlyingdatastructure

Figure23Correspondencebetweensliceandarray

slicehassomeconvenientoperations

sliceis0-basedar[n]equalstoar[0n]Thesecondindexwillbethelengthofsliceifomittedar[n]equalstoar[nlen(ar)]Youcanusear[]toslicewholearrayreasonsareexplainedinfirsttwostatements

Moreexamplespertainingtoslice

defineanarray

vararray=[10]byteabcdefghij

definetwoslices

varaSlicebSlice[]byte

someconvenientoperations

aSlice=array[3]equalstoaSlice=array[03]aSlicehaselementsabc

aSlice=array[5]equalstoaSlice=array[510]aSlicehaselementsfghij

aSlice=array[]equalstoaSlice=array[010]aSlicehasallelements

slicefromslice

aSlice=array[37]aSlicehaselementsdefglen=4cap=7

bSlice=aSlice[13]bSlicecontainsaSlice[1]aSlice[2]soithaselementsef

bSlice=aSlice[3]bSlicecontainsaSlice[0]aSlice[1]aSlice[2]soithasdef

bSlice=aSlice[05]slicecouldbeexpandedinrangeofcapnowbSlicecontainsdefgh

bSlice=aSlice[]bSlicehassameelementsasaSlicedoeswhicharedefg

sliceisareferencetypesoanychangeswillaffectothervariablespointingtothesamesliceorarrayForinstanceinthecaseofaSliceandbSliceaboveifyouchangethevalueofanelementinaSlicebSlicewillbechangedaswell

sliceislikeastructbydefinitionanditcontains3parts

ApointerthatpointstowhereslicestartsThelengthofsliceCapacitythelengthfromstartindextoendindexofslice

Array_a=[10]byteabcdefghij

Slice_a=Array_a[25]

Theunderlyingdatastructureofthecodeaboveasfollows

Gofoundation

40

Figure24Arrayinformationofslice

Therearesomebuilt-infunctionsforslice

lengetsthelengthofslicecapgetsthemaximumlengthofsliceappendappendsoneormoreelementstosliceandreturnsslicecopycopieselementsfromoneslicetotheotherandreturnsthenumberofelementsthatwerecopied

AttentionappendwillchangethearraythatslicepointstoandaffectotherslicesthatpointtothesamearrayAlsoifthereisnotenoughlengthfortheslice((cap-len)==0)appendreturnsanewarrayforthissliceWhenthishappensotherslicespointingtotheoldarraywillnotbeaffected

map

mapbehaveslikeadictionaryinPythonUsetheformmap[keyType]valueTypetodefineit

LetsseesomecodeThesetandgetvaluesinmaparesimilartoslicehowevertheindexinslicecanonlybeoftypeintwhilemapcanusemuchmorethanthatforexampleintstringorwhateveryouwantAlsotheyareallabletouse==and=tocomparevalues

usestringasthekeytypeintasthevaluetypeand`make`initializeit

varnumbersmap[string]int

anotherwaytodefinemap

numbers=make(map[string]int)

numbers[one]=1assignvaluebykey

numbers[ten]=10

numbers[three]=3

fmtPrintln(Thethirdnumberisnumbers[three])getvalues

ItprintsThethirdnumberis3

Somenoteswhenyouusemap

mapisdisorderlyEverytimeyouprintmapyouwillgetdifferentresultsItsimpossibletogetvaluesbyindex-youhavetousekeymapdoesnthaveafixedlengthItsareferencetypejustlikeslicelenworksformapalsoItreturnshowmanykeysthatmaphasItsquiteeasytochangethevaluethroughmapSimplyusenumbers[one]=11tochangethevalueofkeyoneto11

Youcanuseformkeyvaltoinitializemapsvaluesandmaphasbuilt-inmethodstocheckifthekeyexists

Usedeletetodeleteanelementinmap

Initializeamap

rating=map[string]float32C5Go45Python45C++2

maphastworeturnvaluesForthesecondreturnvalueifthekeydoesnt

existokreturnsfalseItreturnstrueotherwise

csharpRatingok=rating[C]

ifok

fmtPrintln(CisinthemapanditsratingiscsharpRating)

else

fmtPrintln(WehavenoratingassociatedwithCinthemap)

delete(ratingC)deleteelementwithkeyc

AsIsaidabovemapisareferencetypeIftwomapspointtosameunderlyingdataanychangewillaffectbothofthem

Gofoundation

41

m=make(map[string]string)

m[Hello]=Bonjour

m1=m

m1[Hello]=Salutnowthevalueofm[hello]isSalut

makenewmakedoesmemoryallocationforbuilt-inmodelssuchasmapsliceandchannelwhilenewisfortypesmemoryallocation

new(T)allocateszero-valuetotypeTsmemoryreturnsitsmemoryaddresswhichisthevalueoftypeTByGosdefinitionitreturnsapointerwhichpointstotypeTszero-value

newreturnspointers

Thebuilt-infunctionmake(Targs)hasdifferentpurposesthannew(T)makecanbeusedforslicemapandchannelandreturnsatypeTwithaninitialvalueThereasonfordoingthisisbecausetheunderlyingdataofthesethreetypesmustbeinitializedbeforetheypointtothemForexampleaslicecontainsapointerthatpointstotheunderlyingarraylengthandcapacityBeforethesedataareinitializedsliceisnilsoforslicemapandchannelmakeinitializestheirunderlyingdataandassignssomesuitablevalues

makereturnsnon-zerovalues

Thefollowingpictureshowshownewandmakearedifferent

Figure25Underlyingmemoryallocationofmakeandnew

Zero-valuedoesnotmeanemptyvalueItsthevaluethatvariablesdefaulttoinmostcasesHereisalistofsomezero-values

int0

int80

int320

int640

uint0x0

rune0theactualtypeofruneisint32

byte0x0theactualtypeofbyteisuint8

float320lengthis4byte

float640lengthis8byte

boolfalse

string

LinksDirectoryPrevioussectionHelloGoNextsectionControlstatementsandfunctions

Gofoundation

42

23ControlstatementsandfunctionsInthissectionwearegoingtotalkaboutcontrolstatementsandfunctionoperationsinGo

ControlstatementThegreatestinventioninprogrammingisflowcontrolBecauseofthemyouareabletousesimplecontrolstatementsthatcanbeusedtorepresentcomplexlogicTherearethreecategoriesofflowcontrolconditionalcyclecontrolandunconditionaljump

if

ifwillmostlikelybethemostcommonkeywordinyourprogramsIfitmeetstheconditionsthenitdoessomethinganditdoessomethingelseifnot

ifdoesntneedparenthesesinGo

ifxgt10

fmtPrintln(xisgreaterthan10)

else

fmtPrintln(xislessthanorequalto10)

ThemostusefulthingconcerningifinGoisthatitcanhaveoneinitializationstatementbeforetheconditionalstatementThescopeofthevariablesdefinedinthisinitializationstatementareonlyavailableinsidetheblockofthedefiningif

initializexthencheckifxgreaterthan

ifx=computedValue()xgt10

fmtPrintln(xisgreaterthan10)

else

fmtPrintln(xislessthan10)

thefollowingcodewillnotcompile

fmtPrintln(x)

Useif-elseformultipleconditions

ifinteger==3

fmtPrintln(Theintegerisequalto3)

elseifintegerlt3

fmtPrintln(Theintegerislessthan3)

else

fmtPrintln(Theintegerisgreaterthan3)

gotoGohasagotokeywordbutbecarefulwhenyouuseitgotoreroutesthecontrolflowtoapreviouslydefinedlabelwithinthebodyofsamecodeblock

Controlstatementsandfunctions

43

funcmyFunc()

i=0

Herelabelendswith

fmtPrintln(i)

i++

gotoHerejumptolabelHere

Thelabelnameiscasesensitive

for

foristhemostpowerfulcontrollogicinGoItcanreaddatainloopsanditerativeoperationsjustlikewhile

forexpression1expression2expression3

expression1expression2andexpression3areallexpressionswhereexpression1andexpression3arevariabledefinitionsorreturnvaluesfromfunctionsandexpression2isaconditionalstatementexpression1willbeexecutedoncebeforeloopingandexpression3willbeexecutedaftereachloop

Examplesaremoreusefulthanwords

packagemain

importfmt

funcmain()

sum=0

forindex=0indexlt10index++

sum+=index

fmtPrintln(sumisequaltosum)

Printsumisequalto45

SometimesweneedmultipleassignmentsbutGodoesnthavetheoperatorsoweuseparallelassignmentlikeij=i+1j-1

Wecanomitexpression1andexpression3iftheyarenotnecessary

sum=1

forsumlt1000

sum+=sum

OmitaswellFeelfamiliarYesitsidenticaltowhile

sum=1

forsumlt1000

sum+=sum

TherearetwoimportantoperationsinloopswhicharebreakandcontinuebreakjumpsoutoftheloopandcontinueskipsthecurrentloopandstartsthenextoneIfyouhavenestedloopsusebreakalongwithlabels

Controlstatementsandfunctions

44

forindex=10indexgt0index--

ifindex==5

breakorcontinue

fmtPrintln(index)

breakprints109876

continueprints1098764321

forcanreaddatafromarrayslicemapandstringwhenitisusedtogetherwithrange

forkv=rangemap

fmtPrintln(mapskeyk)

fmtPrintln(mapsvalv)

BecauseGosupportsmulti-valuereturnsandgivescompileerrorswhenyoudontusevaluesthatweredefinedyoumaywanttouse_todiscardcertainreturnvalues

for_v=rangemap

fmtPrintln(mapsvalv)

Withgoyoucanaswellcreateaninfiniteloopwhichisequivalenttowhiletrueinotherlanguges

for

yourlogic

switchSometimesyoumayfindthatyouareusingtoomanyif-elsestatementstoimplementsomelogicwhichmaymakeitdifficulttoreadandmaintaininthefutureThisistheperfecttimetousetheswitchstatementtosolvethisproblem

switchsExpr

caseexpr1

someinstructions

caseexpr2

someotherinstructions

caseexpr3

someotherinstructions

default

othercode

ThetypeofsExprexpr1expr2andexpr3mustbethesameswitchisveryflexibleConditionsdonthavetobeconstantsanditexecutesfromtoptobottomuntilitmatchesconditionsIfthereisnostatementafterthekeywordswitchthenitmatchestrue

i=10

switchi

case1

fmtPrintln(iisequalto1)

case234

fmtPrintln(iisequalto23or4)

case10

fmtPrintln(iisequalto10)

default

fmtPrintln(AllIknowisthatiisaninteger)

Controlstatementsandfunctions

45

InthefifthlineweputmanyvaluesinonecaseandwedontneedtoaddthebreakkeywordattheendofcasesbodyItwilljumpoutoftheswitchbodyonceitmatchedanycaseIfyouwanttocontinuetomatchingmorecasesyouneedtousethefallthroughstatement

integer=6

switchinteger

case4

fmtPrintln(integerlt=4)

fallthrough

case5

fmtPrintln(integerlt=5)

fallthrough

case6

fmtPrintln(integerlt=6)

fallthrough

case7

fmtPrintln(integerlt=7)

fallthrough

case8

fmtPrintln(integerlt=8)

fallthrough

default

fmtPrintln(defaultcase)

Thisprogramprintsthefollowinginformation

integerlt=6

integerlt=7

integerlt=8

defaultcase

FunctionsUsethefunckeywordtodefineafunction

funcfuncName(input1type1input2type2)(output1type1output2type2)

functionbody

multi-valuereturn

returnvalue1value2

Wecanextrapolatethefollowinginformationfromtheexampleabove

UsekeywordfunctodefineafunctionfuncNameFunctionshavezerooneormorethanoneargumentsTheargumenttypecomesaftertheargumentnameandargumentsareseparatedbyFunctionscanreturnmultiplevaluesTherearetworeturnvaluesnamedoutput1andoutput2youcanomittheirnamesandusetheirtypeonlyIfthereisonlyonereturnvalueandyouomittedthenameyoudontneedbracketsforthereturnvaluesIfthefunctiondoesnthavereturnvaluesyoucanomitthereturnparametersaltogetherIfthefunctionhasreturnvaluesyouhavetousethereturnstatementsomewhereinthebodyofthefunction

Letsseeonepracticalexample(calculatemaximumvalue)

Controlstatementsandfunctions

46

packagemain

importfmt

returngreatervaluebetweenaandb

funcmax(abint)int

ifagtb

returna

returnb

funcmain()

x=3

y=4

z=5

max_xy=max(xy)callfunctionmax(xy)

max_xz=max(xz)callfunctionmax(xz)

fmtPrintf(max(dd)=dnxymax_xy)

fmtPrintf(max(dd)=dnxzmax_xz)

fmtPrintf(max(dd)=dnyzmax(yz))callfunctionhere

IntheaboveexampletherearetwoargumentsinthefunctionmaxtheirtypesarebothintsothefirsttypecanbeomittedForinstanceabintinsteadofaintbintThesamerulesapplyforadditionalargumentsNoticeherethatmaxonlyhasonereturnvaluesoweonlyneedtowritethetypeofitsreturnvalue-thisistheshortformofwritingit

Multi-valuereturn

OnethingthatGoisbetteratthanCisthatitsupportsmulti-valuereturns

Wellusethefollowingexamplehere

packagemain

importfmt

returnresultsofA+BandAB

funcSumAndProduct(ABint)(intint)

returnA+BAB

funcmain()

x=3

y=4

xPLUSyxTIMESy=SumAndProduct(xy)

fmtPrintf(d+d=dnxyxPLUSy)

fmtPrintf(dd=dnxyxTIMESy)

Theaboveexamplereturnstwovalueswithoutnames-youhavetheoptionofnamingthemalsoIfwenamedthereturnvalueswewouldjustneedtousereturntoreturnthevaluessincetheyareinitializedinthefunctionautomaticallyNoticethatifyourfunctionsaregoingtobeusedoutsideofthepackagewhichmeansyourfunctionnamesstartwithacapitalletteryoudbetterwritecompletestatementsforreturnitmakesyourcodemorereadable

funcSumAndProduct(ABint)(addintmultipliedint)

add=A+B

multiplied=AB

return

Controlstatementsandfunctions

47

Variadicfunctions

GosupportsfunctionswithavariablenumberofargumentsThesefunctionsarecalledvariadicwhichmeansthefunctionallowsanuncertainnumbersofarguments

funcmyfunc(argint)

arghellipinttellsGothatthisisafunctionthathasvariableargumentsNoticethattheseargumentsaretypeintInthebodyoffunctiontheargbecomesasliceofint

for_n=rangearg

fmtPrintf(Andthenumberisdnn)

Passbyvalueandpointers

Whenwepassanargumenttothefunctionthatwascalledthatfunctionactuallygetsthecopyofourvariablessoanychangewillnotaffecttotheoriginalvariable

Letsseeoneexampleinordertoprovewhatimsaying

packagemain

importfmt

simplefunctiontoadd1toa

funcadd1(aint)int

a=a+1wechangevalueofa

returnareturnnewvalueofa

funcmain()

x=3

fmtPrintln(x=x)shouldprintx=3

x1=add1(x)calladd1(x)

fmtPrintln(x+1=x1)shouldprintx+1=4

fmtPrintln(x=x)shouldprintx=3

CanyouseethatEventhoughwecalledadd1withxtheoriginvalueofxdoesntchange

Thereasonisverysimplewhenwecalledadd1wegaveacopyofxtoitnotthexitself

NowyoumayaskhowIcanpasstherealxtothefunction

WeneedusepointershereWeknowvariablesarestoredinmemoryandtheyhavesomememoryaddressesSoifwewanttochangethevalueofavariablewemustchangeitsmemoryaddressThereforethefunctionadd1hastoknowthememoryaddressofxinordertochangeitsvalueHerewepassampxtothefunctionandchangetheargumentstypetothepointertypeintBeawarethatwepassacopyofthepointernotcopyofvalue

Controlstatementsandfunctions

48

packagemain

importfmt

simplefunctiontoadd1toa

funcadd1(aint)int

a=a+1wechangedvalueofa

returnareturnnewvalueofa

funcmain()

x=3

fmtPrintln(x=x)shouldprintx=3

x1=add1(ampx)calladd1(ampx)passmemoryaddressofx

fmtPrintln(x+1=x1)shouldprintx+1=4

fmtPrintln(x=x)shouldprintx=4

NowwecanchangethevalueofxinthefunctionsWhydoweusepointersWhataretheadvantages

AllowsustousemorefunctionstooperateononevariableLowcostbypassingmemoryaddresses(8bytes)copyisnotanefficientwaybothintermsoftimeandspacetopassvariableschannelsliceandmaparereferencetypessotheyusepointerswhenpassingtofunctionsbydefault(AttentionIfyouneedtochangethelengthofsliceyouhavetopasspointersexplicitly)

deferGohasawelldesignedkeywordcalleddeferYoucanhavemanydeferstatementsinonefunctiontheywillexecuteinreverseorderwhentheprogramexecutestotheendoffunctionsInthecasewheretheprogramopenssomeresourcefilesthesefileswouldhavetobeclosedbeforethefunctioncanreturnwitherrorsLetsseesomeexamples

funcReadWrite()bool

fileOpen(file)

Dosomework

iffailureX

fileClose()

returnfalse

iffailureY

fileClose()

returnfalse

fileClose()

returntrue

WesawsomecodebeingrepeatedseveraltimesdefersolvesthisproblemverywellItdoesntonlyhelpyoutowritecleancodebutalsomakesyourcodemorereadable

Controlstatementsandfunctions

49

funcReadWrite()bool

fileOpen(file)

deferfileClose()

iffailureX

returnfalse

iffailureY

returnfalse

returntrue

IftherearemorethanonedeferstheywillexecutebyreverseorderThefollowingexamplewillprint43210

fori=0ilt5i++

deferfmtPrintf(di)

Functionsasvaluesandtypes

FunctionsarealsovariablesinGowecanusetypetodefinethemFunctionsthathavethesamesignaturecanbeseenasthesametype

typetypeNamefunc(input1inputType1input2inputType2[])(result1resultType1[])

WhatstheadvantageofthisfeatureTheansweristhatitallowsustopassfunctionsasvalues

packagemain

importfmt

typetestIntfunc(int)booldefineafunctiontypeofvariable

funcisOdd(integerint)bool

returninteger2=0

funcisEven(integerint)bool

returninteger2==0

passthefunction`f`asanargumenttoanotherfunction

funcfilter(slice[]intftestInt)[]int

varresult[]int

for_value=rangeslice

iff(value)

result=append(resultvalue)

returnresult

varslice=[]int123457

funcmain()

odd=filter(sliceisOdd)

even=filter(sliceisEven)

fmtPrintln(slice=slice)

fmtPrintln(Oddelementsofsliceareodd)

fmtPrintln(Evenelementsofsliceareeven)

Controlstatementsandfunctions

50

ItsveryusefulwhenweuseinterfacesAsyoucanseetestIntisavariablethathasafunctionastypeandthereturnedvaluesandargumentsoffilterarethesameasthoseoftestIntThereforewecanhavecomplexlogicinourprogramswhilemaintainingflexibilityinourcode

PanicandRecover

Godoesnthavetry-catchstructurelikeJavadoesInsteadofthrowingexceptionsGousespanicandrecovertodealwitherrorsHoweveryoushouldntusepanicverymuchalthoughitspowerful

Panicisabuilt-infunctiontobreakthenormalflowofprogramsandgetintopanicstatusWhenafunctionFcallspanicFwillnotcontinueexecutingbutitsdeferfunctionswillcontinuetoexecuteThenFgoesbacktothebreakpointwhichcausedthepanicstatusTheprogramwillnotterminateuntilallofthesefunctionsreturnwithpanictothefirstlevelofthatgoroutinepaniccanbeproducedbycallingpanicintheprogramandsomeerrorsalsocausepaniclikearrayaccessoutofboundserrors

Recoverisabuilt-infunctiontorecovergoroutinesfrompanicstatusCallingrecoverindeferfunctionsisusefulbecausenormalfunctionswillnotbeexecutedwhentheprogramisinthepanicstatusItcatchespanicvaluesiftheprogramisinthepanicstatusanditgetsniliftheprogramisnotinpanicstatus

Thefollowingexampleshowshowtousepanic

varuser=osGetenv(USER)

funcinit()

ifuser==

panic(novaluefor$USER)

Thefollowingexampleshowshowtocheckpanic

functhrowsPanic(ffunc())(bbool)

deferfunc()

ifx=recover()x=nil

b=true

()

f()iffcausespanicitwillrecover

return

mainfunctionandinitfunction

GohastworetentionswhicharecalledmainandinitwhereinitcanbeusedinallpackagesandmaincanonlybeusedinthemainpackageThesetwofunctionsarenotabletohaveargumentsorreturnvaluesEventhoughwecanwritemanyinitfunctionsinonepackageIstronglyrecommendwritingonlyoneinitfunctionforeachpackage

Goprogramswillcallinit()andmain()automaticallysoyoudontneedtocallthembyyourselfForeverypackagetheinitfunctionisoptionalbutpackagemainhasoneandonlyonemainfunction

ProgramsinitializeandbeginexecutionfromthemainpackageIfthemainpackageimportsotherpackagestheywillbeimportedinthecompiletimeIfonepackageisimportedmanytimesitwillbeonlycompiledonceAfterimportingpackagesprogramswillinitializetheconstantsandvariableswithintheimportedpackagesthenexecutetheinitfunctionifitexistsandsoonAfteralltheotherpackagesareinitializedprogramswillinitializeconstantsandvariablesinthemainpackagethenexecutetheinitfunctioninsidethepackageifitexistsThefollowingfigureshowstheprocess

Figure26FlowofprogramsinitializationinGo

Controlstatementsandfunctions

51

import

WeuseimportveryofteninGoprogramsasfollows

import(

fmt

)

Thenweusefunctionsinthatpackageasfollows

fmtPrintln(helloworld)

fmtisfromGostandardlibraryitislocatedwithin$GOROOTpkgGosupportsthird-partypackagesintwoways

1 RelativepathimportmodelloadpackageinthesamedirectoryIdontrecommendthisway2 Absolutepathimportshorturlmodelloadpackageinpath$GOPATHpkgshorturlmodel

Therearesomespecialoperatorswhenweimportpackagesandbeginnersarealwaysconfusedbytheseoperators

1 DotoperatorSometimeweseepeopleusefollowingwaytoimportpackages

import(

fmt

)

ThedotoperatormeansyoucanomitthepackagenamewhenyoucallfunctionsinsideofthatpackageNowfmtPrintf(Helloworld)becomestoPrintf(Helloworld)

2 AliasoperationItchangesthenameofthepackagethatweimportedwhenwecallfunctionsthatbelongtothatpackage

import(

ffmt

)

NowfmtPrintf(Helloworld)becomestofPrintf(Helloworld)3 _operatorThisistheoperatorthatisdifficulttounderstandwithoutsomeoneexplainingittoyou

import(

databasesql

_githubcomziutekmymysqlgodrv

)

The_operatoractuallymeanswejustwanttoimportthatpackageandexecuteitsinitfunctionandwearenotsureifwewanttousethefunctionsbelongingtothatpackage

LinksDirectoryPrevioussectionGofoundationNextsectionstruct

Controlstatementsandfunctions

52

24struct

structWecandefinenewtypesofcontainersofotherpropertiesorfieldsinGojustlikeinotherprogramminglanguagesForexamplewecancreateatypecalledpersontorepresentapersonwithfieldsnameandageWecallthiskindoftypeastruct

typepersonstruct

namestring

ageint

Lookhoweasyitistodefineastruct

Therearetwofields

nameisastringusedtostoreapersonsnameageisaintusedtostoreapersonsage

Letsseehowtouseit

typepersonstruct

namestring

ageint

varPpersonpispersontype

Pname=AstaxieassignAstaxietothefieldnameofp

Page=25assign25tofieldageofp

fmtPrintf(ThepersonsnameissnPname)accessfieldnameofp

Therearethreemorewaystoinitializeastruct

Assigninitialvaluesbyorder

P=personTom25

Usetheformatfieldvaluetoinitializethestructwithoutorder

P=personage24nameBob

Defineananonymousstructtheninitializeit

P=structnamestringageintAmy18

Letsseeacompleteexample

struct

53

packagemain

importfmt

defineanewtype

typepersonstruct

namestring

ageint

structispassedbyvalue

comparetheageoftwopeoplethenreturntheolderpersonanddifferencesofage

funcOlder(p1p2person)(personint)

ifp1agegtp2age

returnp1p1age-p2age

returnp2p2age-p1age

funcmain()

vartomperson

tomnametomage=Tom18

bob=personage25nameBob

paul=personPaul43

tb_Oldertb_diff=Older(tombob)

tp_Oldertp_diff=Older(tompaul)

bp_Olderbp_diff=Older(bobpaul)

fmtPrintf(Ofsandssisolderbydyearsntomnamebobnametb_Oldernametb_diff)

fmtPrintf(Ofsandssisolderbydyearsntomnamepaulnametp_Oldernametp_diff)

fmtPrintf(Ofsandssisolderbydyearsnbobnamepaulnamebp_Oldernamebp_diff)

embeddedfieldsinstructIvejustintroducedtoyouhowtodefineastructwithfieldnamesandtypeInfactGosupportsfieldswithoutnamesbutwithtypesWecalltheseembeddedfields

Whentheembeddedfieldisastructallthefieldsinthatstructwillimplicitlybethefieldsinthestructinwhichithasbeenembedded

Letsseeoneexample

struct

54

packagemain

importfmt

typeHumanstruct

namestring

ageint

weightint

typeStudentstruct

HumanembeddedfielditmeansStudentstructincludesallfieldsthatHumanhas

specialtystring

funcmain()

instantiateandinitializeastudent

mark=StudentHumanMark25120ComputerScience

accessfields

fmtPrintln(Hisnameismarkname)

fmtPrintln(Hisageismarkage)

fmtPrintln(Hisweightismarkweight)

fmtPrintln(Hisspecialtyismarkspecialty)

modifymarksspecialty

markspecialty=AI

fmtPrintln(Markchangedhisspecialty)

fmtPrintln(Hisspecialtyismarkspecialty)

fmtPrintln(MarkbecomeoldHeisnotanathleteanymore)

markage=46

markweight+=60

fmtPrintln(Hisageismarkage)

fmtPrintln(Hisweightismarkweight)

Figure27EmbeddinginStudentandHuman

WeseethatwecanaccesstheageandnamefieldsinStudentjustlikewecaninHumanThisishowembeddedfieldsworkItsverycoolisntitHoldontheressomethingcoolerYoucanevenuseStudenttoaccessHumaninthisembeddedfield

markHuman=HumanMarcus55220

markHumanage-=1

AllthetypesinGocanbeusedasembeddedfields

struct

55

packagemain

importfmt

typeSkills[]string

typeHumanstruct

namestring

ageint

weightint

typeStudentstruct

Humanstructasembeddedfield

Skillsstringsliceasembeddedfield

intbuilt-intypeasembeddedfield

specialtystring

funcmain()

initializeStudentJane

jane=StudentHumanHumanJane35100specialtyBiology

accessfields

fmtPrintln(Hernameisjanename)

fmtPrintln(Herageisjaneage)

fmtPrintln(Herweightisjaneweight)

fmtPrintln(Herspecialtyisjanespecialty)

modifyvalueofskillfield

janeSkills=[]stringanatomy

fmtPrintln(HerskillsarejaneSkills)

fmtPrintln(Sheacquiredtwonewones)

janeSkills=append(janeSkillsphysicsgolang)

fmtPrintln(HerskillsnowarejaneSkills)

modifyembeddedfield

janeint=3

fmtPrintln(Herpreferrednumberisjaneint)

Intheaboveexamplewecanseethatalltypescanbeembeddedfieldsandwecanusefunctionstooperateonthem

ThereisonemoreproblemhoweverIfHumanhasafieldcalledphoneandStudenthasafieldwithsamenamewhatshouldwedo

GouseaverysimplewaytosolveitTheouterfieldsgetupperaccesslevelswhichmeanswhenyouaccessstudentphonewewillgetthefieldcalledphoneinstudentnottheoneintheHumanstructThisfeaturecanbesimplyseenasfieldoverloading

struct

56

packagemain

importfmt

typeHumanstruct

namestring

ageint

phonestringHumanhasphonefield

typeEmployeestruct

Human

specialtystring

phonestringphoneinemployee

funcmain()

Bob=EmployeeHumanBob34777-444-XXXXDesigner333-222

fmtPrintln(BobsworkphoneisBobphone)

fmtPrintln(BobspersonalphoneisBobHumanphone)

LinksDirectoryPrevioussectionControlstatementsandfunctionsNextsectionObject-oriented

struct

57

Object-orientedWetalkedaboutfunctionsandstructsinthelasttwosectionsbutdidyoueverconsiderusingfunctionsasfieldsofastructInthissectionIwillintroduceyoutoanotherformoffunctionthathasareceiverwhichiscalledamethod

methodSupposeyoudefinearectanglestructandyouwanttocalculateitsareaWedtypicallyusethefollowingcodetoachievethisgoal

packagemain

importfmt

typeRectanglestruct

widthheightfloat64

funcarea(rRectangle)float64

returnrwidthrheight

funcmain()

r1=Rectangle122

r2=Rectangle94

fmtPrintln(Areaofr1isarea(r1))

fmtPrintln(Areaofr2isarea(r2))

TheaboveexamplecancalculatearectanglesareaWeusethefunctioncalledareabutitsnotamethodoftherectanglestruct(likeclassmethodsinclassicobject-orientedlanguages)Thefunctionandstructaretwoindependentthingsasyoumaynotice

ItsnotaproblemsofarHoweverifyoualsohavetocalculatetheareaofacirclesquarepentagonoranyotherkindofshapeyouaregoingtoneedtoaddadditionalfunctionswithverysimilarnames

Figure28Relationshipbetweenfunctionandstruct

ObviouslythatsnotcoolAlsotheareashouldreallybethepropertyofacircleorrectangle

ThisiswhereamethodcomestoplayThemethodisafunctionaffiliatedwithatypeIthassimilarsyntaxasfunctionexceptafterthefunckeywordhasaparametercalledthereceiverwhichisthemainbodyofthatmethod

UsingthesameexampleRectangleArea()belongsdirectlytorectangleinsteadofasaperipheralfunctionMorespecificallylengthwidthandArea()allbelongtorectangle

AsRobPikesaid

Amethodisafunctionwithanimplicitfirstargumentcalledareceiver

Syntaxofmethod

func(rReceiverType)funcName(parameters)(results)

Letschangeourexampleusingmethodinstead

Object-oriented

58

packagemain

import(

fmt

math

)

typeCirclestruct

radiusfloat64

typeRectanglestruct

widthheightfloat64

method

func(cCircle)Area()float64

returncradiuscradiusmathPi

method

func(rRectangle)Area()float64

returnrwidthrheight

funcmain()

c1=Circle10

c2=Circle25

r1=Rectangle94

r2=Rectangle122

fmtPrintln(Areaofc1isc1Area())

fmtPrintln(Areaofc2isc2Area())

fmtPrintln(Areaofr1isr1Area())

fmtPrintln(Areaofr2isr2Area())

Notesforusingmethods

IfthenameofmethodsarethesamebuttheydontsharethesamereceiverstheyarenotthesameMethodsareabletoaccessfieldswithinreceiversUsetocallamethodinthestructthesamewayfieldsarecalled

Figure29Methodsaredifferentindifferentstructs

IntheexampleabovetheArea()methodsbelongtobothRectangleandCirclerespectivelysothereceiversareRectangleandCircle

OnethingthatsworthnotingisthatthemethodwithadottedlinemeansthereceiverispassedbyvaluenotbyreferenceThedifferencebetweenthemisthatamethodcanchangeitsreceiversvalueswhenthereceiverispassedbyreferenceanditgetsacopyofthereceiverwhenthereceiverispassedbyvalue

CanthereceiveronlybeastructOfcoursenotAnytypecanbethereceiverofamethodYoumaybeconfusedaboutcustomizedtypesStructisaspecialkindofcustomizedtype-therearemorecustomizedtypes

Usethefollowingformattodefineacustomizedtype

typetypeNametypeLiteral

Examplesofcustomizedtypes

Object-oriented

59

typeageint

typemoneyfloat32

typemonthsmap[string]int

m=months

January31

February28

December31

IhopethatyouknowhowtousecustomizedtypesnowSimilartotypedefinCweuseagestosubstituteintintheaboveexample

Letsgetbacktotalkingaboutmethod

Youcanuseasmanymethodsincustomtypesasyouwant

packagemain

importfmt

const(

WHITE=iota

BLACK

BLUE

RED

YELLOW

)

typeBoxstruct

widthheightdepthfloat64

colorColor

typeColorbyte

typeBoxList[]Boxasliceofboxes

method

func(bBox)Volume()float64

returnbwidthbheightbdepth

methodwithapointerreceiver

func(bBox)SetColor(cColor)

bcolor=c

method

func(blBoxList)BiggestsColor()Color

v=000

k=Color(WHITE)

for_b=rangebl

ifbVolume()gtv

v=bVolume()

k=bcolor

returnk

method

func(blBoxList)PaintItBlack()

fori_=rangebl

bl[i]SetColor(BLACK)

method

func(cColor)String()string

Object-oriented

60

strings=[]stringWHITEBLACKBLUEREDYELLOW

returnstrings[c]

funcmain()

boxes=BoxList

Box444RED

Box10101YELLOW

Box1120BLACK

Box10101BLUE

Box10301WHITE

Box202020YELLOW

fmtPrintf(Wehavedboxesinoursetnlen(boxes))

fmtPrintln(Thevolumeofthefirstoneisboxes[0]Volume()cmsup3)

fmtPrintln(Thecolorofthelastoneisboxes[len(boxes)-1]colorString())

fmtPrintln(ThebiggestoneisboxesBiggestsColor()String())

Letspaintthemallblack

boxesPaintItBlack()

fmtPrintln(Thecolorofthesecondoneisboxes[1]colorString())

fmtPrintln(ObviouslynowthebiggestoneisboxesBiggestsColor()String())

Wedefinesomeconstantsandcustomizedtypes

UseColorasaliasofbyteDefineastructBoxwhichhasfieldsheightwidthlengthandcolorDefineastructBoxListwhichhasBoxasitsfield

Thenwedefinedsomemethodsforourcustomizedtypes

Volume()usesBoxasitsreceiverandreturnsthevolumeofBoxSetColor(cColor)changesBoxscolorBiggestsColor()returnsthecolorwhichhasthebiggestvolumePaintItBlack()setscolorforallBoxinBoxListtoblackString()useColorasitsreceiverreturnsthestringformatofcolorname

IsitmuchclearerwhenweusewordstodescribeourrequirementsWeoftenwriteourrequirementsbeforewestartcoding

Usepointerasreceiver

LetstakealookatSetColormethodItsreceiverisapointerofBoxYesyoucanuseBoxasareceiverWhydoweuseapointerhereBecausewewanttochangeBoxscolorinthismethodThusifwedontuseapointeritwillonlychangethevalueinsideacopyofBox

Ifweseethatareceiveristhefirstargumentofamethoditsnothardtounderstandhowitworks

Youmightbeaskingwhywearentusing(b)Color=cinsteadofbColor=cintheSetColor()methodEitheroneisOKherebecauseGoknowshowtointerprettheassignmentDoyouthinkGoismorefascinatingnow

Youmayalsobeaskingwhetherweshoulduse(ampbl[i])SetColor(BLACK)inPaintItBlackbecausewepassapointertoSetColorAgaineitheroneisOKbecauseGoknowshowtointerpretit

Inheritanceofmethod

WelearnedaboutinheritanceoffieldsinthelastsectionSimilarlywealsohavemethodinheritanceinGoIfananonymousfieldhasmethodsthenthestructthatcontainsthefieldwillhaveallthemethodsfromitaswell

Object-oriented

61

packagemain

importfmt

typeHumanstruct

namestring

ageint

phonestring

typeStudentstruct

Humananonymousfield

schoolstring

typeEmployeestruct

Human

companystring

defineamethodinHuman

func(hHuman)SayHi()

fmtPrintf(HiIamsyoucancallmeonsnhnamehphone)

funcmain()

sam=EmployeeHumanSam45111-888-XXXXGolangInc

mark=StudentHumanMark25222-222-YYYYMIT

samSayHi()

markSayHi()

MethodOverridingIfwewantEmployeetohaveitsownmethodSayHiwecandefineamethodthathasthesamenameinEmployeeanditwillhideSayHiinHumanwhenwecallit

Object-oriented

62

packagemain

importfmt

typeHumanstruct

namestring

ageint

phonestring

typeStudentstruct

Human

schoolstring

typeEmployeestruct

Human

companystring

func(hHuman)SayHi()

fmtPrintf(HiIamsyoucancallmeonsnhnamehphone)

func(eEmployee)SayHi()

fmtPrintf(HiIamsIworkatsCallmeonsnename

ecompanyephone)Yesyoucansplitinto2lineshere

funcmain()

sam=EmployeeHumanSam45111-888-XXXXGolangInc

mark=StudentHumanMark25222-222-YYYYMIT

samSayHi()

markSayHi()

YouareabletowriteanObject-orientedprogramnowandmethodsuseruleofcapitallettertodecidewhetherpublicorprivateaswell

LinksDirectoryPrevioussectionstructNextsectioninterface

Object-oriented

63

26Interface

InterfaceOneofthesubtlestdesignfeaturesinGoareinterfacesAfterreadingthissectionyouwilllikelybeimpressedbytheirimplementation

Whatisaninterface

Inshortaninterfaceisasetofmethodsthatweusetodefineasetofactions

LiketheexamplesinprevioussectionsbothStudentandEmployeecanSayHi()buttheydontdothesamething

LetsdosomemoreworkWelladdonemoremethodSing()tothemalongwiththeBorrowMoney()methodtoStudentandtheSpendSalary()methodtoEmployee

NowStudenthasthreemethodscalledSayHi()Sing()andBorrowMoney()andEmployeehasSayHi()Sing()andSpendSalary()

ThiscombinationofmethodsiscalledaninterfaceandisimplementedbybothStudentandEmployeeSoStudentandEmployeeimplementtheinterfaceSayHi()andSing()AtthesametimeEmployeedoesntimplementtheinterfaceBorrowMoney()andStudentdoesntimplementtheinterfaceSpendSalary()ThisisbecauseEmployeedoesnthavethemethodBorrowMoney()andStudentdoesnthavethemethodSpendSalary()

TypeofInterfaceAninterfacedefinesasetofmethodssoifatypeimplementsallthemethodswesaythatitimplementstheinterface

interface

64

typeHumanstruct

namestring

ageint

phonestring

typeStudentstruct

Human

schoolstring

loanfloat32

typeEmployeestruct

Human

companystring

moneyfloat32

defineinterfaces

typeMeninterface

SayHi()

Sing(lyricsstring)

Guzzle(beerSteinstring)

typeYoungChapinterface

SayHi()

Sing(songstring)

BorrowMoney(amountfloat32)

typeElderlyGentinterface

SayHi()

Sing(songstring)

SpendSalary(amountfloat32)

func(hHuman)SayHi()

fmtPrintf(HiIamsyoucancallmeonsnhnamehphone)

func(hHuman)Sing(lyricsstring)

fmtPrintln(Lalalalalalalalalalalyrics)

func(hHuman)Guzzle(beerSteinstring)

fmtPrintln(GuzzleGuzzleGuzzlebeerStein)

EmployeeoverloadsSayHi

func(eEmployee)SayHi()

fmtPrintf(HiIamsIworkatsCallmeonsnename

ecompanyephone)Yesyoucansplitinto2lineshere

func(sStudent)BorrowMoney(amountfloat32)

sloan+=amount(againandagainand)

func(eEmployee)SpendSalary(amountfloat32)

emoney-=amountMorevodkapleaseGetmethroughtheday

Weknowthataninterfacecanbeimplementedbyanytypeandonetypecanimplementmanyinterfacessimultaneously

Notethatanytypeimplementstheemptyinterfaceinterfacebecauseitdoesnthaveanymethodsandalltypeshavezeromethodsbydefault

Valueofinterface

interface

65

SowhatkindofvaluescanbeputintheinterfaceIfwedefineavariableasatypeinterfaceanytypethatimplementstheinterfacecanassignedtothisvariable

LiketheaboveexampleifwedefineavariablemasinterfaceMenthenanyoneofStudentHumanorEmployeecanbeassignedtomSowecouldhaveasliceofMenandanytypethatimplementsinterfaceMencanassigntothissliceBeawarehoweverthatthesliceofinterfacedoesnthavethesamebehaviorasasliceofothertypes

packagemain

importfmt

typeHumanstruct

namestring

ageint

phonestring

typeStudentstruct

Human

schoolstring

loanfloat32

typeEmployeestruct

Human

companystring

moneyfloat32

InterfaceMenimplementedbyHumanStudentandEmployee

typeMeninterface

SayHi()

Sing(lyricsstring)

method

func(hHuman)SayHi()

fmtPrintf(HiIamsyoucancallmeonsnhnamehphone)

method

func(hHuman)Sing(lyricsstring)

fmtPrintln(Lalalalalyrics)

method

func(eEmployee)SayHi()

fmtPrintf(HiIamsIworkatsCallmeonsnename

ecompanyephone)Yesyoucansplitinto2lineshere

funcmain()

mike=StudentHumanMike25222-222-XXXMIT000

paul=StudentHumanPaul26111-222-XXXHarvard100

sam=EmployeeHumanSam36444-222-XXXGolangInc1000

tom=EmployeeHumanSam36444-222-XXXThingsLtd5000

defineinterfacei

variMen

icanstoreStudent

i=mike

fmtPrintln(ThisisMikeaStudent)

iSayHi()

iSing(Novemberrain)

icanstoreEmployee

i=tom

fmtPrintln(ThisisTomanEmployee)

iSayHi()

interface

66

iSing(Borntobewild)

sliceofMen

fmtPrintln(LetsuseasliceofMenandseewhathappens)

x=make([]Men3)

thesethreeelementsaredifferenttypesbuttheyallimplementedinterfaceMen

x[0]x[1]x[2]=paulsammike

for_value=rangex

valueSayHi()

Aninterfaceisasetofabstractmethodsandcanbeimplementedbynon-interfacetypesItcannotthereforeimplementitself

Emptyinterface

AnemptyinterfaceisaninterfacethatdoesntcontainanymethodssoalltypesimplementanemptyinterfaceThisfactisveryusefulwhenwewanttostorealltypesatsomepointandissimilartovoidinC

defineaasemptyinterface

varvoidinterface

vars

i=5

s=Helloworld

acanstorevalueofanytype

void=i

void=s

Ifafunctionusesanemptyinterfaceasitsargumenttypeitcanacceptanytypeifafunctionusesemptyinterfaceasitsreturnvaluetypeitcanreturnanytype

Methodargumentsofaninterface

AnyvariablecanbeusedinaninterfaceSohowcanweusethisfeaturetopassanytypeofvariabletoafunction

ForexampleweusefmtPrintlnalotbuthaveyouevernoticedthatitcanacceptanytypeofargumentLookingattheopensourcecodeoffmtweseethefollowingdefinition

typeStringerinterface

String()string

ThismeansanytypethatimplementsinterfaceStringercanbepassedtofmtPrintlnasanargumentLetsproveit

interface

67

packagemain

import(

fmt

strconv

)

typeHumanstruct

namestring

ageint

phonestring

HumanimplementsfmtStringer

func(hHuman)String()string

returnName+hname+Age+strconvItoa(hage)+yearsContact+hphone

funcmain()

Bob=HumanBob39000-7777-XXX

fmtPrintln(ThisHumanisBob)

LookingbacktotheexampleofBoxyouwillfindthatColorimplementsinterfaceStringeraswellsoweareabletocustomizetheprintformatIfwedontimplementthisinterfacefmtPrintlnprintsthetypewithitsdefaultformat

fmtPrintln(ThebiggestoneisboxesBiggestsColor()String())

fmtPrintln(ThebiggestoneisboxesBiggestsColor())

AttentionIfthetypeimplementedtheinterfaceerrorfmtwillcallError()soyoudonthavetoimplementStringeratthispoint

TypeofvariableinaninterfaceIfavariableisthetypethatimplementsaninterfaceweknowthatanyothertypethatimplementsthesameinterfacecanbeassignedtothisvariableThequestionishowcanweknowthespecifictypestoredintheinterfaceTherearetwowayswhichIwillshowyou

AssertionofComma-okpattern

Gohasthesyntaxvalueok=element(T)ThischeckstoseeifthevariableisthetypethatweexpectwherevalueisthevalueofthevariableokisavariableofbooleantypeelementistheinterfacevariableandtheTisthetypeofassertion

Iftheelementisthetypethatweexpectokwillbetruefalseotherwise

Letsuseanexampletoseemoreclearly

interface

68

packagemain

import(

fmt

strconv

)

typeElementinterface

typeList[]Element

typePersonstruct

namestring

ageint

func(pPerson)String()string

return(name+pname+-age+strconvItoa(page)+years)

funcmain()

list=make(List3)

list[0]=1anint

list[1]=Helloastring

list[2]=PersonDennis70

forindexelement=rangelist

ifvalueok=element(int)ok

fmtPrintf(list[d]isanintanditsvalueisdnindexvalue)

elseifvalueok=element(string)ok

fmtPrintf(list[d]isastringanditsvalueissnindexvalue)

elseifvalueok=element(Person)ok

fmtPrintf(list[d]isaPersonanditsvalueissnindexvalue)

else

fmtPrintf(list[d]isofadifferenttypenindex)

Itsquiteeasytousethispatternbutifwehavemanytypestotestwedbetteruseswitch

switchtest

Letsuseswitchtorewritetheaboveexample

interface

69

packagemain

import(

fmt

strconv

)

typeElementinterface

typeList[]Element

typePersonstruct

namestring

ageint

func(pPerson)String()string

return(name+pname+-age+strconvItoa(page)+years)

funcmain()

list=make(List3)

list[0]=1anint

list[1]=Helloastring

list[2]=PersonDennis70

forindexelement=rangelist

switchvalue=element(type)

caseint

fmtPrintf(list[d]isanintanditsvalueisdnindexvalue)

casestring

fmtPrintf(list[d]isastringanditsvalueissnindexvalue)

casePerson

fmtPrintf(list[d]isaPersonanditsvalueissnindexvalue)

default

fmtPrintln(list[d]isofadifferenttypeindex)

Onethingyoushouldrememberisthatelement(type)cannotbeusedoutsideoftheswitchbodywhichmeansinthatcaseyouhavetousethecomma-okpattern

Embeddedinterfaces

ThemostbeautifulthingisthatGohasalotofbuilt-inlogicsyntaxsuchasanonymousfieldsinstructNotsuprisinglywecanuseinterfacesasanonymousfieldsaswellbutwecallthemEmbeddedinterfacesHerewefollowthesamerulesasanonymousfieldsMorespecificallyifaninterfacehasanotherinterfaceembeddedwithinititwillbehaveasifithasallthemethodsthattheembeddedinterfacehas

Wecanseethatthesourcefileincontainerheaphasthefollowingdefinition

typeInterfaceinterface

sortInterfaceembeddedsortInterface

Push(xinterface)aPushmethodtopushelementsintotheheap

Pop()interfaceaPopmethodthatpopselementsfromtheheap

WeseethatsortInterfaceisanembeddedinterfacesotheaboveInterfacehasthethreemethodscontainedwithinthesortInterfaceimplicitly

interface

70

typeInterfaceinterface

Lenisthenumberofelementsinthecollection

Len()int

Lessreturnswhethertheelementwithindexishouldsort

beforetheelementwithindexj

Less(ijint)bool

Swapswapstheelementswithindexesiandj

Swap(ijint)

AnotherexampleistheioReadWriterinpackageio

ioReadWriter

typeReadWriterinterface

Reader

Writer

Reflection

ReflectioninGoisusedfordetermininginformationatruntimeWeusethereflectpackageandTheLawsofReflectionpostexplainshowreflectworksinGo

TherearethreestepsinvolvedwhenusingreflectFirstweneedtoconvertaninterfacetoreflecttypes(reflectTypeorreflectValuethisdependsonthesituation)

t=reflectTypeOf(i)getmeta-dataintypeiandusettogetallelements

v=reflectValueOf(i)getactualvalueintypeiandusevtochangeitsvalue

Afterthatwecanconvertthereflectedtypestogetthevaluesthatweneed

varxfloat64=34

t=reflectTypeOf(x)

v=reflectValueOf(x)

fmtPrintln(typet)

fmtPrintln(valuev)

fmtPrintln(kindisfloat64vKind()==reflectFloat64)

FinallyifwewanttochangethevaluesofthereflectedtypesweneedtomakeitmodifiableAsdiscussedearlierthereisadifferencebetweenpassbyvalueandpassbyreferenceThefollowingcodewillnotcompile

varxfloat64=34

v=reflectValueOf(x)

vSetFloat(71)

Insteadwemustusethefollowingcodetochangethevaluesfromreflecttypes

varxfloat64=34

p=reflectValueOf(ampx)

v=pElem()

vSetFloat(71)

Wehavejustdiscussedthebasicsofreflectionhoweveryoumustpracticemoreinordertounderstandmore

Links

interface

71

DirectoryPrevioussectionObject-orientedNextsectionConcurrency

interface

72

ConcurrencyItissaidthatGoistheCofthe21stcenturyIthinktherearetworeasonsforitFirstGoisasimplelanguageSecondconcurrencyisahottopicintodaysworldandGosupportsthisfeatureatthelanguagelevel

goroutinegoroutinesandconcurrencyarebuiltintothecoredesignofGoTheyresimilartothreadsbutworkdifferentlyGoalsogivesyoufullsupporttosharingmemoryinyourgoroutinesOnegoroutineusuallyuses4~5KBofstackmemoryThereforeitsnothardtorunthousandsofgoroutinesonasinglecomputerAgoroutineismorelightweightmoreefficientandmoreconvenientthansystemthreads

goroutinesrunonthethreadmanageratruntimeinGoWeusethegokeywordtocreateanewgoroutinewhichisafunctionattheunderlyinglevel(main()isagoroutine)

gohello(abc)

Letsseeanexample

packagemain

import(

fmt

runtime

)

funcsay(sstring)

fori=0ilt5i++

runtimeGosched()

fmtPrintln(s)

funcmain()

gosay(world)createanewgoroutine

say(hello)currentgoroutine

Output

hello

world

hello

world

hello

world

hello

world

hello

WeseethatitsveryeasytouseconcurrencyinGobyusingthekeywordgoIntheaboveexamplethesetwogoroutinessharesomememorybutwewouldbetterofffollowingthedesignrecipeDontuseshareddatatocommunicateusecommunicationtosharedata

runtimeGosched()meanslettheCPUexecuteothergoroutinesandcomebackatsomepoint

InGo15theruntimenowsetsthedefaultnumberofthreadstorunsimultaneouslydefinedbyGOMAXPROCStothenumberofcoresavailableontheCPU

Concurrency

73

BeforeGo15ThescheduleronlyusesonethreadtorunallgoroutineswhichmeansitonlyimplementsconcurrencyIfyouwanttousemoreCPUcoresinordertotakeadvantageofparallelprocessingyouhavetocallruntimeGOMAXPROCS(n)tosetthenumberofcoresyouwanttouseIfnlt1itchangesnothing

channelsgoroutinesruninthesamememoryaddressspacesoyouhavetomaintainsynchronizationwhenyouwanttoaccesssharedmemoryHowdoyoucommunicatebetweendifferentgoroutinesGousesaverygoodcommunicationmechanismcalledchannelAchannelisliketwo-waypipelineinUnixshellsusechanneltosendorreceivedataTheonlydatatypethatcanbeusedinchannelsisthetypechannelandthekeywordchanBeawarethatyouhavetousemaketocreateanewchannel

ci=make(chanint)

cs=make(chanstring)

cf=make(chaninterface)

channelusestheoperatorlt-tosendorreceivedata

chlt-vsendvtochannelch

v=lt-chreceivedatafromchandassigntov

Letsseemoreexamples

packagemain

importfmt

funcsum(a[]intcchanint)

total=0

for_v=rangea

total+=v

clt-totalsendtotaltoc

funcmain()

a=[]int728-940

c=make(chanint)

gosum(a[len(a)2]c)

gosum(a[len(a)2]c)

xy=lt-clt-creceivefromc

fmtPrintln(xyx+y)

SendingandreceivingdatainchannelsblocksbydefaultsoitsmucheasiertousesynchronousgoroutinesWhatImeanbyblockisthatagoroutinewillnotcontinuewhenreceivingdatafromanemptychannelie(value=lt-ch)untilothergoroutinessenddatatothischannelOntheotherhandthegoroutinewillnotcontinueuntilthedataitsendstoachannelie(chlt-5)isreceived

BufferedchannelsIintroducednon-bufferedchannelsaboveGoalsohasbufferedchannelsthatcanstoremorethanasingleelementForexamplech=make(chanbool4)herewecreateachannelthatcanstore4booleanelementsSointhischannelweareabletosend4elementsintoitwithoutblockingbutthegoroutinewillbeblockedwhenyoutrytosendafifthelementandnogoroutinereceivesit

Concurrency

74

ch=make(chantypen)

n==0non-buffer(block)

ngt0buffer(non-blockuntilnelementsinthechannel)

Youcantrythefollowingcodeonyourcomputerandchangesomevalues

packagemain

importfmt

funcmain()

c=make(chanint2)change2to1willhaveruntimeerrorbut3isfine

clt-1

clt-2

fmtPrintln(lt-c)

fmtPrintln(lt-c)

RangeandCloseWecanuserangetooperateonbufferchannelsasinsliceandmap

packagemain

import(

fmt

)

funcfibonacci(nintcchanint)

xy=11

fori=0iltni++

clt-x

xy=yx+y

close(c)

funcmain()

c=make(chanint10)

gofibonacci(cap(c)c)

fori=rangec

fmtPrintln(i)

fori=rangecwillnotstopreadingdatafromchanneluntilthechannelisclosedWeusethekeywordclosetoclosethechannelinaboveexampleItsimpossibletosendorreceivedataonaclosedchannelyoucanusevok=lt-chtotestifachannelisclosedIfokreturnsfalseitmeansthethereisnodatainthatchannelanditwasclosed

Remembertoalwaysclosechannelsinproducersandnotinconsumersoritsveryeasytogetintopanicstatus

AnotherthingyouneedtorememberisthatchannelsarenotlikefilesYoudonthavetoclosethemfrequentlyunlessyouaresurethechanneliscompletelyuselessoryouwanttoexitrangeloops

SelectIntheaboveexamplesweonlyuseonechannelbuthowcanwedealwithmorethanonechannelGohasakeywordcalledselecttolistentomanychannels

Concurrency

75

selectisblockingbydefaultanditcontinuestoexecuteonlywhenoneofchannelshasdatatosendorreceiveIfseveralchannelsarereadytouseatthesametimeselectchooseswhichtoexecuterandomly

packagemain

importfmt

funcfibonacci(cquitchanint)

xy=11

for

select

caseclt-x

xy=yx+y

caselt-quit

fmtPrintln(quit)

return

funcmain()

c=make(chanint)

quit=make(chanint)

gofunc()

fori=0ilt10i++

fmtPrintln(lt-c)

quitlt-0

()

fibonacci(cquit)

selecthasadefaultcaseaswelljustlikeswitchWhenallthechannelsarenotreadyforuseitexecutesthedefaultcase(itdoesntwaitforthechannelanymore)

select

casei=lt-c

usei

default

executesherewhencisblocked

TimeoutSometimesagoroutinebecomesblockedHowcanweavoidthistopreventthewholeprogramfromblockingItssimplewecansetatimeoutintheselect

funcmain()

c=make(chanint)

o=make(chanbool)

gofunc()

for

select

casev=lt-c

println(v)

caselt-timeAfter(5timeSecond)

println(timeout)

olt-true

break

()

lt-o

Concurrency

76

RuntimegoroutineThepackageruntimehassomefunctionsfordealingwithgoroutines

runtimeGoexit()

Exitsthecurrentgoroutinebutdeferedfunctionswillbeexecutedasusual

runtimeGosched()

Letstheschedulerexecuteothergoroutinesandcomesbackatsomepoint

runtimeNumCPU()int

ReturnsthenumberofCPUcores

runtimeNumGoroutine()int

Returnsthenumberofgoroutines

runtimeGOMAXPROCS(nint)int

SetshowmanyCPUcoresyouwanttouse

LinksDirectoryPrevioussectioninterfaceNextsectionSummary

Concurrency

77

28SummaryInthischapterwemainlyintroducedthe25GokeywordsLetsreviewwhattheyareandwhattheydo

breakdefaultfuncinterfaceselect

casedefergomapstruct

chanelsegotopackageswitch

constfallthroughifrangetype

continueforimportreturnvar

varandconstareusedtodefinevariablesandconstantspackageandimportareforpackageusefuncisusedtodefinefunctionsandmethodsreturnisusedtoreturnvaluesinfunctionsormethodsdeferisusedtodefinedeferfunctionsgoisusedtostartanewgoroutineselectisusedtoswitchovermultiplechannelsforcommunicationinterfaceisusedtodefineinterfacesstructisusedtodefinespecialcustomizedtypesbreakcasecontinueforfallthroughelseifswitchgotoanddefaultwereintroducedinsection23chanisthetypeofchannelforcommunicationamonggoroutinestypeisusedtodefinecustomizedtypesmapisusedtodefinemapwhichissimilartohashtablesinotherlanguagesrangeisusedforreadingdatafromslicemapandchannel

Ifyouunderstandhowtousethese25keywordsyouvelearnedalotofGoalready

LinksDirectoryPrevioussectionConcurrencyNextchapterWebfoundation

Summary

78

3WebfoundationThereasonyouarereadingthisbookisthatyouwanttolearntobuildwebapplicationsinGoAsIvesaidbeforeGoprovidesmanypowerfulpackageslikehttpThesepackagescanhelpyoualotwhentryingtobuildwebapplicationsIllteachyoueverythingyouneedtoknowinthefollowingchaptersandwelltalkaboutsomeconceptsofthewebandhowtorunwebapplicationsinGointhischapter

LinksDirectoryPreviouschapterChapter2SummaryNextsectionWebworkingprinciples

Webfoundation

79

WebworkingprinciplesEverytimeyouopenyourbrowserstypesomeURLsandpressenteryouwillseebeautifulwebpagesappearonyourscreenButdoyouknowwhatishappeningbehindthesesimpleactions

NormallyyourbrowserisaclientAfteryoutypeaURLittakesthehostpartoftheURLandsendsittoaDomainNameServer(DNS)inordertogettheIPaddressofthehostThenitconnectstotheIPaddressandaskstosetupaTCPconnectionThebrowsersendsHTTPrequeststhroughtheconnectionTheserverhandlesthemandreplieswithHTTPresponsescontainingthecontentthatmakeupthewebpageFinallythebrowserrendersthebodyofthewebpageanddisconnectsfromtheserver

Figure31Processesofusersvisitawebsite

AwebserveralsoknownasanHTTPserverusestheHTTPprotocoltocommunicatewithclientsAllwebbrowserscanbeconsideredclients

Wecandividethewebsworkingprinciplesintothefollowingsteps

ClientusesTCPIPprotocoltoconnecttoserverClientsendsHTTPrequestpackagestoserverServerreturnsHTTPresponsepackagestoclientIftherequestedresourcesincludedynamicscriptsservercallsscriptenginefirstClientdisconnectsfromserverstartsrenderingHTML

ThisisasimpleworkflowofHTTPaffairs-noticethattheserverclosesitsconnectionsafteritsendsdatatotheclientsthenwaitsforthenextrequest

URLandDNSresolutionWealwaysuseURLstoaccesswebpagesbutdoyouknowhowURLswork

ThefullnameofaURLisUniformResourceLocatorItsfordescribingresourcesontheinternetanditsbasicformisasfollows

schemehost[port]path[query-string][anchor]

schemeassignunderlyingprotocol(suchasHTTPHTTPSFTP)

hostIPordomainnameofHTTPserver

portdefaultportis80anditcanbeomittedinthiscase

IfyouwanttouseotherportsyoumustspecifywhichportForexample

httpwwwcnblogscom8080

pathresourcespath

query-stringdataaresenttoserver

anchoranchor

DNSisanabbreviationofDomainNameSystemItsthenamingsystemforcomputernetworkservicesanditconvertsdomainnamestoactualIPaddressesjustlikeatranslator

Figure32DNSworkingprinciples

TounderstandmoreaboutitsworkingprincipleletsseethedetailedDNSresolutionprocessasfollows

1 AftertypingthedomainnamewwwqqcominthebrowsertheoperatingsystemwillcheckifthereareanymappingrelationshipsinthehostsfilesforthisdomainnameIfsothenthedomainnameresolutioniscomplete

2 IfnomappingrelationshipsexistinthehostsfilestheoperatingsystemwillcheckifanycacheexistsintheDNSIfso

Webworkingprinciples

80

thenthedomainnameresolutioniscomplete3 IfnomappingrelationshipsexistinboththehostandDNScachetheoperatingsystemfindsthefirstDNSresolution

serverinyourTCPIPsettingswhichislikelyyourlocalDNSserverWhenthelocalDNSserverreceivesthequeryifthedomainnamethatyouwanttoqueryiscontainedwithinthelocalconfigurationofitsregionalresourcesitreturnstheresultstotheclientThisDNSresolutionisauthoritative

4 IfthelocalDNSserverdoesntcontainthedomainnamebutamappingrelationshipexistsinthecachethelocalDNSservergivesbackthisresulttotheclientThisDNSresolutionisnotauthoritative

5 IfthelocalDNSservercannotresolvethisdomainnameeitherbyconfigurationofregionalresourcesorcacheitwillproceedtothenextstepwhichdependsonthelocalDNSserverssettings-IfthelocalDNSserverdoesntenableforwardingitroutestherequesttotherootDNSserverthenreturnstheIPaddressofatoplevelDNSserverwhichmayknowthedomainnamecominthiscaseIfthefirsttoplevelDNSserverdoesntrecognizethedomainnameitagainreroutestherequesttothenexttoplevelDNSserveruntilitreachesonethatrecognizesthedomainnameThenthetoplevelDNSserverasksthisnextlevelDNSserverfortheIPaddresscorrespondingtowwwqqcom-IfthelocalDNSserverhasforwardingenableditsendstherequesttoanupperlevelDNSserverIftheupperlevelDNSserveralsodoesntrecognizethedomainnamethentherequestkeepsgettingreroutedtohigherlevelsuntilitfinallyreachesaDNSserverwhichrecognizesthedomainname

WhetherornotthelocalDNSserverenablesforwardingtheIPaddressofthedomainnamealwaysreturnstothelocalDNSserverandthelocalDNSserversendsitbacktotheclient

Figure33DNSresolutionworkflow

RecursivequeryprocesssimplymeansthattheenquirerschangeintheprocessEnquirersdonotchangeinIterativequeryprocesses

NowweknowclientsgetIPaddressesintheendsothebrowsersarecommunicatingwithserversthroughIPaddresses

HTTPprotocolTheHTTPprotocolisacorepartofwebservicesItsimportanttoknowwhattheHTTPprotocolisbeforeyouunderstandhowthewebworks

HTTPistheprotocolthatisusedtofacilitatecommunicationbetweenbrowserandwebserverItisbasedontheTCPprotocolandusuallyusesport80onthesideofthewebserverItisaprotocolthatutilizestherequest-responsemodel-clientssendrequestsandserversrespondAccordingtotheHTTPprotocolclientsalwayssetupnewconnectionsandsendHTTPrequeststoserversServersarenotabletoconnecttoclientsproactivelyorestablishcallbackconnectionsTheconnectionbetweenaclientandaservercanbeclosedbyeithersideForexampleyoucancancelyourdownloadrequestandHTTPconnectionandyourbrowserwilldisconnectfromtheserverbeforeyoufinishdownloading

TheHTTPprotocolisstatelesswhichmeanstheserverhasnoideaabouttherelationshipbetweenthetwoconnectionseventhoughtheyarebothfromsameclientTosolvethisproblemwebapplicationsusecookiestomaintainthestateofconnections

BecausetheHTTPprotocolisbasedontheTCPprotocolallTCPattackswillaffectHTTPcommunicationsinyourserverExamplesofsuchattacksareSYNfloodingDoSandDDoSattacks

HTTPrequestpackage(browserinformation)

RequestpackagesallhavethreepartsrequestlinerequestheaderandbodyThereisoneblanklinebetweenheaderandbody

Webworkingprinciples

81

GETdomainsexampleHTTP11requestlinerequestmethodURLprotocolanditsversion

Hostwwwianaorgdomainname

User-AgentMozilla50(WindowsNT61)AppleWebKit5374(KHTMLlikeGecko)Chrome220122994Safari5374

browserinformation

Accepttexthtmlapplicationxhtml+xmlapplicationxmlq=09q=08mimethatclientscanaccept

Accept-Encodinggzipdeflatesdchstreamcompression

Accept-CharsetUTF-8q=05charactersetinclientside

blankline

bodyrequestresourcearguments(forexampleargumentsinPOST)

Weusefiddlertogetthefollowingrequestinformation

Figure34InformationofaGETrequestcaughtbyfiddler

Figure35InformationofaPOSTrequestcaughtbyfiddler

WecanseethatGETdoesnothavearequestbodyunlikePOSTwhichdoes

TherearemanymethodsyoucanusetocommunicatewithserversinHTTPGETPOSTPUTandDELETEarethe4basicmethodsthatwetypicallyuseAURLrepresentsaresourceonanetworksothese4methodsdefinethequerychangeaddanddeleteoperationsthatcanactontheseresourcesGETandPOSTareverycommonlyusedinHTTPGETcanappendqueryparameterstotheURLusingtoseparatetheURLandparametersandampbetweentheargumentslikeEditPostsaspxname=test1ampid=123456POSTputsdataintherequestbodybecausetheURLimplementsalengthlimitationviathebrowserThusPOSTcansubmitmuchmoredatathanGETAlsowhenwesubmitusernamesandpasswordswedontwantthiskindofinformationtoappearintheURLsoweusePOSTtokeeptheminvisible

HTTPresponsepackage(serverinformation)Letsseewhatinformationiscontainedintheresponsepackages

HTTP11200OKstatusline

Servernginx108webserversoftwareanditsversionintheservermachine

DateDateTue30Oct2012041425GMTrespondedtime

Content-Typetexthtmlrespondeddatatype

Transfer-Encodingchunkeditmeansdataweresentinfragments

Connectionkeep-alivekeepconnection

Content-Length90lengthofbody

blankline

ltDOCTYPEhtmlPUBLIC-W3CDTDXHTML10TransitionalENmessagebody

ThefirstlineiscalledthestatuslineItsuppliestheHTTPversionstatuscodeandstatusmessage

ThestatuscodeinformstheclientofthestatusoftheHTTPserversresponseInHTTP115kindsofstatuscodesweredefined

-1xxInformational

-2xxSuccess

-3xxRedirection

-4xxClientError

-5xxServerError

Letsseemoreexamplesaboutresponsepackages200meansserverrespondedcorrectly302meansredirection

Figure36Fullinformationforvisitingawebsite

HTTPisstatelessandConnectionkeep-alive

Webworkingprinciples

82

ThetermstatelessdoesntmeanthattheserverhasnoabilitytokeepaconnectionItsimplymeansthattheserverdoesntrecognizeanyrelationshipsbetweenanytworequests

InHTTP11Keep-aliveisusedbydefaultIfclientshaveadditionalrequeststheywillusethesameconnectionforthem

NoticethatKeep-alivecannotmaintainoneconnectionforevertheapplicationrunningintheserverdeterminesthelimitwithwhichtokeeptheconnectionaliveforandinmostcasesyoucanconfigurethislimit

Requestinstance

Figure37Allpackagesforopeningonewebpage

WecanseetheentirecommunicationprocessbetweenclientandserverfromtheabovepictureYoumaynoticethattherearemanyresourcefilesinthelistthesearecalledstaticfilesandGohasspecializedprocessingmethodsforthesefiles

ThisisthemostimportantfunctionofbrowserstorequestforaURLandretrievedatafromwebserversthenrendertheHTMLIfitfindssomefilesintheDOMsuchasCSSorJSfilesbrowserswillrequesttheseresourcesfromtheserveragainuntilalltheresourcesfinishrenderingonyourscreen

ReducingHTTPrequesttimesisonewayofimprovingtheloadingspeedofwebpagesByreducingthenumberofCSSandJSfilesthatneedtobeloadedbothrequestlatenciesandpressureonyourwebserverscanbereducedatthesametime

LinksDirectoryPrevioussectionWebfoundationNextsectionBuildasimplewebserver

Webworkingprinciples

83

32BuildasimplewebserverWevediscussedthatwebapplicationsarebasedontheHTTPprotocolandGoprovidesfullHTTPsupportinthenethttppackageItsveryeasytosetawebserverupusingthispackage

Usehttppackagesetupawebserver

packagemain

import(

fmt

nethttp

strings

log

)

funcsayhelloName(whttpResponseWriterrhttpRequest)

rParseForm()parseargumentsyouhavetocallthisbyyourself

fmtPrintln(rForm)printforminformationinserverside

fmtPrintln(pathrURLPath)

fmtPrintln(schemerURLScheme)

fmtPrintln(rForm[url_long])

forkv=rangerForm

fmtPrintln(keyk)

fmtPrintln(valstringsJoin(v))

fmtFprintf(wHelloastaxie)senddatatoclientside

funcmain()

httpHandleFunc(sayhelloName)setrouter

err=httpListenAndServe(9090nil)setlistenport

iferr=nil

logFatal(ListenAndServeerr)

Afterweexecutetheabovecodetheserverbeginslisteningtoport9090inlocalhost

Openyourbrowserandvisithttplocalhost9090YoucanseethatHelloastaxieisonyourscreen

Letstryanotheraddresswithadditionalargumentshttplocalhost9090url_long=111ampurl_long=222

Nowletsseewhathappensonboththeclientandserversides

Youshouldseethefollowinginformationontheserverside

Figure38Serverprintedinformation

Asyoucanseeweonlyneedtocalltwofunctionsinordertobuildasimplewebserver

IfyouareworkingwithPHPyoureprobablyaskingwhetherornotweneedsomethinglikeNginxorApacheTheansweriswedontsinceGolistenstotheTCPportbyitselfandthefunctionsayhelloNameisthelogicfunctionjustlikeacontrollerinPHP

IfyouareworkingwithPythonyoushouldknowtornadoandtheaboveexampleisverysimilartothat

IfyouareworkingwithRubyyoumaynoticeitislikescriptserverinROR(RubyonRails)

Buildasimplewebserver

84

WeusedtwosimplefunctionstosetupasimplewebserverinthissectionandthissimpleserveralreadyhasthecapacityforhighconcurrencyoperationsWewilltalkabouthowtoutilizethisinthenexttwosections

LinksDirectoryPrevioussectionWebworkingprinciplesNextsectionHowGoworkswithweb

Buildasimplewebserver

85

33HowGoworkswithwebWelearnedtousethenethttppackagetobuildasimplewebserverintheprevioussectionandallthoseworkingprinciplesarethesameasthosewewilltalkaboutinthefirstsectionofthischapter

ConceptsinwebprinciplesRequestrequestdatafromusersincludingPOSTGETCookieandURL

Responseresponsedatafromservertoclients

Connconnectionsbetweenclientsandservers

HandlerRequesthandlinglogicandresponsegeneration

httppackageoperatingmechanismThefollowingpictureshowstheworkflowofaGowebserver

Figure39httpworkflow

1 Createalisteningsocketlistentoaportandwaitforclients2 Acceptrequestsfromclients3 HandlerequestsreadHTTPheaderIftherequestusesPOSTmethodreaddatainthemessagebodyandpassthem

tohandlersFinallysocketreturnsresponsedatatoclients

OnceweknowtheanswerstothethreefollowingquestionsitseasytoknowhowthewebworksinGo

HowdowelistentoaportHowdoweacceptclientrequestsHowdoweallocatehandlers

IntheprevioussectionwesawthatGousesListenAndServetohandlethesestepsinitializeaserverobjectcallnetListen(tcpaddr)tosetupaTCPlistenerandlistentoaspecificaddressandport

Letstakealookatthehttppackagessourcecode

HowGoworkswithweb

86

Buildversiongo112

func(srvServer)Serve(lnetListener)error

deferlClose()

vartempDelaytimeDurationhowlongtosleeponacceptfailure

for

rwe=lAccept()

ife=nil

ifneok=e(netError)okampampneTemporary()

iftempDelay==0

tempDelay=5timeMillisecond

else

tempDelay=2

ifmax=1timeSecondtempDelaygtmax

tempDelay=max

logPrintf(httpAccepterrorvretryinginvetempDelay)

timeSleep(tempDelay)

continue

returne

tempDelay=0

cerr=srvnewConn(rw)

iferr=nil

continue

gocserve()

HowdoweacceptclientrequestsafterwebeginlisteningtoaportInthesourcecodewecanseethatsrvServe(netListener)iscalledtohandleclientrequestsInthebodyofthefunctionthereisaforItacceptsarequestcreatesanewconnectionthenstartsanewgoroutinepassingtherequestdatatothegocserve()goroutineThisishowGosupportshighconcurrencyandeverygoroutineisindependent

HowdoweusespecificfunctionstohandlerequestsconnparsesrequestcReadRequest()atfirstthengetsthecorrespondinghandlerhandler=shsrvHandlerwhichisthesecondargumentwepassedwhenwecalledListenAndServeBecausewepassednilGousesitsdefaulthandlerhandler=DefaultServeMuxSowhatisDefaultServeMuxdoinghereWellitstheroutervariablewhichcancallhandlerfunctionsforspecificURLsDidwesetthisYeswedidWedidthisinthefirstlinewhereweusedhttpHandleFunc(sayhelloName)WereusingthisfunctiontoregistertherouterruleforthepathWhentheURListheroutercallsthefunctionsayhelloNameDefaultServeMuxcallsServerHTTPtogethandlerfunctionsfordifferentpathscallingsayhelloNameinthisspecificcaseFinallytheserverwritesdataandrespondstoclients

Detailedworkflow

Figure310WorkflowofhandlinganHTTPrequest

IthinkyoushouldknowhowGorunswebserversnow

LinksDirectoryPrevioussectionBuildasimplewebserverNextsectionGetintohttppackage

HowGoworkswithweb

87

HowGoworkswithweb

88

34GetintohttppackageInprevioussectionswelearnedabouttheworkflowofthewebandtalkedalittlebitaboutGoshttppackageInthissectionwearegoingtolearnabouttwocorefunctionsinthehttppackageConnandServeMux

goroutineinConnUnlikenormalHTTPserversGousesgoroutinesforeveryjobinitiatedbyConninordertoachievehighconcurrencyandperformancesoeveryjobisindependent

Gousesthefollowingcodetowaitfornewconnectionsfromclients

cerr=srvnewConn(rw)

iferr=nil

continue

gocserve()

Asyoucanseeitcreatesanewgoroutineforeveryconnectionandpassesthehandlerthatisabletoreaddatafromtherequesttothegoroutine

CustomizedServeMuxWeusedGosdefaultrouterinprevioussectionswhendiscussingconnserverwiththerouterpassingrequestdatatoaback-endhandler

Thestructofthedefaultrouter

typeServeMuxstruct

musyncRWMutexbecauseofconcurrencywehavetouseamutexhere

mmap[string]muxEntryrouterruleseverystringmappingtoahandler

ThestructofmuxEntry

typemuxEntrystruct

explicitboolexactmatchornot

hHandler

TheinterfaceofHandler

typeHandlerinterface

ServeHTTP(ResponseWriterRequest)routingimplementer

HandlerisaninterfacebutifthefunctionsayhelloNamedidntimplementthisinterfacethenhowdidweadditashandlerTheanswerliesinanothertypecalledHandlerFuncinthehttppackageWecalledHandlerFunctodefineoursayhelloNamemethodsosayhelloNameimplementedHandleratthesametimeItslikewerecallingHandlerFunc(f)andthefunctionfisforceconvertedtotypeHandlerFunc

Getintohttppackage

89

typeHandlerFuncfunc(ResponseWriterRequest)

ServeHTTPcallsf(wr)

func(fHandlerFunc)ServeHTTP(wResponseWriterrRequest)

f(wr)

Howdoestheroutercallhandlersafterwesettherouterrules

TheroutercallsmuxhandlerServeHTTP(wr)whenitreceivesrequestsInotherwordsitcallstheServeHTTPinterfaceofthehandlerswhichhaveimplementedit

Nowletsseehowmuxhandlerworks

func(muxServeMux)handler(rRequest)Handler

muxmuRLock()

defermuxmuRUnlock()

Host-specificpatterntakesprecedenceovergenericones

h=muxmatch(rHost+rURLPath)

ifh==nil

h=muxmatch(rURLPath)

ifh==nil

h=NotFoundHandler()

returnh

TherouterusestherequestsURLasakeytofindthecorrespondinghandlersavedinthemapthencallshandlerServeHTTPtoexecutefunctionstohandlethedata

YoushouldunderstandthedefaultroutersworkflowbynowandGoactuallysupportscustomizedroutersThesecondargumentofListenAndServeisforconfiguringcustomizedroutersItsaninterfaceofHandlerThereforeanyrouterthatimplementstheHandlerinterfacecanbeused

Thefollowingexampleshowshowtoimplementasimplerouter

packagemain

import(

fmt

nethttp

)

typeMyMuxstruct

func(pMyMux)ServeHTTP(whttpResponseWriterrhttpRequest)

ifrURLPath==

sayhelloName(wr)

return

httpNotFound(wr)

return

funcsayhelloName(whttpResponseWriterrhttpRequest)

fmtFprintf(wHellomyroute)

funcmain()

mux=ampMyMux

httpListenAndServe(9090mux)

Getintohttppackage

90

RoutingIfyoudonotwanttouseaRouteryoucanstillachievewhatwewroteintheabovesectionbyreplacingthesecondargumenttoListenAndServetonilandregisteringtheURLsusingaHandleFuncfunctionwhichgoesthroughalltheregisteredURLstofindthebestmatchsocaremustbetakenabouttheorderoftheregistering

samplecode

httpHandleFunc(viewsShowAllTasksFunc)

httpHandleFunc(completeviewsCompleteTaskFunc)

httpHandleFunc(deleteviewsDeleteTaskFunc)

ShowAllTasksFuncisusedtohandletheURLwhichisthedefaultons

TODOaddhttp404error

funcShowAllTasksFunc(whttpResponseWriterrhttpRequest)

ifrMethod==GET

context=dbGetTasks(pending)truewhenyouwantnondeletedtasks

dbisapackagewhichinteractswiththedatabase

ifmessage=

contextMessage=message

homeTemplateExecute(wcontext)

message=

else

message=Methodnotallowed

httpRedirect(wrhttpStatusFound)

ThisisfineforsimpleapplicationswhichdoesntrequiresparameterizedroutingwhatwhenyouneedthatYoucaneitherusetheexistingtoolkitsorframeworksbutsincethisbookisaboutwritingwebappsingolangwearegoingtoteachhowtohandlethisscenarioaswell

WhenthematchismadeontheHandleFuncfunctiontheURLismatchedsosupposewearewritingatodolistmanagerandwewanttodeleteatasksotheURLwedecideforthatapplicationisdelete1soweregisterthedeleteURLlikethishttpHandleFunc(deleteviewsDeleteTaskFunc)delete1thisURLmatchesclosestwiththedeleteURLthananyotherURLsointherURLpathwegettheentireURLoftherequest

httpHandleFunc(deleteviewsDeleteTaskFunc)

DeleteTaskFuncisusedtodeleteatasktrash=movetorecyclebindelete=permanentdelete

funcDeleteTaskFunc(whttpResponseWriterrhttpRequest)

ifrMethod==DELETE

id=rURLPath[len(delete)]

ifid==all

dbDeleteAll()

httpRedirect(wrhttpStatusFound)

else

iderr=strconvAtoi(id)

iferr=nil

fmtPrintln(err)

else

err=dbDeleteTask(id)

iferr=nil

message=Errordeletingtask

else

message=Taskdeleted

httpRedirect(wrhttpStatusFound)

else

message=Methodnotallowed

httpRedirect(wrhttpStatusFound)

Getintohttppackage

91

linkhttpsgithubcomthewhitetulipTasksblobmasterviewsviewsgoL170-L195

InthisabovemethodwhatwebasicallydoisinthefunctionwhichhandlesthedeleteURLwetakeitscompeleteURLwhichisdelete1thenwetakeasliceofthestringandextracteverythingwhichstartsafterthedeletewordwhichistheactualparameterinthiscaseitis1ThenweusethestrconvpackagetoconvertittoanintegeranddeletethetaskwiththattaskID

InmorecomplexscenariostoowecanusethismethodtheadvantageisthatwedonthavetouseanythirdpartytoolkitbutthenagainthirdpartytoolkitsareusefulintheirownrightyouneedtomakeadecisionwhichmethodyoudpreferNoansweristherightanswer

GocodeexecutionflowLetstakealookatthewholeexecutionflow

CallhttpHandleFunc1 CallHandleFuncofDefaultServeMux2 CallHandleofDefaultServeMux3 Addrouterrulestomap[string]muxEntryofDefaultServeMux

CallhttpListenAndServe(9090nil)1 InstantiateServer2 CallListenAndServemethodofServer3 CallnetListen(tcpaddr)tolistentoport4 Startaloopandacceptrequestsintheloopbody5 InstantiateaConnandstartagoroutineforeveryrequestgocserve()6 Readrequestdatawerr=creadRequest()7 CheckwhetherhandlerisemptyornotifitsemptythenuseDefaultServeMux8 CallServeHTTPofhandler9 ExecutecodeinDefaultServeMuxinthiscase10 ChoosehandlerbyURLandexecutecodeinthathandlerfunctionmuxhandlerServeHTTP(wr)11 HowtochoosehandlerACheckrouterrulesforthisURLBCallServeHTTPinthathandlerifthereisoneCCall

ServeHTTPofNotFoundHandlerotherwise

LinksDirectoryPrevioussectionHowGoworkswithwebNextsectionSummary

Getintohttppackage

92

35SummaryInthischapterweintroducedHTTPDNSresolutionflowandhowtobuildasimplewebserverThenwetalkedabouthowGoimplementswebserversforusbylookingatthesourcecodeofthenethttppackage

IhopethatyounowknowmuchmoreaboutwebdevelopmentandyoushouldseethatitsquiteeasyandflexibletobuildawebapplicationinGo

LinksDirectoryPrevioussectionGetintohttppackageNextchapterUserform

Summary

93

4UserformAuserformissomethingthatisverycommonlyusedwhendevelopingwebapplicationsItprovidestheabilitytocommunicatebetweenclientsandserversYoumustbeveryfamiliarwithformsifyouareawebdeveloperifyouareaCC++programmeryoumaywanttoaskwhatisauserform

AformisanareathatcontainsformelementsUserscaninputinformationintoformelementsliketextboxesdropdownlistsradiobuttonscheckboxesetcWeusetheformtagltformgttodefineforms

ltformgt

inputelements

ltformgt

GoalreadyhasmanyconvenientfunctionstodealwithuserformsYoucaneasilygetformdatainHTTPrequestsandtheyareeasytointegrateintoyourownwebapplicationsInsection41wearegoingtotalkabouthowtohandleformdatainGoAlsosinceyoucannottrustanydatacomingfromtheclientsideyoumustfirstvalidatethedatabeforeusingitWellgothroughsomeexamplesabouthowtovalidateformdatainsection42

WesaythatHTTPisstatelessHowcanweidentifythatcertainformsarefromthesameuserAndhowdowemakesurethatoneformcanonlybesubmittedonceWelllookatsomedetailsconcerningcookies(acookieisinformationthatcanbesavedontheclientsideandaddedtotherequestheaderwhentherequestissenttotheserver)inbothsections43and44

Anothercommonuse-caseforformsisuploadingfilesInsection45youwilllearnhowtodothisaswellascontrollingthefileuploadsizebeforeitbeginsuploadinginGo

LinksDirectoryPreviouschapterChapter3SummaryNextsectionProcessforminputs

HTTPForm

94

41ProcessforminputsBeforewebeginletstakealookatasimpleexampleofatypicaluserformsavedaslogingtplinyourprojectfolder

lthtmlgt

ltheadgt

lttitlegtlttitlegt

ltheadgt

ltbodygt

ltformaction=loginmethod=postgt

Usernameltinputtype=textname=usernamegt

Passwordltinputtype=passwordname=passwordgt

ltinputtype=submitvalue=Logingt

ltformgt

ltbodygt

lthtmlgt

ThisformwillsubmittologinontheserverAftertheuserclickstheloginbuttonthedatawillbesenttotheloginhandlerregisteredbytheserverrouterThenweneedtoknowwhetheritusesthePOSTmethodorGET

ThisiseasytofindoutusingthehttppackageLetsseehowtohandletheformdataontheloginpage

Processforminputs

95

packagemain

import(

fmt

htmltemplate

log

nethttp

strings

)

funcsayhelloName(whttpResponseWriterrhttpRequest)

rParseForm()ParseurlparameterspassedthenparsetheresponsepacketforthePOSTbody(requestbody)

attentionIfyoudonotcallParseFormmethodthefollowingdatacannotbeobtainedform

fmtPrintln(rForm)printinformationonserverside

fmtPrintln(pathrURLPath)

fmtPrintln(schemerURLScheme)

fmtPrintln(rForm[url_long])

forkv=rangerForm

fmtPrintln(keyk)

fmtPrintln(valstringsJoin(v))

fmtFprintf(wHelloastaxie)writedatatoresponse

funclogin(whttpResponseWriterrhttpRequest)

fmtPrintln(methodrMethod)getrequestmethod

ifrMethod==GET

t_=templateParseFiles(logingtpl)

tExecute(wnil)

else

rParseForm()

logicpartoflogin

fmtPrintln(usernamerForm[username])

fmtPrintln(passwordrForm[password])

funcmain()

httpHandleFunc(sayhelloName)settingrouterrule

httpHandleFunc(loginlogin)

err=httpListenAndServe(9090nil)settinglisteningport

iferr=nil

logFatal(ListenAndServeerr)

HereweuserMethodtogettherequestmethodanditreturnsanhttpverb-GETPOSTPUTetc

IntheloginfunctionweuserMethodtocheckwhetheritsaloginpageorloginprocessinglogicInotherwordswechecktoseewhethertheuserissimplyopeningthepageortryingtologinServeshowsthepageonlywhentherequestcomesinviatheGETmethodanditexecutestheloginlogicwhentherequestusesthePOSTmethod

Youshouldseethefollowinginterfaceafteropeninghttp1270019090logininyourbrowser

Figure41Userlogininterface

TheserverwillnotprintanythinguntilafterwetypeinausernameandpasswordbecausethehandlerdoesntparsetheformuntilwecallrParseForm()LetsaddrParseForm()beforefmtPrintln(usernamerForm[username])compileourprogramandtestitagainYouwillfindthattheinformationisprintedontheserversidenow

rFormcontainsalloftherequestargumentsforinstancethequery-stringintheURLandthedatainPOSTandPUTIfthedatahasconflictsforexampleparametersthathavethesamenametheserverwillsavethedataintoaslicewithmultiplevaluesTheGodocumentationstatesthatGowillsavethedatafromGETandPOSTrequestsindifferentplaces

Processforminputs

96

Trychangingthevalueoftheactionintheformhttp1270019090logintohttp1270019090loginusername=astaxieinthelogingtplfiletestitagainandyouwillseethatthesliceisprintedontheserverside

Figure42Serverprintsrequestdata

ThetypeofrequestFormisurlValueItsavesdatawiththeformatkey=value

v=urlValues

vSet(nameAva)

vAdd(friendJess)

vAdd(friendSarah)

vAdd(friendZoe)

vEncode()==name=Avaampfriend=Jessampfriend=Sarahampfriend=Zoe

fmtPrintln(vGet(name))

fmtPrintln(vGet(friend))

fmtPrintln(v[friend])

TipsRequestshavetheabilitytoaccessformdatausingtheFormValue()methodForexampleyoucanchangerForm[username]torFormValue(username)andGocallsrParseFormautomaticallyNoticethatitreturnsthefirstvalueifthereareargumentswiththesamenameanditreturnsanemptystringifthereisnosuchargument

LinksDirectoryPrevioussectionUserformNextsectionVerificationofinputs

Processforminputs

97

42VerificationofinputsOneofthemostimportantprinciplesinwebdevelopmentisthatyoucannottrustanythingfromclientsideuserformsYouhavetovalidateallincomingdatabeforeuseitManywebsitesareaffectedbythisproblemwhichissimpleyetcrucial

TherearetwowaysofverifyingformdatathatareincommonuseThefirstisJavaScriptvalidationonthefront-endandthesecondisservervalidationontheback-endInthissectionwearegoingtotalkaboutserversidevalidationinwebdevelopment

RequiredfieldsSometimeswerequirethatusersinputsomefieldsbuttheyfailtocompletethefieldForexampleintheprevioussectionwhenwerequiredausernameYoucanusethelenfunctiontogetthelengthofafieldinordertoensurethatusershaveenteredsomething

iflen(rForm[username][0])==0

codeforemptyfield

rFormtreatsdifferentformelementtypesdifferentlywhentheyareblankForemptytextboxestextareasandfileuploadsitreturnsanemptystringforradiobuttonsandcheckboxesitdoesntevencreatethecorrespondingitemsInsteadyouwillgeterrorsifyoutrytoaccessitThereforeitssafertouserFormGet()togetfieldvaluessinceitwillalwaysreturnemptyifthevaluedoesnotexistOntheotherhandrFormGet()canonlygetonefieldvalueatatimesoyouneedtouserFormtogetthemapofvalues

NumbersSometimesyourequirenumbersratherthanothertextforthefieldvalueForexampleletssaythatyourequiretheageofauserinintegerformonlyie50or10insteadofoldenoughoryoungmanIfwerequireapositivenumberwecanconvertthevaluetotheinttypefirstthenprocessit

getinterr=strconvAtoi(rFormGet(age))

iferr=nil

erroroccurswhenconverttonumberitmaynotanumber

checkrangeofnumber

ifgetintgt100

toobig

Anotherwaytodothisisbyusingregularexpressions

ifm_=regexpMatchString(^[0-9]+$rFormGet(age))m

returnfalse

ForhighperformancepurposesregularexpressionsarenotefficienthoweversimpleregularexpressionsareusuallyfastenoughIfyouarefamiliarwithregularexpressionsitsaveryconvenientwaytoverifydataNoticethatGousesRE2soallUTF-8charactersaresupported

Chinese

Validationofinputs

98

SometimesweneeduserstoinputtheirChinesenamesandwehavetoverifythattheyalluseChineseratherthanrandomcharactersForChineseverificationregularexpressionsaretheonlyway

ifm_=regexpMatchString(^[x4e00-x9fa5]+$rFormGet(realname))m

returnfalse

EnglishlettersSometimesweneeduserstoinputonlyEnglishlettersForexamplewerequiresomeonesEnglishnamelikeastaxieinsteadofasta谢Wecaneasilyuseregularexpressionstoperformourverification

ifm_=regexpMatchString(^[a-zA-Z]+$rFormGet(engname))m

returnfalse

E-mailaddressIfyouwanttoknowwhetherusershaveenteredvalidE-mailaddressesyoucanusethefollowingregularexpression

ifm_=regexpMatchString(`^([w_]210)(w1)([a-z]24)$`rFormGet(email))m

fmtPrintln(no)

else

fmtPrintln(yes)

DropdownlistLetssaywerequireanitemfromourdropdownlistbutinsteadwegetavaluefabricatedbyhackersHowdowepreventthisfromhappening

Supposewehavethefollowingltselectgt

ltselectname=fruitgt

ltoptionvalue=applegtappleltoptiongt

ltoptionvalue=peargtpearltoptiongt

ltoptionvalue=bananagtbananaltoptiongt

ltselectgt

Wecanusethefollowingstrategytosanitizeourinput

slice=[]stringapplepearbanana

for_v=rangeslice

ifv==rFormGet(fruit)

returntrue

returnfalse

AllthefunctionsIveshownaboveareinmyopensourceprojectforoperatingonslicesandmapshttpsgithubcomastaxiebeeku

Radiobuttons

Validationofinputs

99

Ifwewanttoknowwhethertheuserismaleorfemalewemayusearadiobuttonreturning1formaleand2forfemaleHoweversomelittlekidwhojustreadhisfirstbookonHTTPdecidestosendtoyoua3WillyourprogramthrowanexceptionAsyoucanseeweneedtousethesamemethodaswedidforourdropdownlisttomakesurethatonlyexpectedvaluesarereturnedbyourradiobutton

ltinputtype=radioname=gendervalue=1gtMale

ltinputtype=radioname=gendervalue=2gtFemale

Andweusethefollowingcodetovalidatetheinput

slice=[]int12

for_v=rangeslice

ifv==rFormGet(gender)

returntrue

returnfalse

CheckboxesSupposetherearesomecheckboxesforuserinterestsandthatyoudontwantextraneousvalueshereeitherYoucanvalidatetheseasefollows

ltinputtype=checkboxname=interestvalue=footballgtFootball

ltinputtype=checkboxname=interestvalue=basketballgtBasketball

ltinputtype=checkboxname=interestvalue=tennisgtTennis

Inthiscasethesanitizationisalittlebitdifferenttovalidatingthebuttonandcheckboxinputssinceherewegetaslicefromthecheckboxes

slice=[]stringfootballbasketballtennis

a=Slice_diff(rForm[interest]slice)

ifa==nil

returntrue

returnfalse

DateandtimeSupposeyouwantuserstoinputvaliddatesortimesGohasthetimepackageforconvertingyearmonthanddaytotheircorrespondingtimesAfterthatitseasytocheckit

t=timeDate(2009timeNovember1023000timeUTC)

fmtPrintf(GolaunchedatsntLocal())

Afteryouhavethetimeyoucanusethetimepackageformoreoperationsdependingonyourneeds

InthissectionwevediscussedsomecommonmethodsofvalidatingformdataontheserversideIhopethatyounowunderstandmoreaboutdatavalidationinGoespeciallyhowtouseregularexpressionstoyouradvantage

LinksDirectory

Validationofinputs

100

PrevioussectionProcessforminputsNextsectionCrosssitescripting

Validationofinputs

101

43CrosssitescriptingTodayswebsiteshavemuchmoredynamiccontentinordertoimproveuserexperiencewhichmeansthatwemustprovidedynamicinformationdependingoneveryindividualsbehaviorUnfortunatelydynamicwebsitesaresusceptibletomaliciousattacksknownasCrosssitescripting(knownasXSS)StaticwebsitesarenotsusceptibletoCrosssitescripting

AttackersofteninjectmaliciousscriptslikeJavaScriptVBScriptActiveXorFlashintothosewebsitesthathaveloopholesOncetheyhavesuccessfullyinjectedtheirscriptsuserinformationcanbestolenandyourwebsitecanbefloodedwithspamTheattackerscanalsochangeusersettingstowhatevertheywant

Ifyouwishtopreventthiskindofattackyoushouldcombinethefollowingtwoapproaches

ValidationofalldatafromuserswhichwetalkedaboutintheprevioussectionCarefullyhandledatathatwillbesenttoclientsinordertopreventanyinjectedscriptsfromrunningonbrowsers

SohowcanwedothesetwothingsinGoFortunatelythehtmltemplatepackagehassomeusefulfunctionstoescapedataasfollows

funcHTMLEscape(wioWriterb[]byte)escapesbtowfuncHTMLEscapeString(sstring)stringreturnsastringafterescapingfromsfuncHTMLEscaper(argsinterface)stringreturnsastringafterescapingfrommultiplearguments

Letschangetheexampleinsection41

fmtPrintln(usernametemplateHTMLEscapeString(rFormGet(username)))printatserverside

fmtPrintln(passwordtemplateHTMLEscapeString(rFormGet(password)))

templateHTMLEscape(w[]byte(rFormGet(username)))respondedtoclients

Ifsomeonetriestoinputtheusernameasltscriptgtalert()ltscriptgtwewillseethefollowingcontentinthebrowser

Figure43JavaScriptafterescaped

FunctionsinthehtmltemplatepackagehelpyoutoescapeallHTMLtagsWhatifyoujustwanttoprintltscriptgtalert()ltscriptgttobrowsersYoushouldusetexttemplateinstead

importtexttemplate

terr=templateNew(foo)Parse(`defineTHelloend`)

err=tExecuteTemplate(outTltscriptgtalert(youhavebeenpwned)ltscriptgt)

Output

Helloltscriptgtalert(youhavebeenpwned)ltscriptgt

OryoucanusethetemplateHTMLtypeVariablecontentwillnotbeescapedifitstypeistemplateHTML

importhtmltemplate

terr=templateNew(foo)Parse(`defineTHelloend`)

err=tExecuteTemplate(outTtemplateHTML(ltscriptgtalert(youhavebeenpwned)ltscriptgt))

Output

Helloltscriptgtalert(youhavebeenpwned)ltscriptgt

Crosssitescripting

102

Onemoreexampleofescaping

importhtmltemplate

terr=templateNew(foo)Parse(`defineTHelloend`)

err=tExecuteTemplate(outTltscriptgtalert(youhavebeenpwned)ltscriptgt)

Output

Helloampltscriptampgtalert(amp39youhavebeenpwnedamp39)ampltscriptampgt

LinksDirectoryPrevioussectionVerificationofinputsNextsectionDuplicatesubmissions

Crosssitescripting

103

44DuplicatesubmissionsIdontknowifyouveeverseensomeblogsorBBSthathavemorethanonepostthatareexactlythesamebutIcantellyouthatitsbecauseuserssubmittedduplicatepostformsTherearemanythingsthatcancauseduplicatesubmissionssometimesusersjustdoubleclickthesubmitbuttonortheywanttomodifysomecontentafterpostingandpressthebackbuttonInsomecasesitisbytheintentionalactionsofmalicioususersItseasytoseehowduplicatesubmissionscanleadtomanyproblemsThuswehavetouseeffectivemeanstopreventit

ThesolutionistoaddahiddenfieldwithauniquetokentoyourformandtoalwayscheckthistokenbeforeprocessingtheincomingdataAlsoifyouareusingAjaxtosubmitaformuseJavaScripttodisablethesubmitbuttononcetheformhasbeensubmitted

Letsimprovetheexamplefromsection42

ltinputtype=checkboxname=interestvalue=footballgtFootball

ltinputtype=checkboxname=interestvalue=basketballgtBasketball

ltinputtype=checkboxname=interestvalue=tennisgtTennis

Usernameltinputtype=textname=usernamegt

Passwordltinputtype=passwordname=passwordgt

ltinputtype=hiddenname=tokenvalue=gt

ltinputtype=submitvalue=Logingt

WeuseanMD5hash(timestamp)togeneratethetokenandaddedittobothahiddenfieldontheclientsideformandasessioncookieontheserverside(Chapter6)Wecanthenusethistokentocheckwhetherornotthisformwassubmitted

funclogin(whttpResponseWriterrhttpRequest)

fmtPrintln(methodrMethod)getrequestmethod

ifrMethod==GET

crutime=timeNow()Unix()

h=md5New()

ioWriteString(hstrconvFormatInt(crutime10))

token=fmtSprintf(xhSum(nil))

t_=templateParseFiles(logingtpl)

tExecute(wtoken)

else

loginrequest

rParseForm()

token=rFormGet(token)

iftoken=

checktokenvalidity

else

giveerrorifnotoken

fmtPrintln(usernamelengthlen(rForm[username][0]))

fmtPrintln(usernametemplateHTMLEscapeString(rFormGet(username)))printinserverside

fmtPrintln(passwordtemplateHTMLEscapeString(rFormGet(password)))

templateHTMLEscape(w[]byte(rFormGet(username)))respondtoclient

Figure44Thecontentinbrowserafteraddingatoken

YoucanrefreshthispageandyouwillseeadifferenttokeneverytimeThisensuresthateveryformisunique

FornowyoucanpreventmanyduplicatesubmissionattacksbyaddingtokenstoyourformsbutitcannotpreventalldeceptiveattacksofthistypeThereismuchmoreworkthatneedstobedone

Duplicatesubmissions

104

LinksDirectoryPrevioussectionCrosssitescriptingNextsectionFileupload

Duplicatesubmissions

105

45FileuploadSupposeyouhaveawebsitelikeInstagramandyouwantuserstouploadtheirbeautifulphotosHowwouldyouimplementthatfunctionality

YouhavetoaddpropertyenctypetotheformthatyouwanttouseforuploadingphotosTherearethreepossiblevaluesforthisproperty

applicationx-www-form-urlencodedTranscodeallcharactersbeforeuploading(default)

multipartform-dataNotranscodingYoumustusethisvaluewhenyourformhasfileuploadcontrols

textplainConvertspacesto+butnotranscodingforspecialcharacters

ThereforetheHTMLcontentofafileuploadformshouldlooklikethis

lthtmlgt

ltheadgt

lttitlegtUploadfilelttitlegt

ltheadgt

ltbodygt

ltformenctype=multipartform-dataaction=http1270019090uploadmethod=postgt

ltinputtype=filename=uploadfilegt

ltinputtype=hiddenname=tokenvalue=gt

ltinputtype=submitvalue=uploadgt

ltformgt

ltbodygt

lthtmlgt

Weneedtoaddafunctionontheserversidetohandlethisform

httpHandleFunc(uploadupload)

uploadlogic

funcupload(whttpResponseWriterrhttpRequest)

fmtPrintln(methodrMethod)

ifrMethod==GET

crutime=timeNow()Unix()

h=md5New()

ioWriteString(hstrconvFormatInt(crutime10))

token=fmtSprintf(xhSum(nil))

t_=templateParseFiles(uploadgtpl)

tExecute(wtoken)

else

rParseMultipartForm(32ltlt20)

filehandlererr=rFormFile(uploadfile)

iferr=nil

fmtPrintln(err)

return

deferfileClose()

fmtFprintf(wvhandlerHeader)

ferr=osOpenFile(test+handlerFilenameosO_WRONLY|osO_CREATE0666)

iferr=nil

fmtPrintln(err)

return

deferfClose()

ioCopy(ffile)

Fileupload

106

AsyoucanseeweneedtocallrParseMultipartFormforuploadingfilesThefunctionParseMultipartFormtakesthemaxMemoryargumentAfteryoucallParseMultipartFormthefilewillbesavedintheservermemorywithmaxMemorysizeIfthefilesizeislargerthanmaxMemorytherestofthedatawillbesavedinasystemtemporaryfileYoucanuserFormFiletogetthefilehandleanduseioCopytosavetoyourfilesystem

YoudontneedtocallrParseFormwhenyouaccessothernon-filefieldsintheformbecauseGowillcallitwhenitsnecessaryAlsocallingParseMultipartFormonceisenough-multiplecallsmakenodifference

Weusethreestepsforuploadingfilesasfollows

1 Addenctype=multipartform-datatoyourform2 CallrParseMultipartFormontheserversidetosavethefileeithertomemoryortoatemporaryfile3 CallrFormFiletogetthefilehandleandsavetothefilesystem

ThefilehandleristhemultipartFileHeaderItusesthefollowingstruct

typeFileHeaderstruct

Filenamestring

HeadertextprotoMIMEHeader

containsfilteredorunexportedfields

Figure45Printinformationonserverafterreceivingfile

ClientsuploadfilesIshowedanexampleofusingaformtoauploadafileWecanimpersonateaclientformtouploadfilesinGoaswell

Fileupload

107

packagemain

import(

bytes

fmt

io

ioioutil

mimemultipart

nethttp

os

)

funcpostFile(filenamestringtargetUrlstring)error

bodyBuf=ampbytesBuffer

bodyWriter=multipartNewWriter(bodyBuf)

thisstepisveryimportant

fileWritererr=bodyWriterCreateFormFile(uploadfilefilename)

iferr=nil

fmtPrintln(errorwritingtobuffer)

returnerr

openfilehandle

fherr=osOpen(filename)

iferr=nil

fmtPrintln(erroropeningfile)

returnerr

deferfhClose()

iocopy

_err=ioCopy(fileWriterfh)

iferr=nil

returnerr

contentType=bodyWriterFormDataContentType()

bodyWriterClose()

resperr=httpPost(targetUrlcontentTypebodyBuf)

iferr=nil

returnerr

deferrespBodyClose()

resp_bodyerr=ioutilReadAll(respBody)

iferr=nil

returnerr

fmtPrintln(respStatus)

fmtPrintln(string(resp_body))

returnnil

sampleusage

funcmain()

target_url=httplocalhost9090upload

filename=astaxiepdf

postFile(filenametarget_url)

TheaboveexampleshowsyouhowtouseaclienttouploadfilesItusesmultipartWritetowritefilesintocacheandsendsthemtotheserverthroughthePOSTmethod

IfyouhaveotherfieldsthatneedtowriteintodatalikeusernamecallmultipartWriteFieldasneeded

Links

Fileupload

108

DirectoryPrevioussectionDuplicatesubmissionsNextsectionSummary

Fileupload

109

46SummaryInthischapterwemainlylearnedhowtoprocessformdatainGothroughseveralexampleslikelogginginusersanduploadingfilesWealsoemphasizedthatvalidatinguserdataisextremelyimportantforwebsitesecurityandweusedonesectiontotalkabouthowtofilterdatawithregularexpressions

Ihopethatyounowknowmoreaboutthecommunicationprocessbetweenclientandserver

LinksDirectoryPrevioussectionFileuploadNextchapterDatabase

Summary

110

5DatabaseForwebdevelopersthedatabaseisatthecoreofwebdevelopmentYoucansavealmostanythingintoadatabaseandqueryorupdatedatainsideitlikeuserinformationproductsornewsarticles

GodoesntprovideanydatabasedriversbutitdoeshaveadriverinterfacedefinedinthedatabasesqlpackagePeoplecandevelopdatabasedriversbasedonthatinterfaceInsection51wearegoingtotalkaboutdatabasedriverinterfacedesigninGoInsections52to54IwillintroducesomeSQLdatabasedriverstoyouInsection55IwillpresenttheORM thatIhavedevelopedwhichisbasedonthedatabasesqlinterfacestandardItiscompatiblewithmostdriversthathaveimplementedthedatabasesqlinterfaceanditmakesiteasytoaccessdatabasesidiomaticallyinGo

NoSQLhasbeenahottopicinrecentyearsMorewebsitesaredecidingtouseNoSQLdatabasesastheirmaindatabaseinsteadofjustforthepurposeofcachingIwillintroduceyoutotwoNoSQLdatabaseswhichareMongoDBandRedisinsection56

LinksDirectoryPreviousChapterChapter4SummaryNextsectiondatabasesqlinterface

Database

111

51databasesqlinterfaceGodoesntprovideanyofficialdatabasedriversunlikeotherlanguageslikePHPwhichdoHoweveritdoeshavesomedatabasedriverinterfacestandardsfordeveloperstodevelopdatabasedriverswithTheadvantageisthatifyourcodeisdevelopedaccordingtotheseinterfacestandardsyouwillnotneedtochangeanycodeifyourdatabasechangesLetsseewhatthesedatabaseinterfacestandardsare

sqlRegisterThisfunctionisinthedatabasesqlpackageforregisteringdatabasedriverswhenyouusethird-partydatabasedriversAlloftheseshouldcalltheRegister(namestringdriverdriverDriver)functionininit()inordertoregisterthemselves

Letstakealookatthecorrespondingmymysqlandsqlite3drivercode

httpsgithubcommattngo-sqlite3driver

funcinit()

sqlRegister(sqlite3ampSQLiteDriver)

httpsgithubcommikespookmymysqldriver

Driverautomaticallyregisteredindatabasesql

vard=Driverprototcpraddr1270013306

funcinit()

Register(SETNAMESutf8)

sqlRegister(mymysqlampd)

Weseethatallthird-partydatabasedriversimplementthisfunctiontoregisterthemselvesandGousesamaptosaveuserdriversinsideofdatabasesql

vardrivers=make(map[string]driverDriver)

drivers[name]=driver

Thereforethisregistrationfunctioncanregisterasmanydriversasyoumayrequireeachwithdifferentnames

Wealwaysseethefollowingcodewhenweusethird-partydrivers

import(

databasesql

_githubcommattngo-sqlite3

)

Heretheunderscore(alsoknownasablank)_canbequiteconfusingformanybeginnersbutthisisagreatfeatureinGoWealreadyknowthatthisunderscoreidentifierisusedfordiscardingvaluesfromfunctionreturnsandalsothatyoumustuseallpackagesthatyouveimportedinyourcodeinGoSowhentheblankisusedwithimportitmeansthatyouneedtoexecutetheinit()functionofthatpackagewithoutdirectlyusingitwhichisaperfectfitfortheuse-caseofregisteringdatabasedrivers

driverDriverDriverisaninterfacecontaininganOpen(namestring)methodthatreturnsaConninterface

databasesqlinterface

112

typeDriverinterface

Open(namestring)(Connerror)

Thisisaone-timeConnwhichmeansitcanonlybeusedoncepergoroutineThefollowingcodewillcauseerrorstooccur

gogoroutineA(Conn)query

gogoroutineB(Conn)insert

BecauseGohasnoideawhichgoroutinedoeswhichoperationthequeryoperationmaygettheresultoftheinsertoperationandvice-versa

Allthird-partydriversshouldhavethisfunctiontoparsethenameofConnandreturnthecorrectresults

driverConnThisisadatabaseconnectioninterfacewithsomemethodsandasivesaidabovethesameConncanonlybeusedoncepergoroutine

typeConninterface

Prepare(querystring)(Stmterror)

Close()error

Begin()(Txerror)

PreparereturnsthepreparestatusofcorrespondingSQLcommandsforqueryinganddeletingetcCloseclosesthecurrentconnectionandcleansresourcesMostthird-partydriversimplementsomekindofconnectionpoolsoyoudontneedtocacheconnectionswhichcancauseunexpectederrorsBeginreturnsaTxthatrepresentsatransactionhandleYoucanuseitforqueryingupdatingrollingbacktransactionsetc

driverStmtThisisareadystatusthatcorrespondswithConnsoitcanonlybeusedoncepergoroutine(asisthecasewithConn)

typeStmtinterface

Close()error

NumInput()int

Exec(args[]Value)(Resulterror)

Query(args[]Value)(Rowserror)

CloseclosesthecurrentconnectionbutstillreturnsrowdataifitisexecutingaqueryoperationNumInputreturnsthenumberofobligateargumentsDatabasedriversshouldchecktheircallersargumentswhentheresultisgreaterthan0anditreturns-1whendatabasedriversdontknowanyobligateargumentExecexecutestheupdateinsertSQLcommandspreparedinPreparereturnsResultQueryexecutestheselectSQLcommandpreparedinPreparereturnsrowdata

driverTx

databasesqlinterface

113

Generallytransactionhandlesonlyhavesubmitorrollbackmethodsanddatabasedriversonlyneedtoimplementthesetwomethods

typeTxinterface

Commit()error

Rollback()error

driverExecerThisisanoptionalinterface

typeExecerinterface

Exec(querystringargs[]Value)(Resulterror)

IfthedriverdoesntimplementthisinterfacewhenyoucallDBExecitwillautomaticallycallPreparethenreturnStmtAfterthatitexecutestheExecmethodofStmtthenclosesStmt

driverResultThisistheinterfaceforresultsofupdateinsertoperations

typeResultinterface

LastInsertId()(int64error)

RowsAffected()(int64error)

LastInsertIdreturnsauto-incrementIdnumberafteradatabaseinsertoperationRowsAffectedreturnsrowsthatwereaffectedbyqueryoperations

driverRowsThisistheinterfacefortheresultofaqueryoperation

typeRowsinterface

Columns()[]string

Close()error

Next(dest[]Value)error

ColumnsreturnsfieldinformationofdatabasetablesTheslicehasaone-to-onecorrespondencewithSQLqueryfieldsonlyanddoesnotreturnallfieldsofthatdatabasetableCloseclosesRowsiteratorNextreturnsnextdataandassignstodestconvertingallstringsintobytearraysandgetsioEOFerrorifnomoredataisavailable

driverRowsAffectedThisisanaliasofint64butitimplementstheResultinterface

databasesqlinterface

114

typeRowsAffectedint64

func(RowsAffected)LastInsertId()(int64error)

func(vRowsAffected)RowsAffected()(int64error)

driverValueThisisanemptyinterfacethatcancontainanykindofdata

typeValueinterface

TheValuemustbesomethingthatdriverscanoperateonornilsoitshouldbeoneofthefollowingtypes

int64

float64

bool

[]byte

string[]ExceptRowsNextwhichcannotreturnstring

timeTime

driverValueConverterThisdefinesaninterfaceforconvertingnormalvaluestodriverValue

typeValueConverterinterface

ConvertValue(vinterface)(Valueerror)

Thisinterfaceiscommonlyusedindatabasedriversandhasmanyusefulfeatures

ConvertsdriverValuetoacorrespondingdatabasefieldtypeforexampleconvertsint64touint16ConvertsdatabasequeryresultstodriverValueConvertsdriverValuetoauserdefinedvalueinthescanfunction

driverValuerThisdefinesaninterfaceforreturningdriverValue

typeValuerinterface

Value()(Valueerror)

ManytypesimplementthisinterfaceforconversionbetweendriverValueanditself

AtthispointyoushouldknowabitaboutdevelopingdatabasedriversinGoOnceyoucanimplementinterfacesforoperationslikeadddeleteupdateetcthereareonlyafewproblemsleftrelatedtocommunicatingwithspecificdatabases

databasesqldatabasesqldefinesevenmorehigh-levelmethodsontopofdatabasesqldriverformoreconvenientdatabaseoperationsanditsuggeststhatyouimplementaconnectionpool

databasesqlinterface

115

typeDBstruct

driverdriverDriver

dsnstring

musyncMutexprotectsfreeConnandclosed

freeConn[]driverConn

closedbool

AsyoucanseetheOpenfunctionreturnsaDBthathasafreeConnandthisisasimpleconnectionpoolItsimplementationisverysimpleanduglyItusesdeferdbputConn(cierr)intheDbpreparefunctiontoputaconnectionintotheconnectionpoolEverytimeyoucalltheConnfunctionitchecksthelengthoffreeConnIfitsgreaterthan0thatmeansthereisareusableconnectionanditdirectlyreturnstoyouOtherwiseitcreatesanewconnectionandreturns

LinksDirectoryPrevioussectionDatabaseNextsectionMySQL

databasesqlinterface

116

52MySQLTheLAMPstackhasbeenverypopularontheinternetinrecentyearsandtheMinLAMPstandforMySQLMySQLisfamousbecauseitsopensourceandeasytouseAssuchithasbecomethede-factodatabaseintheback-endsofmanywebsites

MySQLdriversThereareacoupleofdriversthatsupportMySQLinGoSomeofthemimplementthedatabasesqlinterfaceandothersusetheirowninterfacestandards

httpsgithubcomgo-sql-drivermysqlsupportsdatabasesqlwritteninpureGohttpsgithubcomziutekmymysqlsupportsdatabasesqlanduserdefinedinterfaceswritteninpureGo

Illusethefirstdriverinthefollowingexamples(Iusethisoneinmypersonalprojectstoo)andIalsorecommendthatyouuseitforthefollowingreasons

ItsanewdatabasedriverandsupportsmorefeaturesItfullysupportsdatabasesqlinterfacestandardsSupportskeep-alivelongconnectionswiththread-safety

SamplesInthefollowingsectionsIllusethesamedatabasetablestructurefordifferentdatabasesthencreateSQLasfollows

CREATETABLE`userinfo`(

`uid`INT(10)NOTNULLAUTO_INCREMENT

`username`VARCHAR(64)NULLDEFAULTNULL

`departname`VARCHAR(64)NULLDEFAULTNULL

`created`DATENULLDEFAULTNULL

PRIMARYKEY(`uid`)

)

Thefollowingexampleshowshowtooperateonadatabasebasedonthedatabasesqlinterfacestandards

packagemain

import(

_githubcomgo-sql-drivermysql

databasesql

fmt

)

funcmain()

dberr=sqlOpen(mysqlastaxieastaxietestcharset=utf8)

checkErr(err)

insert

stmterr=dbPrepare(INSERTuserinfoSETusername=departname=created=)

checkErr(err)

reserr=stmtExec(astaxie研发部门2012-12-09)

checkErr(err)

iderr=resLastInsertId()

checkErr(err)

fmtPrintln(id)

update

HowtouseMySQL

117

stmterr=dbPrepare(updateuserinfosetusername=whereuid=)

checkErr(err)

reserr=stmtExec(astaxieupdateid)

checkErr(err)

affecterr=resRowsAffected()

checkErr(err)

fmtPrintln(affect)

query

rowserr=dbQuery(SELECTFROMuserinfo)

checkErr(err)

forrowsNext()

varuidint

varusernamestring

vardepartmentstring

varcreatedstring

err=rowsScan(ampuidampusernameampdepartmentampcreated)

checkErr(err)

fmtPrintln(uid)

fmtPrintln(username)

fmtPrintln(department)

fmtPrintln(created)

delete

stmterr=dbPrepare(deletefromuserinfowhereuid=)

checkErr(err)

reserr=stmtExec(id)

checkErr(err)

affecterr=resRowsAffected()

checkErr(err)

fmtPrintln(affect)

dbClose()

funccheckErr(errerror)

iferr=nil

panic(err)

Letmeexplainafewoftheimportantfunctionshere

sqlOpen()opensaregistereddatabasedriverTheGo-MySQL-DriverregisteredthemysqldriverhereThesecondargumentistheDSN(DataSourceName)thatdefinesinformationpertainingtothedatabaseconnectionItsupportsfollowingformats

userunix(pathtosocket)dbnamecharset=utf8

userpasswordtcp(localhost5555)dbnamecharset=utf8

userpassworddbname

userpasswordtcp([deadbeefcafe]80)dbname

dbPrepare()returnsaSQLoperationthatisgoingtobeexecutedItalsoreturnstheexecutionstatusafterexecutingSQL

dbQuery()executesSQLandreturnsaRowsresultstmtExec()executesSQLthathasbeenpreparedandstoredinStmt

Notethatweusetheformat=topassargumentsThisisnecessaryforpreventingSQLinjectionattacks

HowtouseMySQL

118

LinksDirectoryPrevioussectiondatabasesqlinterfaceNextsectionSQLite

HowtouseMySQL

119

53SQLiteSQLiteisanopensourceembeddedrelationaldatabaseIthasaself-containedzero-configurationandtransaction-supporteddatabaseengineItscharacteristicsarehighlyportableeasytousecompactefficientandreliableInmostofcasesyouonlyneedabinaryfileofSQLitetocreateconnectandoperateadatabaseIfyouarelookingforanembeddeddatabasesolutionSQLiteisworthconsideringYoucansaySQLiteistheopensourceversionofAccess

SQLitedriversTherearemanydatabasedriversforSQLiteinGobutmanyofthemdonotsupportthedatabasesqlinterfacestandards

httpsgithubcommattngo-sqlite3supportsdatabasesqlbasedoncgohttpsgithubcomfeyeleanorgosqlite3doesntsupportdatabasesqlbasedoncgohttpsgithubcomphfgo-sqlite3doesntsupportdatabasesqlbasedoncgo

ThefirstdriveristheonlyonethatsupportsthedatabasesqlinterfacestandardinitsSQLitedriversoIusethisinmyprojects-itwillmakeiteasytomigratemycodeinthefutureifIneedto

SamplesWecreatethefollowingSQL

CREATETABLE`userinfo`(

`uid`INTEGERPRIMARYKEYAUTOINCREMENT

`username`VARCHAR(64)NULL

`departname`VARCHAR(64)NULL

`created`DATENULL

)

Anexample

packagemain

import(

databasesql

fmt

time

_githubcommattngo-sqlite3

)

funcmain()

dberr=sqlOpen(sqlite3foodb)

checkErr(err)

insert

stmterr=dbPrepare(INSERTINTOuserinfo(usernamedepartnamecreated)values())

checkErr(err)

reserr=stmtExec(astaxie研发部门2012-12-09)

checkErr(err)

iderr=resLastInsertId()

checkErr(err)

fmtPrintln(id)

update

stmterr=dbPrepare(updateuserinfosetusername=whereuid=)

checkErr(err)

HowtouseSQLite

120

reserr=stmtExec(astaxieupdateid)

checkErr(err)

affecterr=resRowsAffected()

checkErr(err)

fmtPrintln(affect)

query

rowserr=dbQuery(SELECTFROMuserinfo)

checkErr(err)

varuidint

varusernamestring

vardepartmentstring

varcreatedtimeTime

forrowsNext()

err=rowsScan(ampuidampusernameampdepartmentampcreated)

checkErr(err)

fmtPrintln(uid)

fmtPrintln(username)

fmtPrintln(department)

fmtPrintln(created)

rowsClose()goodhabittoclose

delete

stmterr=dbPrepare(deletefromuserinfowhereuid=)

checkErr(err)

reserr=stmtExec(id)

checkErr(err)

affecterr=resRowsAffected()

checkErr(err)

fmtPrintln(affect)

dbClose()

funccheckErr(errerror)

iferr=nil

panic(err)

YoumayhavenoticedthatthecodeisalmostthesameasintheprevioussectionandthatweonlychangedthenameoftheregistereddriverandcalledsqlOpentoconnecttoSQLiteinadifferentway

Notethatsometimesyoucantusetheforstatementbecauseyoudonthavemorethanonerowthenyoucanusetheifstatement

ifrowsNext()

err=rowsScan(ampuidampusernameampdepartmentampcreated)

checkErr(err)

fmtPrintln(uid)

fmtPrintln(username)

fmtPrintln(department)

fmtPrintln(created)

AlsoyouhavetodoarowsNext()withoutusingthatyoucantfetchdataintheScanfunction

Transactions

HowtouseSQLite

121

TheaboveexampleshowshowyoufetchdatafromthedatabasebutwhenyouwanttowriteawebapplicationthenitwillnotonlybenecessarytofetchdatafromthedbbutitwillalsoberequiredtowritedataintoitForthatpurposeyoushouldusetransactionsbecauseforvariousreasonssuchashavingmultiplegoroutineswhichaccessthedatabasethedatabasemightgetlockedThisisundesirableinyourwebapplicationandtheuseoftransactionsiseffectiveinensuringyourdatabaseactivitieseitherpassorfailcompletelydependingoncircumstancesItisclearthatusingtransactionscanpreventalotofthingsfromgoingwrongwiththewebapp

trashSQLerr=databasePrepare(updatetasksetis_deleted=Ylast_modified_at=datetime()whereid=)

iferr=nil

fmtPrintln(err)

txerr=databaseBegin()

iferr=nil

fmtPrintln(err)

_err=txStmt(trashSQL)Exec(id)

iferr=nil

fmtPrintln(doingrollback)

txRollback()

else

txCommit()

Asitisclearfromtheaboveblockofcodeyoufirstprepareastatementafterwhichyouexecuteitdependingontheoutputofthatexecutionthenyoueitherrollitbackorcommitit

AsafinalnoteonthissectionthereisausefulSQLitemanagementtoolavailablehttpsqlitebrowserorg

LinksDirectoryPrevioussectionMySQLNextsectionPostgreSQL

HowtouseSQLite

122

54PostgreSQLPostgreSQLisanobject-relationaldatabasemanagementsystemavailableformanyplatformsincludingLinuxFreeBSDSolarisMicrosoftWindowsandMacOSXItisreleasedunderanMIT-stylelicenseandisthusfreeandopensourcesoftwareItslargerthanMySQLbecauseitsdesignedforenterpriseusageasanalternativetoOraclePostgresqlisagoodchoiceforenterprisetypeprojects

PostgreSQLdriversTherearemanydatabasedriversavailableforPostgreSQLHerearethreeexamplesofthem

httpsgithubcomlibpqsupportsdatabasesqlwritteninpureGohttpsgithubcomjbarhamgopgsqldriversupportsdatabasesqlwritteninpureGohttpsgithubcomlxngo-pgsqlsupportsdatabasesqlwritteninpureGo

Iwillusethefirstoneintheexamplesthatfollow

SamplesWecreatethefollowingSQL

CREATETABLEuserinfo

(

uidserialNOTNULL

usernamecharactervarying(100)NOTNULL

departnamecharactervarying(500)NOTNULL

Createddate

CONSTRAINTuserinfo_pkeyPRIMARYKEY(uid)

)

WITH(OIDS=FALSE)

Anexample

packagemain

import(

databasesql

fmt

_githubcomlibpq

time

)

const(

DB_USER=postgres

DB_PASSWORD=postgres

DB_NAME=test

)

funcmain()

dbinfo=fmtSprintf(user=spassword=sdbname=ssslmode=disable

DB_USERDB_PASSWORDDB_NAME)

dberr=sqlOpen(postgresdbinfo)

checkErr(err)

deferdbClose()

fmtPrintln(Insertingvalues)

varlastInsertIdint

err=dbQueryRow(INSERTINTOuserinfo(usernamedepartnamecreated)VALUES($1$2$3)returninguidastax

ie研发部门2012-12-09)Scan(amplastInsertId)

HowtousePostgreSQL

123

checkErr(err)

fmtPrintln(lastinsertedid=lastInsertId)

fmtPrintln(Updating)

stmterr=dbPrepare(updateuserinfosetusername=$1whereuid=$2)

checkErr(err)

reserr=stmtExec(astaxieupdatelastInsertId)

checkErr(err)

affecterr=resRowsAffected()

checkErr(err)

fmtPrintln(affectrowschanged)

fmtPrintln(Querying)

rowserr=dbQuery(SELECTFROMuserinfo)

checkErr(err)

forrowsNext()

varuidint

varusernamestring

vardepartmentstring

varcreatedtimeTime

err=rowsScan(ampuidampusernameampdepartmentampcreated)

checkErr(err)

fmtPrintln(uid|username|department|created)

fmtPrintf(3v|8v|6v|6vnuidusernamedepartmentcreated)

fmtPrintln(Deleting)

stmterr=dbPrepare(deletefromuserinfowhereuid=$1)

checkErr(err)

reserr=stmtExec(lastInsertId)

checkErr(err)

affecterr=resRowsAffected()

checkErr(err)

fmtPrintln(affectrowschanged)

funccheckErr(errerror)

iferr=nil

panic(err)

NotethatPostgreSQLusesthe$1$2formatinsteadofthethatMySQLusesandithasadifferentDSNformatinsqlOpenAnotherthingisthatthePostgreSQLdriverdoesnotsupportsqlResultLastInsertId()Soinsteadofthis

stmterr=dbPrepare(INSERTINTOuserinfo(usernamedepartnamecreated)VALUES($1$2$3))

reserr=stmtExec(astaxie研发部门2012-12-09)

fmtPrintln(resLastInsertId())

usedbQueryRow()andScan()togetthevalueforthelastinsertedid

err=dbQueryRow(INSERTINTOTABLE_NAMEvalues($1)returninguidVALUE1)Scan(amplastInsertId)

fmtPrintln(lastInsertId)

LinksDirectoryPrevioussectionSQLite

HowtousePostgreSQL

124

NextsectionDevelopORMbasedonbeedb

HowtousePostgreSQL

125

55DevelopORMbasedonbeedb(Projectbeedbisnolongermaintainedbutthecodesstillthere)

beedbisanORM(object-relationalmapper)developedinGobymeItusesidiomaticGotooperateondatabasesimplementingstruct-to-databasemappingandactsasalightweightGoORMframeworkThepurposeofdevelopingthisORMisnotonlytohelppeoplelearnhowtowriteanORMbutalsotofindagoodbalancebetweenfunctionalityandperformancewhenitcomestodatapersistence

beedbisanopensourceprojectthatsupportsbasicORMfunctionalitybutdoesntsupportassociationqueries

BecausebeedbsupportsdatabasesqlinterfacestandardsanydriverthatimplementsthisinterfacecanbeusedwithbeedbIvetestedthefollowingdrivers

Mysqlgithubgo-mysql-drivermysql

PostgreSQLgithubcomlibpq

SQLitegithubcommattngo-sqlite3

Mysqlgithubcomziutekmymysqlgodrv

MSADODBgithubcommattngo-adodb

Oraclegithubcommattngo-oci8

ODBCbitbucketorgmiquellamgodbc

InstallationYoucanusegogettoinstallbeedblocally

gogetgithubcomastaxiebeedb

InitializationFirstyouhavetoimportallthenecessarypackages

import(

databasesql

githubcomastaxiebeedb

_githubcomziutekmymysqlgodrv

)

Thenyouneedtoopenadatabaseconnectionandcreateabeedbobject(MySQLinthisexample)

dberr=sqlOpen(mymysqltestxiemengjun123456)

iferr=nil

panic(err)

orm=beedbNew(db)

beedbNew()actuallyhastwoargumentsThefirstisthedatabaseobjectandthesecondisforindicatingwhichdatabaseengineyoureusingIfyoureusingMySQLSQLiteyoucanjustskipthesecondargument

OtherwisethisargumentmustbesuppliedForinstanceinthecaseofSQLServer

HowtousebeedbORM

126

orm=beedbNew(dbmssql)

PostgreSQL

orm=beedbNew(dbpg)

beedbsupportsdebuggingUsethefollowingcodetoenableit

beedbOnDebug=true

NextwehaveastructfortheUserinfodatabasetablethatweusedinprevioussections

typeUserinfostruct

Uidint`PK`iftheprimarykeyisnotidyouneedtoaddtag`PK`foryourcustomizedprimarykey

Usernamestring

Departnamestring

CreatedtimeTime

Beawarethatbeedbauto-convertscamelcasenamestolowersnakecaseForexampleifwehaveUserInfoasthestructnamebeedbwillconvertittouser_infointhedatabaseThesameruleappliestostructfieldnames

InsertdataThefollowingexampleshowsyouhowtousebeedbtosaveastructinsteadofusingrawSQLcommandsWeusethebeedbSavemethodtoapplythechange

varsaveoneUserinfo

saveoneUsername=TestAddUser

saveoneDepartname=TestAddDepartname

saveoneCreated=timeNow()

ormSave(ampsaveone)

YoucanchecksaveoneUidaftertherecordisinserteditsvalueisaself-incrementedIDwhichtheSavemethodtakescareofforyou

beedbprovidesanotherwayofinsertingdatathisisviaGosmaptype

add=make(map[string]interface)

add[username]=astaxie

add[departname]=clouddevelop

add[created]=2012-12-02

ormSetTable(userinfo)Insert(add)

Insertmultipledata

addslice=make([]map[string]interface10)

add=make(map[string]interface)

add2=make(map[string]interface)

add[username]=astaxie

add[departname]=clouddevelop

add[created]=2012-12-02

add2[username]=astaxie2

add2[departname]=clouddevelop2

add2[created]=2012-12-02

addslice=append(addsliceaddadd2)

ormSetTable(userinfo)InsertBatch(addslice)

HowtousebeedbORM

127

ThemethodshownaboveissimilartoachainedquerywhichyoushouldbefamiliarwithifyouveeverusedjqueryItreturnstheoriginalORMobjectaftercallsthencontinuesdoingotherjobs

ThemethodSetTabletellstheORMwewanttoinsertourdataintotheuserinfotable

UpdatedataLetscontinueworkingwiththeaboveexampletoseehowtoupdatedataNowthatwehavetheprimarykeyofsaveone(Uid)beedbexecutesanupdateoperationinsteadofinsertinganewrecord

saveoneUsername=UpdateUsername

saveoneDepartname=UpdateDepartname

saveoneCreated=timeNow()

ormSave(ampsaveone)update

Likebeforeyoucanalsousemapforupdatingdata

t=make(map[string]interface)

t[username]=astaxie

ormSetTable(userinfo)SetPK(uid)Where(2)Update(t)

Letmeexplainsomeofthemethodsusedabove

SetPK()tellstheORMthatuidistheprimarykeyrecordsintheuserinfotableWhere()setsconditionsandsupportsmultipleargumentsIfthefirstargumentisanintegeritsashortformforWhere(ltprimarykeygt=ltvaluegt)Update()methodacceptsamapandupdatesthedatabase

QuerydataThebeedbqueryinterfaceisveryflexibleLetsseesomeexamples

Example1querybyprimarykey

varuserUserinfo

Whereacceptstwoargumentssupportsintegers

ormWhere(uid=27)Find(ampuser)

Example2

varuser2Userinfo

ormWhere(3)Find(ampuser2)shortformthatomitsprimarykey

Example3otherqueryconditions

varuser3Userinfo

Wheretwoargumentsareacceptedwithsupportforchartype

ormWhere(name=john)Find(ampuser3)

Example4morecomplexconditions

varuser4Userinfo

Wherethreeargumentsareaccepted

ormWhere(name=andageltjohn88)Find(ampuser4)

Examplestogetmultiplerecords

HowtousebeedbORM

128

Example1gets10recordswithidgt3thatstartswithposition20

varallusers[]Userinfo

err=ormWhere(idgt3)Limit(1020)FindAll(ampallusers)

Example2omitsthesecondargumentoflimitsoitstartswith0andgets10records

vartenusers[]Userinfo

err=ormWhere(idgt3)Limit(10)FindAll(amptenusers)

Example3getsallrecords

vareveryone[]Userinfo

err=ormOrderBy(uiddescusernameasc)FindAll(ampeveryone)

AsyoucanseetheLimitmethodisforlimitingthenumberofresults

Limit()supportstwoargumentsthenumberofresultsandthestartingposition0isthedefaultvalueofthestartingpositionOrderBy()isfororderingresultsTheargumentistheordercondition

AlltheexamplesherearesimplymappingrecordstostructsYoucanalsojustputthedataintoamapasfollows

a_=ormSetTable(userinfo)SetPK(uid)Where(2)Select(uidusername)FindMap()

Select()tellsbeedbhowmanyfieldsyouwanttogetfromthedatabasetableIfunspecifiedallfieldsarereturnedbydefaultFindMap()returnsthe[]map[string][]bytetypesoyouneedtoconverttoothertypesyourself

Deletedatabeedbprovidesrichmethodstodeletedata

Example1deleteasinglerecord

saveoneistheoneinaboveexample

ormDelete(ampsaveone)

Example2deletemultiplerecords

alluseristheslicewhichgetsmultiplerecords

ormDeleteAll(ampalluser)

Example3deleterecordsbySQL

ormSetTable(userinfo)Where(uidgt3)DeleteRow()

AssociationqueriesbeedbdoesntsupportjoiningbetweenstructsHoweversincesomeapplicationsneedthisfeaturehereisanimplementation

a_=ormSetTable(userinfo)Join(LEFTuserdetailuserinfouid=userdetailuid)

Where(userinfouid=1)Select(userinfouiduserinfousernameuserdetailprofile)FindMap()

HowtousebeedbORM

129

WeseeanewmethodcalledJoin()thathasthreearguments

ThefirstargumentTypeofJoinINNERLEFTOUTERCROSSetcThesecondargumentthetableyouwanttojoinwithThethirdargumentjoincondition

GroupByandHavingbeedbalsohasanimplementationofgroupbyandhaving

a_=ormSetTable(userinfo)GroupBy(username)Having(username=astaxie)FindMap()

GroupBy()indicatesthefieldthatisforgroupbyHaving()indicatesconditionsofhaving

FutureIhavereceivedalotoffeedbackonbeedbfrommanypeopleallaroundtheworldandImthinkingaboutreconfiguringthefollowingaspects

ImplementaninterfacedesignsimilartodatabasesqldriverinordertofacilitateCRUDoperationsImplementrelationaldatabaseassociationslikeonetooneonetomanyandmanytomanyHeresasample

typeProfilestruct

Nicknamestring

Mobilestring

typeUserinfostruct

Uidint

PK_Usernamestring

Departnamestring

CreatedtimeTime

ProfileHasOne

Auto-createtablesandindexesImplementaconnectionpoolusinggoroutines

LinksDirectoryPrevioussectionPostgreSQLNextsectionNoSQLdatabase

HowtousebeedbORM

130

56NoSQLdatabaseANoSQLdatabaseprovidesamechanismforthestorageandretrievalofdatathatuseslooserconsistencymodelsthantypicalrelationaldatabasesinordertoachievehorizontalscalingandhigheravailabilitySomeauthorsrefertothemasNotonlySQLtoemphasizethatsomeNoSQLsystemsdoallowSQL-likequerylanguagestobeused

AstheClanguageofthe21stcenturyGohasgoodsupportforNoSQLdatabasesincludingthepopularredismongoDBCassandraandMembaseNoSQLdatabases

redisredisisakey-valuestoragesystemlikeMemcachedthatsupportsthestringlistsetandzset(orderedset)valuetypes

TherearesomeGodatabasedriversforredis

httpsgithubcomgaryburdredigohttpsgithubcomgo-redisredishttpsgithubcomhoisieredishttpsgithubcomalphazeroGo-Redishttpsgithubcomsimonz05godis

Letsseehowtousethedriverthatredigotooperateonadatabase

packagemain

import(

fmt

githubcomgaryburdredigoredis

os

ossignal

syscall

time

)

var(

PoolredisPool

)

funcinit()

redisHost=6379

Pool=newPool(redisHost)

close()

funcnewPool(serverstring)redisPool

returnampredisPool

MaxIdle3

IdleTimeout240timeSecond

Dialfunc()(redisConnerror)

cerr=redisDial(tcpserver)

iferr=nil

returnnilerr

returncerr

TestOnBorrowfunc(credisConnttimeTime)error

_err=cDo(PING)

returnerr

NOSQL

131

funcclose()

c=make(chanosSignal1)

signalNotify(cosInterrupt)

signalNotify(csyscallSIGTERM)

signalNotify(csyscallSIGKILL)

gofunc()

lt-c

PoolClose()

osExit(0)

()

funcGet(keystring)([]byteerror)

conn=PoolGet()

deferconnClose()

vardata[]byte

dataerr=redisBytes(connDo(GETkey))

iferr=nil

returndatafmtErrorf(errorgetkeysvkeyerr)

returndataerr

funcmain()

testerr=Get(test)

fmtPrintln(testerr)

IforkedthelastofthesepackagesfixedsomebugsanduseditinmyshortURLservice(2millionPVeveryday)

httpsgithubcomastaxiegoredis

LetsseehowtousethedriverthatIforkedtooperateonadatabase

packagemain

import(

githubcomastaxiegoredis

fmt

)

funcmain()

varclientgoredisClient

SetthedefaultportinRedis

clientAddr=1270016379

stringmanipulation

clientSet(a[]byte(hello))

val_=clientGet(a)

fmtPrintln(string(val))

clientDel(a)

listoperation

vals=[]stringabcde

for_v=rangevals

clientRpush(l[]byte(v))

dbvals_=clientLrange(l04)

foriv=rangedbvals

println(istring(v))

clientDel(l)

NOSQL

132

WecanseethatitisquiteeasytooperateredisinGoandithashighperformanceItsclientcommandsarealmostthesameasredisbuilt-incommands

mongoDBmongoDB(fromhumongous)isanopensourcedocument-orienteddatabasesystemdevelopedandsupportedby10genItispartoftheNoSQLfamilyofdatabasesystemsInsteadofstoringdataintablesasisdoneinaclassicalrelationaldatabaseMongoDBstoresstructureddataasJSON-likedocumentswithdynamicschemas(MongoDBcallstheformatBSON)makingtheintegrationofdataincertaintypesofapplicationseasierandfaster

Figure51MongoDBcomparedtoMysql

ThebestdriverformongoDBiscalledmgoanditispossiblethatitwillbeincludedinthestandardlibraryinthefuture

Installmgo

gogetgopkginmgov2

Hereistheexample

packagemain

import(

fmt

gopkginmgov2

gopkginmgov2bson

log

)

typePersonstruct

Namestring

Phonestring

funcmain()

sessionerr=mgoDial(server1examplecomserver2examplecom)

iferr=nil

panic(err)

defersessionClose()

OptionalSwitchthesessiontoamonotonicbehavior

sessionSetMode(mgoMonotonictrue)

c=sessionDB(test)C(people)

err=cInsert(ampPersonAle+555381169639

ampPersonCla+555384028510)

iferr=nil

logFatal(err)

result=Person

err=cFind(bsonMnameAle)One(ampresult)

iferr=nil

logFatal(err)

fmtPrintln(PhoneresultPhone)

NOSQL

133

WecanseethattherearenobigdifferenceswhenitcomestooperatingonmgoorbeedbdatabasestheyarebothbasedonstructsThisistheGowayofdoingthings

LinksDirectoryPrevioussectionDevelopORMbasedonbeedbNextsectionSummary

NOSQL

134

57SummaryInthischapteryoufirstlearnedaboutthedesignofthedatabasesqlinterfaceandmanythird-partydatabasedriversforvariousdatabasetypesThenIintroducedbeedbanORMforrelationaldatabasestoyouIalsoshowedyousomesampledatabaseoperationsIntheendItalkedaboutafewNoSQLdatabasesWesawthatGoprovidesverygoodsupportforthoseNoSQLdatabases

AfterreadingthischapterIhopethatyouhaveabetterunderstandingofhowtooperatedatabasesinGoThisisthemostimportantpartofwebdevelopmentsoIwantyoutocompletelyunderstandthedesignconceptsofthedatabasesqlinterface

LinksDirectoryPrevioussectionNoSQLdatabaseNextsectionDatastorageandsession

Summary

135

6DatastorageandsessionsAnimportanttopicinwebdevelopmentisprovidingagooduserexperiencebutthefactthatHTTPisastatelessprotocolseemscontrarytothisspiritHowcanwecontrolthewholeprocessofviewingwebsitesforusersTheclassicsolutionsareusingcookiesandsessionswherecookiesserveastheclientsidemechanismandsessionsaresavedontheserversidewithauniqueidentifierforeverysingleuserNotethatsessionscanbepassedinURLsorcookiesoreveninyourdatabase(whichismuchmoresecurebutmayhamperyourapplicationperformance)

Insection61wearegoingtotalkaboutdifferencesbetweencookiesandsessionsInsection62youlllearnhowtousesessionsinGowithanimplementationofasessionmanagerInsection63wewilltalkaboutsessionhijackingandhowtopreventitwhenyouknowthatsessionscanbesavedanywhereThesessionmanagerwewillimplementinsection63willsavesessionsinmemorybutifweneedtoexpandourapplicationtoallowforsessionsharingitsalwaysbettertosavethesesessionsdirectlyintoourdatabaseWelltalkmoreaboutthisinsection64

LinksDirectoryPreviousChapterChapter5SummaryNextsectionSessionandcookies

Datastorageandsession

136

61SessionandcookiesSessionsandcookiesaretwoverycommonwebconceptsandarealsoveryeasytomisunderstandHowevertheyareextremelyimportantfortheauthorizationofpagesaswellasforgatheringpagestatisticsLetstakealookatthesetwousecases

SupposeyouwanttocrawlapagethatrestrictspublicaccesslikeatwitterusershomepageforinstanceOfcourseyoucanopenyourbrowserandtypeinyourusernameandpasswordtologinandaccessthatinformationbutso-calledwebcrawlingmeansthatweuseaprogramtoautomatethisprocesswithoutanyhumaninterventionThereforewehavetofindoutwhatisreallygoingonbehindthesceneswhenweuseabrowsertologin

WhenwefirstreceivealoginpageandtypeinausernameandpasswordafterwepresstheloginbuttonthebrowsersendsaPOSTrequesttotheremoteserverTheBrowserredirectstotheuserhomepageaftertheserververifiesthelogininformationandreturnsanHTTPresponseThequestionhereishowdoestheserverknowthatwehaveaccessprivilegesforthedesiredwebpageBecauseHTTPisstatelesstheserverhasnowayofknowingwhetherornotwepassedtheverificationinlaststepTheeasiestandperhapsthemostnaivesolutionistoappendtheusernameandpasswordtotheURLThisworksbutputstoomuchpressureontheserver(theservermustvalidateeveryrequestagainstthedatabase)andcanbedetrimentaltotheuserexperienceAnalternativewayofachievingthisgoalistosavetheusersidentityeitherontheserversideorclientsideusingcookiesandsessions

Cookiesinshortstorehistoricalinformation(includinguserlogininformation)ontheclientscomputerTheclientsbrowsersendsthesecookieseverytimetheuservisitsthesamewebsiteautomaticallycompletingtheloginstepfortheuser

Figure61cookieprinciple

SessionsontheotherhandstorehistoricalinformationontheserversideTheserverusesasessionidtoidentifydifferentsessionsandthesessionidthatisgeneratedbytheservershouldalwaysberandomanduniqueYoucanusecookiesorURLargumentstogettheclientsidentity

Figure62sessionprinciple

CookiesCookiesaremaintainedbybrowsersTheycanbemodifiedduringcommunicationbetweenwebserversandbrowsersWebapplicationscanaccesscookieinformationwhenusersvisitthecorrespondingwebsitesWithinmostbrowsersettingsthereisonesettingpertainingtocookieprivacyYoushouldbeabletoseesomethingsimilartothefollowingwhenyouopenit

Figure63cookieinbrowsers

Cookieshaveanexpirytimeandtherearetwotypesofcookiesdistinguishedbytheirlifecylessessioncookiesandpersistentcookies

IfyourapplicationdoesntsetacookieexpirytimethebrowserwillnotsaveitintothelocalfilesystemafterthebrowserisclosedThesecookiesarecalledsessioncookiesandthistypeofcookieisusuallysavedinmemoryinsteadoftothelocalfilesystem

Ifyourapplicationdoessetanexpirytime(forexamplesetMaxAge(606024))thebrowserwillsavethiscookietothelocalfilesystemanditwillnotbedeleteduntilreachingtheallottedexpirytimeCookiesthataresavedtothelocalfilesystemcanbesharedbydifferentbrowserprocesses-forexamplebytwoIEwindowsdifferentbrowsersusedifferentprocessesfordealingwithcookiesthataresavedinmemory  

Sessionandcookies

137

SetcookiesinGoGousestheSetCookiefunctioninthenethttppackagetosetcookies

httpSetCookie(wResponseWritercookieCookie)

wistheresponseoftherequestandcookieisastructLetsseewhatitlookslike

typeCookiestruct

Namestring

Valuestring

Pathstring

Domainstring

ExpirestimeTime

RawExpiresstring

MaxAge=0meansnoMax-Ageattributespecified

MaxAgelt0meansdeletecookienowequivalentlyMax-Age0

MaxAgegt0meansMax-Ageattributepresentandgiveninseconds

MaxAgeint

Securebool

HttpOnlybool

Rawstring

Unparsed[]stringRawtextofunparsedattribute-valuepairs

Hereisanexampleofsettingacookie

expiration=timeNow()Add(36524timeHour)

cookie=httpCookieNameusernameValueastaxieExpiresexpiration

httpSetCookie(wampcookie)

FetchcookiesinGoTheaboveexampleshowshowtosetacookieNowletsseehowtogetacookiethathasbeenset

cookie_=rCookie(username)

fmtFprint(wcookie)

Hereisanotherwaytogetacookie

for_cookie=rangerCookies()

fmtFprint(wcookieName)

Asyoucanseeitsveryconvenienttogetcookiesfromrequests

SessionsAsessionisaseriesofactionsormessagesForexampleyoucanthinkoftheactionsyoubetweenpickingupyourtelephonetohanginguptobeatypeofsessionWhenitcomestonetworkprotocolssessionshavemoretodowithconnectionsbetweenbrowsersandservers

Sessionshelptostoretheconnectionstatusbetweenserverandclientandthiscansometimesbeintheformofadatastoragestruct

Sessionandcookies

138

Sessionsareaserver-sidemechanismandusuallyemployhashtables(orsomethingsimilar)tosaveincominginformation

WhenanapplicationneedstoassignanewsessiontoaclienttheservershouldcheckifthereareanyexistingsessionsforthesameclientwithauniquesessionidIfthesessionidalreadyexiststheserverwilljustreturnthesamesessiontotheclientOntheotherhandifasessioniddoesntexistfortheclienttheservercreatesabrandnewsession(thisusuallyhappenswhentheserverhasdeletedthecorrespondingsessionidbuttheuserhasappendedtheoldsessionmanually)

Thesessionitselfisnotcomplexbutitsimplementationanddeploymentaresoyoucannotuseonewaytorulethemall

SummaryInconclusionthepurposeofsessionsandcookiesarethesameTheyarebothforovercomingthestatelessnessofHTTPbuttheyusedifferentmethodsSessionsusecookiestosavesessionidsontheclientsideandsaveallotherinformationontheserversideCookiessaveallclientinformationontheclientsideYoumayhavenoticedthatcookieshavesomesecurityproblemsForexampleusernamesandpasswordscanpotentiallybecrackedandcollectedbymaliciousthirdpartywebsites

Herearetwocommonexploits

1 appAsettinganunexpectedcookieforappB2 XSSattackappAusestheJavaScriptdocumentcookietoaccessthecookiesofappB

AfterfinishingthissectionyoushouldknowsomeofthebasicconceptsofcookiesandsessionsYoushouldbeabletounderstandthedifferencesbetweenthemsothatyouwontkillyourselfwhenbugsinevitablyemergeWelldiscusssessionsinmoredetailinthefollowingsections

LinksDirectoryPrevioussectionDatastorageandsessionNextsectionHowtousesessioninGo

Sessionandcookies

139

62HowtousesessionsinGoInsection61welearnedthatsessionsareonesolutionforverifyingusersandthatfornowtheGostandardlibrarydoesnothavebaked-insupportforsessionsorsessionhandlingSoweregoingtoimplementourownversionofasessionmanagerinGo

CreatingsessionsThebasicprinciplebehindsessionsisthataservermaintainsinformationforeverysingleclientandclientsrelyonuniquesessionidstoaccessthisinformationWhenusersvisitthewebapplicationtheserverwillcreateanewsessionwiththefollowingthreestepsasneeded

CreateauniquesessionidOpenupadatastoragespacenormallywesavesessionsinmemorybutyouwillloseallsessiondataifthesystemisaccidentallyinterruptedThiscanbeaveryseriousissueifwebapplicationdealswithsensitivedatalikeinelectroniccommerceforinstanceInordertosolvethisproblemyoucaninsteadsaveyoursessiondatainadatabaseorfilesystemThismakesdatapersistencemorereliableandeasytosharewithotherapplicationsalthoughthetradeoffisthatmoreserver-sideIOisneededtoreadandwritethesesessionsSendtheuniquesessionidtotheclient

ThekeystephereistosendtheuniquesessionidtotheclientInthecontextofastandardHTTPresponseyoucaneitherusetheresponselineheaderorbodytoaccomplishthisthereforewehavetwowaystosendsessionidstoclientsbycookiesorURLrewrites

CookiestheservercaneasilyuseSet-cookieinsideofaresponseheadertosendasessionidtoaclientandaclientcanthenusethiscookieforfuturerequestsweoftensettheexpirytimeforcookiescontainingsessioninformationto0whichmeansthecookiewillbesavedinmemoryandonlydeletedafterusershaveclosetheirbrowsersURLrewriteappendthesessionidasargumentsintheURLforallpagesThiswayseemsmessybutitsthebestchoiceifclientshavedisabledcookiesintheirbrowsers

UseGotomanagesessionsWevetalkedaboutconstructingsessionsandyoushouldnowhaveageneraloverviewofitbuthowcanweusesessionsondynamicpagesLetstakeacloserlookatthelifecycleofasessionsowecancontinueimplementingourGosessionmanager

Sessionmanagementdesign

Hereisalistofsomeofthekeyconsiderationsinsessionmanagementdesign

GlobalsessionmanagerKeepsessioniduniqueHaveonesessionforeveryuserSessionstorageinmemoryfileordatabaseDealwithexpiredsessions

NextwellexamineacompleteexampleofaGosessionmanagerandtherationalebehindsomeofitsdesigndecisions

Sessionmanager

Defineaglobalsessionmanager

HowtousesessioninGo

140

typeManagerstruct

cookieNamestringprivatecookiename

locksyncMutexprotectssession

providerProvider

maxlifetimeint64

funcNewManager(provideNamecookieNamestringmaxlifetimeint64)(Managererror)

providerok=provides[provideName]

ifok

returnnilfmtErrorf(sessionunknownprovideq(forgottenimport)provideName)

returnampManagerproviderprovidercookieNamecookieNamemaxlifetimemaxlifetimenil

Createaglobalsessionmanagerinthemain()function

varglobalSessionssessionManager

Theninitializethesessionmanager

funcinit()

globalSessions=NewManager(memorygosessionid3600)

WeknowthatwecansavesessionsinmanywaysincludinginmemorythefilesystemordirectlyintothedatabaseWeneedtodefineaProviderinterfaceinordertorepresenttheunderlyingstructureofoursessionmanager

typeProviderinterface

SessionInit(sidstring)(Sessionerror)

SessionRead(sidstring)(Sessionerror)

SessionDestroy(sidstring)error

SessionGC(maxLifeTimeint64)

SessionInitimplementstheinitializationofasessionandreturnsanewsessionifitsucceedsSessionReadreturnsasessionrepresentedbythecorrespondingsidCreatesanewsessionandreturnsitifitdoesnotalreadyexistSessionDestroygivenansiddeletesthecorrespondingsessionSessionGCdeletesexpiredsessionvariablesaccordingtomaxLifeTime

SowhatmethodsshouldoursessioninterfacehaveIfyouhaveanyexperienceinwebdevelopmentyoushouldknowthatthereareonlyfouroperationsforsessionssetvaluegetvaluedeletevalueandgetcurrentsessionidSooursessioninterfaceshouldhavefourmethodstoperformtheseoperations

typeSessioninterface

Set(keyvalueinterface)errorsetsessionvalue

Get(keyinterface)interfacegetsessionvalue

Delete(keyinterface)errordeletesessionvalue

SessionID()stringbackcurrentsessionID

ThisdesigntakesitsrootsfromthedatabasesqldriverwhichdefinestheinterfacefirstthenregistersspecificstructureswhenwewanttouseitThefollowingcodeistheinternalimplementationofasessionregisterfunction

HowtousesessioninGo

141

varprovides=make(map[string]Provider)

Registermakesasessionprovideravailablebytheprovidedname

IfaRegisteriscalledtwicewiththesamenameorifthedriverisnil

itpanics

funcRegister(namestringproviderProvider)

ifprovider==nil

panic(sessionRegisterproviderisnil)

if_dup=provides[name]dup

panic(sessionRegistercalledtwiceforprovider+name)

provides[name]=provider

UniquesessionidsSessionidsareforidentifyingusersofwebapplicationssotheymustbeuniqueThefollowingcodeshowshowtoachievethisgoal

func(managerManager)sessionId()string

b=make([]byte32)

if_err=ioReadFull(randReaderb)err=nil

return

returnbase64URLEncodingEncodeToString(b)

CreatingasessionWeneedtoallocateorgetanexistingsessioninordertovalidateuseroperationsTheSessionStartfunctionisforcheckingtheexistenceofanysessionsrelatedtothecurrentuserandcreatinganewsessionifnoneisfound

func(managerManager)SessionStart(whttpResponseWriterrhttpRequest)(sessionSession)

managerlockLock()

defermanagerlockUnlock()

cookieerr=rCookie(managercookieName)

iferr=nil||cookieValue==

sid=managersessionId()

session_=managerproviderSessionInit(sid)

cookie=httpCookieNamemanagercookieNameValueurlQueryEscape(sid)PathHttpOnlytrueM

axAgeint(managermaxlifetime)

httpSetCookie(wampcookie)

else

sid_=urlQueryUnescape(cookieValue)

session_=managerproviderSessionRead(sid)

return

Hereisanexamplethatusessessionsforaloginoperation

funclogin(whttpResponseWriterrhttpRequest)

sess=globalSessionsSessionStart(wr)

rParseForm()

ifrMethod==GET

t_=templateParseFiles(logingtpl)

wHeader()Set(Content-Typetexthtml)

tExecute(wsessGet(username))

else

sessSet(usernamerForm[username])

httpRedirect(wr302)

HowtousesessioninGo

142

Operationvaluesetgetanddelete

TheSessionStartfunctionreturnsavariablethatimplementsasessioninterfaceHowdoweuseit

YousawsessionGet(uid)intheaboveexampleforabasicoperationNowletsexamineamoredetailedexample

funccount(whttpResponseWriterrhttpRequest)

sess=globalSessionsSessionStart(wr)

createtime=sessGet(createtime)

ifcreatetime==nil

sessSet(createtimetimeNow()Unix())

elseif(createtime(int64)+360)lt(timeNow()Unix())

globalSessionsSessionDestroy(wr)

sess=globalSessionsSessionStart(wr)

ct=sessGet(countnum)

ifct==nil

sessSet(countnum1)

else

sessSet(countnum(ct(int)+1))

t_=templateParseFiles(countgtpl)

wHeader()Set(Content-Typetexthtml)

tExecute(wsessGet(countnum))

AsyoucanseeoperatingonsessionssimplyinvolvesusingthekeyvaluepatternintheSetGetandDeleteoperations

BecausesessionshavetheconceptofanexpirytimewedefinetheGCtoupdatethesessionslatestmodifytimeThiswaytheGCwillnotdeletesessionsthathaveexpiredbutarestillbeingused

ResetsessionsWeknowthatwebapplicationshavealogoutoperationWhenuserslogoutweneedtodeletethecorrespondingsessionWevealreadyusedtheresetoperationinaboveexample-nowletstakealookatthefunctionbody

Destroysessionid

func(managerManager)SessionDestroy(whttpResponseWriterrhttpRequest)

cookieerr=rCookie(managercookieName)

iferr=nil||cookieValue==

return

else

managerlockLock()

defermanagerlockUnlock()

managerproviderSessionDestroy(cookieValue)

expiration=timeNow()

cookie=httpCookieNamemanagercookieNamePathHttpOnlytrueExpiresexpirationMaxAge-1

httpSetCookie(wampcookie)

Deletesessions

LetsseehowtoletthesessionmanagerdeleteasessionWeneedtostarttheGCinthemain()function

HowtousesessioninGo

143

funcinit()

goglobalSessionsGC()

func(managerManager)GC()

managerlockLock()

defermanagerlockUnlock()

managerproviderSessionGC(managermaxlifetime)

timeAfterFunc(timeDuration(managermaxlifetime)func()managerGC())

WeseethattheGCmakesfulluseofthetimerfunctioninthetimepackageItautomaticallycallsGCwhenthesessiontimesoutensuringthatallsessionsareusableduringmaxLifeTimeAsimilarsolutioncanbeusedtocountonlineusers

SummarySofarweimplementedasessionmanagertomanageglobalsessionsinthewebapplicationanddefinedtheProviderinterfaceasthestorageimplementationofSessionInthenextsectionwearegoingtotalkabouthowtoimplementProviderforadditionalsessionstoragestructureswhichyouwillbeabletoreferenceinthefuture

LinksDirectoryPrevioussectionSessionandcookiesNextsectionSessionstorage

HowtousesessioninGo

144

63SessionstorageWeintroducedasimplesessionmanagersworkingprinciplesintheprevioussectionandamongotherthingswedefinedasessionstorageinterfaceInthissectionImgoingtoshowyouanexampleofamemorybasedsessionstorageenginethatimplementsthisinterfaceYoucantailorthistootherformsofsessionstorageaswell

packagememory

import(

containerlist

githubcomastaxiesession

sync

time

)

varpder=ampProviderlistlistNew()

typeSessionStorestruct

sidstringuniquesessionid

timeAccessedtimeTimelastaccesstime

valuemap[interface]interfacesessionvaluestoredinside

func(stSessionStore)Set(keyvalueinterface)error

stvalue[key]=value

pderSessionUpdate(stsid)

returnnil

func(stSessionStore)Get(keyinterface)interface

pderSessionUpdate(stsid)

ifvok=stvalue[key]ok

returnv

else

returnnil

returnnil

func(stSessionStore)Delete(keyinterface)error

delete(stvaluekey)

pderSessionUpdate(stsid)

returnnil

func(stSessionStore)SessionID()string

returnstsid

typeProviderstruct

locksyncMutexlock

sessionsmap[string]listElementsaveinmemory

listlistListgc

func(pderProvider)SessionInit(sidstring)(sessionSessionerror)

pderlockLock()

deferpderlockUnlock()

v=make(map[interface]interface0)

newsess=ampSessionStoresidsidtimeAccessedtimeNow()valuev

element=pderlistPushBack(newsess)

pdersessions[sid]=element

returnnewsessnil

func(pderProvider)SessionRead(sidstring)(sessionSessionerror)

ifelementok=pdersessions[sid]ok

Sessionstorage

145

returnelementValue(SessionStore)nil

else

sesserr=pderSessionInit(sid)

returnsesserr

returnnilnil

func(pderProvider)SessionDestroy(sidstring)error

ifelementok=pdersessions[sid]ok

delete(pdersessionssid)

pderlistRemove(element)

returnnil

returnnil

func(pderProvider)SessionGC(maxlifetimeint64)

pderlockLock()

deferpderlockUnlock()

for

element=pderlistBack()

ifelement==nil

break

if(elementValue(SessionStore)timeAccessedUnix()+maxlifetime)lttimeNow()Unix()

pderlistRemove(element)

delete(pdersessionselementValue(SessionStore)sid)

else

break

func(pderProvider)SessionUpdate(sidstring)error

pderlockLock()

deferpderlockUnlock()

ifelementok=pdersessions[sid]ok

elementValue(SessionStore)timeAccessed=timeNow()

pderlistMoveToFront(element)

returnnil

returnnil

funcinit()

pdersessions=make(map[string]listElement0)

sessionRegister(memorypder)

TheaboveexampleimplementsamemorybasedsessionstoragemechanismItusesitsinit()functiontoregisterthisstorageenginetothesessionmanagerSohowdoweregisterthisenginefromourmainprogram

import(

githubcomastaxiesession

_githubcomastaxiesessionprovidersmemory

)

Weusetheblankimportmechanism(whichwillinvokethepackagesinit()functionautomatically)toregisterthisenginetoasessionmanagerWethenusethefollowingcodetoinitializethesessionmanager

Sessionstorage

146

varglobalSessionssessionManager

initializeininit()function

funcinit()

globalSessions_=sessionNewManager(memorygosessionid3600)

goglobalSessionsGC()

LinksDirectoryPrevioussectionHowtousesessionsinGoNextsectionPreventsessionhijacking

Sessionstorage

147

64PreventingsessionhijackingSessionhijackingisacommonyetserioussecuritythreatClientsusesessionidsforvalidationandotherpurposeswhencommunicatingwithserversUnfortunatelymaliciousthirdpartiescansometimestrackthesecommunicationsandfigureouttheclientsessionid

Inthissectionwearegoingtoshowyouhowtohijackasessionforeducationalpurposes

ThesessionhijackingprocessThefollowingcodeisacounterforthecountvariable

funccount(whttpResponseWriterrhttpRequest)

sess=globalSessionsSessionStart(wr)

ct=sessGet(countnum)

ifct==nil

sessSet(countnum1)

else

sessSet(countnum(ct(int)+1))

t_=templateParseFiles(countgtpl)

wHeader()Set(Content-Typetexthtml)

tExecute(wsessGet(countnum))

Thecontentofcountgtplisasfollows

HiNowcount

Wecanseethefollowingcontentinthebrowser

Figure64countinbrowser

Keeprefreshinguntilthenumberbecomes6thenopenthebrowserscookiemanager(Iusechromehere)Youshouldbeabletoseethefollowinginformation

Figure65cookiessavedinabrowser

Thisstepisveryimportantopenanotherbrowser(Iusefirefoxhere)copytheURLtothenewbrowseropenacookiesimulatortocreateanewcookieandinputexactlythesamevalueasthecookiewesawinourfirstbrowser

Figure66Simulateacookie

Refreshthepageandyoullseethefollowing

Figure67hijackingthesessionhassucceeded

HereweseethatwecanhijacksessionsbetweendifferentbrowsersandactionsperformedinonebrowsercanaffectthestateofapageinanotherbrowserBecauseHTTPisstatelessthereisnowayofknowingthatthesessionidfromfirefoxissimulatedandchromeisalsonotabletoknowthatitssessionidhasbeenhijacked

Preventhijackofsession

148

preventsessionhijacking

cookieonlyandtoken

ThroughthissimpleexampleofhijackingasessionyoucanseethatitsverydangerousbecauseitallowsattackerstodowhatevertheywantSohowcanwepreventsessionhijacking

ThefirststepistoonlysetsessionidsincookiesinsteadofinURLrewritesAlsoweshouldsetthehttponlycookiepropertytotrueThisrestrictsclient-sidescriptsfromgainingaccesstothesessionidUsingthesetechniquescookiescannotbeaccessedbyXSSanditwontbeaseasyaswedemonstratedtogetasessionidfromacookiemanager

ThesecondstepistoaddatokentoeveryrequestSimilartothemannerinwhichwedealtwithrepeatingformsubmissionsinprevioussectionsweaddahiddenfieldthatcontainsatokenWhenarequestissenttotheserverwecanverifythistokentoprovethattherequestisunique

h=md5New()

salt=astaxie^7amp8888

ioWriteString(hsalt+timeNow()String())

token=fmtSprintf(xhSum(nil))

ifrForm[token]=token

asktologin

sessSet(tokentoken)

SessionidtimeoutAnothersolutionistoaddacreatetimeforeverysessionandtoreplaceexpiredsessionidswithnewonesThiscanpreventsessionhijackingundercertaincircumstancessuchaswhenthehijackisattemptedtoolate

createtime=sessGet(createtime)

ifcreatetime==nil

sessSet(createtimetimeNow()Unix())

elseif(createtime(int64)+60)lt(timeNow()Unix())

globalSessionsSessionDestroy(wr)

sess=globalSessionsSessionStart(wr)

Wesetavaluetosavethecreatetimeandcheckifitsexpired(Iset60secondshere)Thisstepcanoftenthwartsessionhijackingattempts

BycombiningthetwosolutionssetoutaboveyouwillbeabletopreventmostsessionhijackingattemptsfromsucceedingOntheonehandsessionidsthatarefrequentlyresetwillresultinanattackeralwaysgettingexpiredanduselesssessionidsontheotherhandbysettingthehttponlypropertyoncookiesandensuringthatsessionidscanonlybepassedviacookiesallURLbasedattacksaremitigatedFinallywesetMaxAge=0onourcookieswhichmeansthatthesessionidswillnotbesavedinthebrowserhistory

LinksDirectoryPrevioussectionSessionstorageNextsectionSummary

Preventhijackofsession

149

65SummaryInthischapterwelearnedaboutthedefinitionandpurposeofsessionsandcookiesandtherelationshipbetweenthetwoSinceGodoesntsupportsessionsinitsstandardlibrarywealsodesignedourownsessionmanagerWewentthrougheverythingfromcreatingclientsessionstodeletingthemWethendefinedaninterfacecalledProviderwhichsupportsallsessionstoragestructuresInsection63weimplementedamemorybasedsessionmanagertopersistclientdataacrosssessionsInsection64IdemonstratedonewayofhijackingasessionThenwelookedathowtopreventyourownsessionsfrombeinghijackedIhopethatyounowunderstandmostoftheworkingprinciplesbehindsessionssothatyoureabletosafelyusetheminyourapplications

LinksDirectoryPrevioussectionPreventsessionhijackingNextchapterTextfiles

Summary

150

7TextfilesHandlingtextfilesisabigpartofwebdevelopmentWeoftenneedtoproduceorhandlereceivedtextcontentincludingstringsnumbersJSONXMLetcAsahighperformancelanguageGohasgoodsupportforthisinitsstandardlibraryYoullfindthatthesesupportinglibrariesarejustawesomeandwillallowyoutoeasilydealwithanytextcontentyoumayencounterThischaptercontains4sectionsandwillgiveyouafullintroductiontotextprocessinginGo

XMLisaninteractivelanguagethatiscommonlyusedinmanyAPIsmanywebserverswritteninJavauseXMLastheirstandardinteractionlanguageWellmoretalkaboutXMLinsection71Insection72welltakealookatJSONwhichhasbeenverypopularinrecentyearsandismuchmoreconvenientthanXMLInsection73wearegoingtotalkaboutregularexpressionswhich(forthemajorityofpeople)lookslikealanguageusedbyaliensInsection74youwillseehowtheMVCpatternisusedtodevelopapplicationsinGoandalsohowtouseGostemplatepackagefortemplatingyourviewsInsection75wellintroduceyoutofileandfolderoperationsFinallywewillexplainsomeGostringoperationsinsection76

LinksDirectoryPreviousChapterChapter6SummaryNextsectionXML

Textfiles

151

71XMLXMLisacommonlyuseddatacommunicationformatinwebservicesTodayitsassumingamoreandmoreimportantroleinwebdevelopmentInthissectionweregoingtointroducehowtoworkwithXMLthroughGosstandardlibrary

IwillnotmakeanyattemptstoteachXMLssyntaxorconventionsForthatpleasereadmoredocumentationaboutXMLitselfWewillonlyfocusonhowtoencodeanddecodeXMLfilesinGo

SupposeyouworkinITandyouhavetodealwiththefollowingXMLconfigurationfile

ltxmlversion=10encoding=utf-8gt

ltserversversion=1gt

ltservergt

ltserverNamegtShanghai_VPNltserverNamegt

ltserverIPgt127001ltserverIPgt

ltservergt

ltservergt

ltserverNamegtBeijing_VPNltserverNamegt

ltserverIPgt127002ltserverIPgt

ltservergt

ltserversgt

TheaboveXMLdocumentcontainstwokindsofinformationaboutyourservertheservernameandIPWewillusethisdocumentinourfollowingexamples

ParseXMLHowdoweparsethisXMLdocumentWecanusetheUnmarshalfunctioninGosxmlpackagetodothis

funcUnmarshal(data[]bytevinterface)error

thedataparameterreceivesadatastreamfromanXMLsourceandvisthestructureyouwanttooutputtheparsedXMLtoItisaninterfacewhichmeansyoucanconvertXMLtoanystructureyoudesireHerewellonlytalkabouthowtoconvertfromXMLtothestructtypesincetheysharesimilartreestructures

Samplecode

XML

152

packagemain

import(

encodingxml

fmt

ioioutil

os

)

typeRecurlyserversstruct

XMLNamexmlName`xmlservers`

Versionstring`xmlversionattr`

Svs[]server`xmlserver`

Descriptionstring`xmlinnerxml`

typeserverstruct

XMLNamexmlName`xmlserver`

ServerNamestring`xmlserverName`

ServerIPstring`xmlserverIP`

funcmain()

fileerr=osOpen(serversxml)Forreadaccess

iferr=nil

fmtPrintf(errorverr)

return

deferfileClose()

dataerr=ioutilReadAll(file)

iferr=nil

fmtPrintf(errorverr)

return

v=Recurlyservers

err=xmlUnmarshal(dataampv)

iferr=nil

fmtPrintf(errorverr)

return

fmtPrintln(v)

XMLisactuallyatreedatastructureandwecandefineaverysimilarstructureusingstructsinGothenusexmlUnmarshaltoconvertfromXMLtoourstructobjectThesamplecodewillprintthefollowingcontent

servers1[serverShanghai_VPN127001serverBeijing_VPN127002]

ltservergt

ltserverNamegtShanghai_VPNltserverNamegt

ltserverIPgt127001ltserverIPgt

ltservergt

ltservergt

ltserverNamegtBeijing_VPNltserverNamegt

ltserverIPgt127002ltserverIPgt

ltservergt

WeusexmlUnmarshaltoparsetheXMLdocumenttothecorrespondingstructobjectYoushouldseethatwehavesomethinglikexmlserverNameinourstructThisisafeatureofstructscalledstructtagsforhelpingwithreflectionLetsseethedefinitionofUnmarshalagain

funcUnmarshal(data[]bytevinterface)error

XML

153

ThefirstargumentisanXMLdatastreamThesecondargumentisstoragetypeandsupportsthestructsliceandstringtypesGosXMLpackageusesreflectionfordatamappingsoallfieldsinvshouldbeexportedHoweverthiscausesaproblemhowdoesitknowwhichXMLfieldcorrespondstothemappedstructfieldTheansweristhattheXMLparserparsesdatainacertainorderThelibrarywilltrytofindthematchingstructtagfirstIfamatchcannotbefoundthenitsearchesthroughthestructfieldnamesBeawarethatalltagsfieldnamesandXMLelementsarecasesensitivesoyouhavetomakesurethatthereisaone-to-onecorrespondenceforthemappingtosucceed

GosreflectionmechanismallowsyoutousethistaginformationtoreflectXMLdatatoastructobjectIfyouwanttoknowmoreaboutreflectioninGopleasereadthepackagedocumentationonstructtagsandreflection

HerearesomeruleswhenusingthexmlpackagetoparseXMLdocumentstostructs

Ifthefieldtypeisastringor[]bytewiththetaginnerxmlUnmarshalwillassignrawXMLdatatoitlikeDescriptionintheaboveexample

Shanghai_VPN127001Beijing_VPN127002

IfafieldiscalledXMLNameanditstypeisxmlNamethenitgetstheelementnamelikeserversinaboveexample

IfafieldstagcontainsthecorrespondingelementnamethenitgetstheelementnameaswelllikeservernameandserveripintheaboveexampleIfafieldstagcontainsattrthenitgetsthecorrespondingelementsattributelikeversioninaboveexampleIfafieldstagcontainssomethinglikeagtbgtcitgetsthevalueoftheelementcofnodebofnodeaIfafieldstagcontains=thenitgetsnothingIfafieldstagcontainsanythenitgetsallchildelementswhichdonotfittheotherrulesIftheXMLelementshaveoneormorecommentsallofthesecommentswillbeaddedtothefirstfieldthathasthetagthatcontainscommentsThisfieldtypecanbeastringor[]byteIfthiskindoffielddoesnotexistallcommentsarediscarded

TheserulestellyouhowtodefinetagsinstructsOnceyouunderstandtheserulesmappingXMLtostructswillbeaseasyasthesamplecodeaboveBecausetagsandXMLelementshaveaone-to-onecorrespondencewecanalsouseslicestorepresentmultipleelementsonthesamelevel

Notethatallfieldsinstructsshouldbeexported(capitalized)inordertoparsedatacorrectly

ProduceXMLWhatifwewanttoproduceanXMLdocumentinsteadofparsingoneHowdowedothisinGoUnsurprisinglythexmlpackageprovidestwofunctionswhichareMarshalandMarshalIndentwherethesecondfunctionautomaticallyindentsthemarshalledXMLdocumentTheirdefinitionasfollows

funcMarshal(vinterface)([]byteerror)

funcMarshalIndent(vinterfaceprefixindentstring)([]byteerror)

ThefirstargumentinbothofthesefunctionsisforstoringamarshalledXMLdatastream

Letslookatanexampletoseehowthisworks

XML

154

packagemain

import(

encodingxml

fmt

os

)

typeServersstruct

XMLNamexmlName`xmlservers`

Versionstring`xmlversionattr`

Svs[]server`xmlserver`

typeserverstruct

ServerNamestring`xmlserverName`

ServerIPstring`xmlserverIP`

funcmain()

v=ampServersVersion1

vSvs=append(vSvsserverShanghai_VPN127001)

vSvs=append(vSvsserverBeijing_VPN127002)

outputerr=xmlMarshalIndent(v)

iferr=nil

fmtPrintf(errorvnerr)

osStdoutWrite([]byte(xmlHeader))

osStdoutWrite(output)

Theaboveexampleprintsthefollowinginformation

ltxmlversion=10encoding=UTF-8gt

ltserversversion=1gt

ltservergt

ltserverNamegtShanghai_VPNltserverNamegt

ltserverIPgt127001ltserverIPgt

ltservergt

ltservergt

ltserverNamegtBeijing_VPNltserverNamegt

ltserverIPgt127002ltserverIPgt

ltservergt

ltserversgt

AswevepreviouslydefinedthereasonwehaveosStdoutWrite([]byte(xmlHeader))isbecausebothxmlMarshalIndentandxmlMarshaldonotoutputXMLheadersontheirownsowehavetoexplicitlyprinttheminordertoproduceXMLdocumentscorrectly

HerewecanseethatMarshalalsoreceivesavparameteroftypeinterfaceSowhataretheruleswhenmarshallingtoanXMLdocument

IfvisanarrayorsliceitprintsallelementslikeavalueIfvisapointeritprintsthecontentthatvispointingtoprintingnothingwhenvisnilIfvisainterfaceitdealwiththeinterfaceaswellIfvisoneoftheothertypesitprintsthevalueofthattype

SohowdoesxmlMarshaldecidetheelementsnameItfollowstheensuingrules

IfvisastructitdefinesthenameinthetagofXMLNameThefieldnameisXMLNameandthetypeisxmlNameFieldtaginstructFieldnameinstructTypenameofmarshal

XML

155

ThenweneedtofigureouthowtosettagsinordertoproducethefinalXMLdocument

XMLNamewillnotbeprintedFieldsthathavetagscontaining-willnotbeprintedIfatagcontainsnameattritusesnameastheattributenameandthefieldvalueasthevaluelikeversionintheaboveexampleIfatagcontainsattritusesthefieldsnameastheattributenameandthefieldvalueasitsvalueIfatagcontainschardataitprintscharacterdatainsteadofelementIfatagcontainsinnerxmlitprintstherawvalueIfatagcontainscommentitprintsitasacommentwithoutescapingsoyoucannothave--initsvalueIfatagcontainsomitemptyitomitsthisfieldifitsvalueiszero-valueincludingfalse0nilpointerornilinterfacezerolengthofarrayslicemapandstringIfatagcontainsagtbgtcitprintsthreeelementswhereacontainsbandbcontainsclikeinthefollowingcode `xmlFirstNamestringxmlnamegtfirstLastNamestringxmlnamegtlast`

Asta

Xieltnamegt```YoumayhavenoticedthatstructtagsareveryusefulfordealingwithXMLandthesamegoesfortheotherdataformatswellbediscussinginthefollowingsectionsIfyoustillfindthatyouhaveproblemswithworkingwithstructtagsyoushouldprobablyreadmoredocumentationaboutthembeforedivingintothenextsection

LinksDirectoryPrevioussectionTextfilesNextsectionJSON

XML

156

72JSONJSON(JavaScriptObjectNotation)isalightweightdataexchangelanguagewhichisbasedontextdescriptionItsadvantagesincludebeingself-descriptiveeasytounderstandetcEventhoughitisasubsetofJavaScriptJSONusesadifferenttextformattheresultbeingthatitcanbeconsideredasanindependentlanguageJSONbearssimilaritytoC-familylanguages

ThebiggestdifferencebetweenJSONandXMListhatXMLisacompletemarkuplanguagewhereasJSONisnotJSONissmallerandfasterthanXMLthereforeitsmucheasierandquickertoparseinbrowserswhichisoneofthereasonswhymanyopenplatformschoosetouseJSONastheirdataexchangeinterfacelanguage

SinceJSONisbecomingmoreandmoreimportantinwebdevelopmentletstakealookatthelevelofsupportGohasforJSONYoullfindthatGosstandardlibraryhasverygoodsupportforencodinganddecodingJSON

HereweuseJSONtorepresenttheexampleintheprevioussection

servers[serverNameShanghai_VPNserverIP127001serverNameBeijing_VPNserverIP127002]

TherestofthissectionwillusethisJSONdatatointroduceJSONconceptsinGo

ParseJSON

Parsetostruct

SupposewehavetheJSONintheaboveexampleHowcanweparsethisdataandmapittoastructinGoGoprovidesthefollowingfunctionforjustthispurpose

funcUnmarshal(data[]bytevinterface)error

Wecanusethisfunctionlikeso

packagemain

import(

encodingjson

fmt

)

typeServerstruct

ServerNamestring

ServerIPstring

typeServerslicestruct

Servers[]Server

funcmain()

varsServerslice

str=`servers[serverNameShanghai_VPNserverIP127001serverNameBeijing_VPNserverIP

127002]`

jsonUnmarshal([]byte(str)amps)

fmtPrintln(s)

JSON

157

IntheaboveexamplewedefinedacorrespondingstructsinGoforourJSONusingsliceforanarrayofJSONobjectsandfieldnameasourJSONkeysButhowdoesGoknowwhichJSONobjectcorrespondstowhichspecificstructfiledSupposewehaveakeycalledFooinJSONHowdowefinditscorrespondingfield

FirstGotriestofindthe(capitalised)exportedfieldwhosetagcontainsFooIfnomatchcanbefoundlookforthefieldwhosenameisFooIftherearestillnotmatcheslookforsomethinglikeFOOorFoOignoringcasesensitivity

YoumayhavenoticedthatallfieldsthataregoingtobeassignedshouldbeexportedandGoonlyassignsfieldsthatcanbefoundignoringallothersThiscanbeusefulifyouneedtodealwithlargechunksofJSONdatabutyouonlyaspecificsubsetofitthedatayoudontneedcaneasilybediscarded

ParsetointerfaceWhenweknowwhatkindofJSONtoexpectinadvancewecanparseittoaspecificstructButwhatifwedontknow

WeknowthataninterfacecanbeanythinginGosoitisthebestcontainertosaveourJSONofunknownformatTheJSONpackageusesmap[string]interfaceand[]interfacetosaveallkindsofJSONobjectsandarraysHereisalistofJSONmappingrelations

boolrepresentsJSONbooleansfloat64representsJSONnumbersstringrepresentsJSONstringsnilrepresentsJSONnull

SupposewehavethefollowingJSONdata

b=[]byte(`NameWednesdayAge6Parents[GomezMorticia]`)

NowweparsethisJSONtoaninterface

varfinterface

err=jsonUnmarshal(bampf)

Thefstoresamapwherekeysarestringsandvaluesareinterfaces

f=map[string]interface

NameWednesday

Age6

Parents[]interface

Gomez

Morticia

SohowdoweaccessthisdataTypeassertion

m=f(map[string]interface)

Afterassertedyoucanusethefollowingcodetoaccessdata

JSON

158

forkv=rangem

switchvv=v(type)

casestring

fmtPrintln(kisstringvv)

caseint

fmtPrintln(kisintvv)

casefloat64

fmtPrintln(kisfloat64vv)

case[]interface

fmtPrintln(kisanarray)

foriu=rangevv

fmtPrintln(iu)

default

fmtPrintln(kisofatypeIdontknowhowtohandle)

AsyoucanseewecannowparseJSONofanunknownformatthroughinterfaceandtypeassertion

TheaboveexampleistheofficialsolutionbuttypeassertingisnotalwaysconvenientSoIrecommendanopensourceprojectcalledsimplejsoncreatedandmaintainedbybitlyHereisanexampleofhowtousethisprojecttodealwithJSONofanunknownformat

jserr=NewJson([]byte(`

test

array[123]

int10

float5150

bignum9223372036854775807

stringsimplejson

booltrue

`))

arr_=jsGet(test)Get(array)Array()

i_=jsGet(test)Get(int)Int()

ms=jsGet(test)Get(string)MustString()

ItsnothardtoseehowconvenientthisisCheckouttherepositorytoseemoreinformationhttpsgithubcombitlygo-simplejson

ProducingJSONInmanysituationsweneedtoproduceJSONdataandrespondtoclientsInGotheJSONpackagehasafunctioncalledMarshaltodojustthat

funcMarshal(vinterface)([]byteerror)

SupposeweneedtoproduceaserverinformationlistWehavefollowingsample

JSON

159

packagemain

import(

encodingjson

fmt

)

typeServerstruct

ServerNamestring

ServerIPstring

typeServerslicestruct

Servers[]Server

funcmain()

varsServerslice

sServers=append(sServersServerServerNameShanghai_VPNServerIP127001)

sServers=append(sServersServerServerNameBeijing_VPNServerIP127002)

berr=jsonMarshal(s)

iferr=nil

fmtPrintln(jsonerrerr)

fmtPrintln(string(b))

Output

Servers[ServerNameShanghai_VPNServerIP127001ServerNameBeijing_VPNServerIP127002]

AsyouknowallfieldnamesarecapitalizedbutifyouwantyourJSONkeynamestostartwithalowercaseletteryoushouldusestructtagsOtherwiseGowillnotproducedataforinternalfields

typeServerstruct

ServerNamestring`jsonserverName`

ServerIPstring`jsonserverIP`

typeServerslicestruct

Servers[]Server`jsonservers`

AfterthismodificationwecanproducethesameJSONdataasbefore

HerearesomepointsyouneedtokeepinmindwhentryingtoproduceJSON

Fieldtagscontaining-willnotbeoutputtedIfatagcontainsacustomizednameGousesthisinsteadofthefieldnamelikeserverNameintheaboveexampleIfatagcontainsomitemptythisfieldwillnotbeoutputtedifitiszero-valueIfthefieldtypeisboolstringintint64etcanditstagcontainsstringGoconvertsthisfieldtoitscorrespondingJSONtype

Example

JSON

160

typeServerstruct

IDwillnotbeoutputed

IDint`json-`

ServerName2willbeconvertedtoJSONtype

ServerNamestring`jsonserverName`

ServerName2string`jsonserverName2string`

IfServerIPisemptyitwillnotbeoutputted

ServerIPstring`jsonserverIPomitempty`

s=Server

ID3

ServerName`Go10`

ServerName2`Go10`

ServerIP``

b_=jsonMarshal(s)

osStdoutWrite(b)

Output

serverNameGo10serverName2Go10

TheMarshalfunctiononlyreturnsdatawhenithassucceededsoherearesomepointsweneedtokeepinmind

JSONonlysupportsstringsaskeyssoifyouwanttoencodeamapitstypehastobemap[string]TwhereTisthetypeinGoTypeslikechannelcomplextypesandfunctionsarenotcapableofbeingencodedtoJSONDonottrytoencodecyclicdataitleadstoaninfiniterecursionIfthefieldisapointerGooutputsthedatathatitpointstoorelseoutputsnullifitpointstonil

InthissectionweintroducedhowtodecodeandencodeJSONdatainGoWealsolookedatonethird-partyprojectcalledsimplejsonwhichisusefulforparsingJSONorunknownformatTheseareallusefulconceptsfordevelopingwebapplicationsinGo

LinksDirectoryPrevioussectionXMLNextsectionRegexp

JSON

161

73RegexpRegularExpressions(Regexp)isacomplicatedbutpowerfultoolforpatternmatchingandtextmanipulationAlthoughitdoesnotperformaswellaspuretextmatchingitsmoreflexibleBasedonitssyntaxyoucanfilteralmostanykindoftextfromyoursourcecontentIfyouneedtocollectdatainwebdevelopmentitsnotdifficulttouseRegexptoretrievemeaningfuldata

GohastheregexppackagewhichprovidesofficialsupportforregexpIfyouvealreadyusedregexpinotherprogramminglanguagesyoushouldbefamiliarwithitNotethatGoimplementedRE2standardexceptforCFormoredetailsfollowthislinkhttpcodegooglecompre2wikiSyntax

Gosstringspackagecanactuallydomanyjobslikesearching(ContainsIndex)replacing(Replace)parsing(SplitJoin)etcanditsfasterthanRegexpHoweverthesearealltrivialoperationsIfyouwanttosearchacaseinsensitivestringRegexpshouldbeyourbestchoiceSoifthestringspackageissufficientforyourneedsjustuseitsinceitseasytouseandreadifyouneedtoperformmoreadvancedoperationsuseRegexp

IfyourecallformvalidationfromprevioussectionsweusedRegexptoverifythevalidityofuserinputinformationBeawarethatallcharactersareUTF-8LetslearnmoreabouttheGoregexppackage

MatchTheregexppackagehas3functionstomatchifitmatchesapatternthenitreturnstruereturningfalseotherwise

funcMatch(patternstringb[]byte)(matchedboolerrorerror)

funcMatchReader(patternstringrioRuneReader)(matchedboolerrorerror)

funcMatchString(patternstringsstring)(matchedboolerrorerror)

All3functionscheckifpatternmatchestheinputsourcereturningtrueifitmatchesHoweverifyourRegexhassyntaxerrorsitwillreturnanerrorThe3inputsourcesofthesefunctionsaresliceofbyteRuneReaderandstring

HereisanexampleofhowtoverifyanIPaddress

funcIsIP(ipstring)(bbool)

ifm_=regexpMatchString(^[0-9]13[0-9]13[0-9]13[0-9]13$ip)m

returnfalse

returntrue

AsyoucanseeusingpatternintheregexppackageisnotthatdifferentHeresonemoreexampleonverifyingwhetheruserinputisvalid

funcmain()

iflen(osArgs)==1

fmtPrintln(Usageregexp[string])

osExit(1)

elseifm_=regexpMatchString(^[0-9]+$osArgs[1])m

fmtPrintln(Number)

else

fmtPrintln(Notnumber)

IntheaboveexamplesweuseMatch(Reader|String)tocheckifcontentisvalidbuttheyarealleasytouse

Regexp

162

FilterMatchmodecanverifycontentbutitcannotcutfilterorcollectdatafromitIfyouwanttodothatyouhavetousethecomplexmodeofRegexp

LetssayweneedtowriteacrawlerHereisanexampleforwhenyoumustuseRegexptofilterandcutdata

packagemain

import(

fmt

ioioutil

nethttp

regexp

strings

)

funcmain()

resperr=httpGet(httpwwwbaiducom)

iferr=nil

fmtPrintln(httpgeterror)

deferrespBodyClose()

bodyerr=ioutilReadAll(respBody)

iferr=nil

fmtPrintln(httpreaderror)

return

src=string(body)

ConvertHTMLtagstolowercase

re_=regexpCompile(lt[Ss]+gt)

src=reReplaceAllStringFunc(srcstringsToLower)

RemoveSTYLE

re_=regexpCompile(ltstyle[Ss]+ltstylegt)

src=reReplaceAllString(src)

RemoveSCRIPT

re_=regexpCompile(ltscript[Ss]+ltscriptgt)

src=reReplaceAllString(src)

RemoveallHTMLcodeinanglebracketsandreplacewithnewline

re_=regexpCompile(lt[Ss]+gt)

src=reReplaceAllString(srcn)

Removecontinuousnewline

re_=regexpCompile(s2)

src=reReplaceAllString(srcn)

fmtPrintln(stringsTrimSpace(src))

InthisexampleweuseCompileasthefirststepforcomplexmodeItverifiesthatyourRegexsyntaxiscorrectthenreturnsaRegexpforparsingcontentinotheroperations

HerearesomefunctionstoparseyourRegexpsyntax

funcCompile(exprstring)(Regexperror)

funcCompilePOSIX(exprstring)(Regexperror)

funcMustCompile(strstring)Regexp

funcMustCompilePOSIX(strstring)Regexp

Regexp

163

ThedifferencebetweenComplePOSIXandCompileisthattheformerhastousePOSIXsyntaxwhichisleftmostlongestsearchandthelatterisonlyleftmostsearchForinstanceforRegexp[a-z]24andcontentaa09aaa88aaaaCompilePOSIXreturnsaaaabutCompilereturnsaaMustprefixmeanspanicwhentheRegexpsyntaxisnotcorrectreturningerrorotherwise

NowthatweknowhowtocreateanewRegexpletsseehowthemethodsprovidedbythisstructcanhelpustooperateoncontent

func(reRegexp)Find(b[]byte)[]byte

func(reRegexp)FindAll(b[]bytenint)[][]byte

func(reRegexp)FindAllIndex(b[]bytenint)[][]int

func(reRegexp)FindAllString(sstringnint)[]string

func(reRegexp)FindAllStringIndex(sstringnint)[][]int

func(reRegexp)FindAllStringSubmatch(sstringnint)[][]string

func(reRegexp)FindAllStringSubmatchIndex(sstringnint)[][]int

func(reRegexp)FindAllSubmatch(b[]bytenint)[][][]byte

func(reRegexp)FindAllSubmatchIndex(b[]bytenint)[][]int

func(reRegexp)FindIndex(b[]byte)(loc[]int)

func(reRegexp)FindReaderIndex(rioRuneReader)(loc[]int)

func(reRegexp)FindReaderSubmatchIndex(rioRuneReader)[]int

func(reRegexp)FindString(sstring)string

func(reRegexp)FindStringIndex(sstring)(loc[]int)

func(reRegexp)FindStringSubmatch(sstring)[]string

func(reRegexp)FindStringSubmatchIndex(sstring)[]int

func(reRegexp)FindSubmatch(b[]byte)[][]byte

func(reRegexp)FindSubmatchIndex(b[]byte)[]int

These18methodsincludeidenticalfunctionsfordifferentinputsources(byteslicestringandioRuneReader)sowecanreallysimplifythislistbyignoringinputsourcesasfollows

func(reRegexp)Find(b[]byte)[]byte

func(reRegexp)FindAll(b[]bytenint)[][]byte

func(reRegexp)FindAllIndex(b[]bytenint)[][]int

func(reRegexp)FindAllSubmatch(b[]bytenint)[][][]byte

func(reRegexp)FindAllSubmatchIndex(b[]bytenint)[][]int

func(reRegexp)FindIndex(b[]byte)(loc[]int)

func(reRegexp)FindSubmatch(b[]byte)[][]byte

func(reRegexp)FindSubmatchIndex(b[]byte)[]int

Codesample

Regexp

164

packagemain

import(

fmt

regexp

)

funcmain()

a=IamlearningGolanguage

re_=regexpCompile([a-z]24)

Findthefirstmatch

one=reFind([]byte(a))

fmtPrintln(Findstring(one))

Findallmatchesandsavetoaslicenlessthan0meansreturnallmatchesindicateslengthofsliceifit

sgreaterthan0

all=reFindAll([]byte(a)-1)

fmtPrintln(FindAllall)

Findindexoffirstmatchstartandendposition

index=reFindIndex([]byte(a))

fmtPrintln(FindIndexindex)

Findindexofallmatchesthendoessamejobasabove

allindex=reFindAllIndex([]byte(a)-1)

fmtPrintln(FindAllIndexallindex)

re2_=regexpCompile(am()lang())

Findfirstsubmatchandreturnarraythefirstelementcontainsallelementsthesecondelementcontainsthe

resultoffirst()thethirdelementcontainstheresultofsecond()

Output

thefirstelementamlearningGolanguage

thesecondelementlearningGonoticespaceswillbeoutputedaswell

thethirdelementuage

submatch=re2FindSubmatch([]byte(a))

fmtPrintln(FindSubmatchsubmatch)

for_v=rangesubmatch

fmtPrintln(string(v))

SameasFindIndex()

submatchindex=re2FindSubmatchIndex([]byte(a))

fmtPrintln(submatchindex)

FindAllSubmatchfindallsubmatches

submatchall=re2FindAllSubmatch([]byte(a)-1)

fmtPrintln(submatchall)

FindAllSubmatchIndexfindindexofallsubmatches

submatchallindex=re2FindAllSubmatchIndex([]byte(a)-1)

fmtPrintln(submatchallindex)

AswevepreviouslymentionedRegexpalsohas3methodsformatchingTheydotheexactsamethingastheexportedfunctionsInfactthoseexportedfunctionsactuallycallthesemethodsunderthehood

func(reRegexp)Match(b[]byte)bool

func(reRegexp)MatchReader(rioRuneReader)bool

func(reRegexp)MatchString(sstring)bool

NextletsseehowtoreplacestringsusingRegexp

Regexp

165

func(reRegexp)ReplaceAll(srcrepl[]byte)[]byte

func(reRegexp)ReplaceAllFunc(src[]bytereplfunc([]byte)[]byte)[]byte

func(reRegexp)ReplaceAllLiteral(srcrepl[]byte)[]byte

func(reRegexp)ReplaceAllLiteralString(srcreplstring)string

func(reRegexp)ReplaceAllString(srcreplstring)string

func(reRegexp)ReplaceAllStringFunc(srcstringreplfunc(string)string)string

Theseareusedinthecrawlingexamplesowewillnotexplainanyfurtherhere

LetstakealookatthedefinitionofExpand

func(reRegexp)Expand(dst[]bytetemplate[]bytesrc[]bytematch[]int)[]byte

func(reRegexp)ExpandString(dst[]bytetemplatestringsrcstringmatch[]int)[]byte

SohowdoweuseExpand

funcmain()

src=[]byte(`

callhelloalice

hellobob

callhelloeve

`)

pat=regexpMustCompile(`(m)(call)s+(Pltcmdgtw+)s+(Pltarggt+)s$`)

res=[]byte

for_s=rangepatFindAllSubmatchIndex(src-1)

res=patExpand(res[]byte($cmd($arg)n)srcs)

fmtPrintln(string(res))

AtthispointyouvelearntthewholeregexppackageinGoIhopethatyoucanunderstandmorebystudyingexamplesofkeymethodssothatyoucandosomethinginterestingonyourown

LinksDirectoryPrevioussectionJSONNextsectionTemplates

Regexp

166

74Templates

WhatisatemplateHopefullyyoureawareoftheMVC(ModelViewController)designmodelwheremodelsprocessdataviewsshowtheresultsandfinallycontrollershandleuserrequestsForviewsmanydynamiclanguagesgeneratedatabywritingcodeinstaticHTMLfilesForinstanceJSPisimplementedbyinsertinglt==gtPHPbyinsertingltphpgtetc

Thefollowingdemonstratesthetemplatemechanism

Figure71Templatemechanism

MostofthecontentthatwebapplicationsrespondtoclientswithisstaticandthedynamicpartsareusuallyverysmallForexampleifyouneedtodisplayalistuserswhohavevisitedapageonlytheusernamewouldbedynamicThestyleofthelistremainsthesameAsyoucanseetemplatesareusefulforreusingstaticcontent

TemplatinginGoInGowehavethetemplatepackagetohelphandletemplatesWecanusefunctionslikeParseParseFileandExecutetoloadtemplatesfromplaintextorfilesthenevaluatethedynamicpartsasshowninfigure71

Example

funchandler(whttpResponseWriterrhttpRequest)

t=templateNew(sometemplate)Createatemplate

t_=tParseFiles(tmplwelcomehtmlnil)Parsetemplatefile

user=GetUser()Getcurrentuserinfomration

tExecute(wuser)merge

AsyoucanseeitsveryeasytouseloadandrenderdataintemplatesinGojustasinotherprogramminglanguages

Forthesakeofconveniencewewillusethefollowingrulesinourexamples

UseParsetoreplaceParseFilesbecauseParsecantestcontentdirectlyfromstringssowedontneedanyextrafilesUsemainforeveryexampleanddonotusehandlerUseosStdouttoreplacehttpResponseWritersinceosStdoutalsoimplementstheioWriterinterface

InsertingdataintoatemplateWevejustshownyouhowtoparseandrendertemplatesLetstakeitonestepfurtherandrenderdatatoourtemplatesEverytemplateisanobjectinGosohowdoweinsertfieldstotemplates

Fields

InGoEveryfieldthatyouintendtoberenderedwithinatemplateshouldbeputinsideofisshorthandforthecurrentobjectwhichissimilartoitsJavaorC++counterpartIfyouwanttoaccessthefieldsofthecurrentobjectyoushoulduseFieldNameNoticethatonlyexportedfieldscanbeaccessedintemplatesHereisanexample

Templates

167

packagemain

import(

htmltemplate

os

)

typePersonstruct

UserNamestring

funcmain()

t=templateNew(fieldnameexample)

t_=tParse(helloUserName)

p=PersonUserNameAstaxie

tExecute(osStdoutp)

TheaboveexampleoutputshelloAstaxiecorrectlybutifwemodifyourstructalittlebitthefollowingerroremerges

typePersonstruct

UserNamestring

emailstringFieldisnotexported

t_=tParse(helloUserNameemail)

ThispartofthecodewillnotbecompiledbecausewetrytoaccessafieldthathasnotbeenexportedHoweverifwetrytouseafieldthatdoesnotexistGosimplyoutputsanemptystringinsteadofanerror

IfyouprintinatemplateGooutputsaformattedstringofthisobjectcallingfmtunderthecovers

Nestedfields

WeknowhowtooutputafieldnowWhatifthefieldisanobjectanditalsohasitsownfieldsHowdoweprintthemallinoneloopWecanusewithhelliphellipendandrangehellipendforexactlythatpurpose

rangejustlikerangeinGowithletsyouwritethesameobjectnameonceanduseasshorthandforit(SimilartowithinVB)

Moreexamples

Templates

168

packagemain

import(

htmltemplate

os

)

typeFriendstruct

Fnamestring

typePersonstruct

UserNamestring

Emails[]string

Friends[]Friend

funcmain()

f1=FriendFnameminuxma

f2=FriendFnamexushiwei

t=templateNew(fieldnameexample)

t_=tParse(`helloUserName

rangeEmails

anemail

end

withFriends

range

myfriendnameisFname

end

end

`)

p=PersonUserNameAstaxie

Emails[]stringastaxiebeegomeastaxiegmailcom

Friends[]Friendampf1ampf2

tExecute(osStdoutp)

ConditionsIfyouneedtocheckforconditionsintemplatesyoucanusetheif-elsesyntaxjustlikeyoudoinregularGoprogramsIfthepipelineisemptythedefaultvalueofifisfalseThefollowingexampleshowshowtouseif-elseintemplates

packagemain

import(

os

texttemplate

)

funcmain()

tEmpty=templateNew(templatetest)

tEmpty=templateMust(tEmptyParse(Emptypipelineifdemoif``willnotbeoutputtedendn))

tEmptyExecute(osStdoutnil)

tWithValue=templateNew(templatetest)

tWithValue=templateMust(tWithValueParse(Notemptypipelineifdemoif`anything`willbeoutputtede

ndn))

tWithValueExecute(osStdoutnil)

tIfElse=templateNew(templatetest)

tIfElse=templateMust(tIfElseParse(if-elsedemoif`anything`ifpartelseelsepartendn))

tIfElseExecute(osStdoutnil)

Asyoucanseeitseasytouseif-elseintemplates

Templates

169

AttentionYouCANNOTuseconditionalexpressionsinifforinstanceMail==astaxiegmailcomOnlybooleanvaluesareacceptable

pipelines

Unixusersshouldbefamiliarwiththepipeoperatorlikels|grepbeegoThiscommandfiltersfilesandonlyshowsthosethatcontainthewordbeegoOnethingthatIlikeaboutGotemplatesisthattheysupportpipesAnythingincanbethedataofpipelinesThee-mailweusedabovecanrenderourapplicationvulnerabletoXSSattacksHowcanweaddressthisissueusingpipes

|html

Wecanusethismethodtoescapethee-mailbodytoHTMLItsquitesimilartowritingaUnixcommandanditisconvenientforuseintemplatefunctions

TemplatevariablesSometimesweneedtouselocalvariablesintemplatesWecanusethemwiththewithrangeandifkeywordsandtheirscopeisbetweenthesekeywordsandendHeresanexampleofdeclaringaglobalvariable

$variable=pipeline

Moreexamples

with$x=output|printfq$xend

with$x=outputprintfq$xend

with$x=output$x|printfqend

Templatefunctions

GousesthefmtpackagetoformatoutputintemplatesbutsometimesweneedtodosomethingelseForexampleconsiderthefollowingscenarioletssaywewanttoreplacewithatinoure-mailaddresslikeastaxieatbeegomeAtthispointwehavetowriteacustomizedfunction

EverytemplatefunctionhasauniquenameandisassociatedwithonefunctioninyourGoprogramasfollows

typeFuncMapmap[string]interface

SupposewehaveanemailDealtemplatefunctionassociatedwithitsEmailDealWithcounterpartfunctioninourGoprogramWecanusethefollowingcodetoregisterthisfunction

t=tFuncs(templateFuncMapemailDealEmailDealWith)

EmailDealWithdefinition

funcEmailDealWith(argshellipinterface)string

Example

Templates

170

packagemain

import(

fmt

htmltemplate

os

strings

)

typeFriendstruct

Fnamestring

typePersonstruct

UserNamestring

Emails[]string

Friends[]Friend

funcEmailDealWith(argsinterface)string

ok=false

varsstring

iflen(args)==1

sok=args[0](string)

ifok

s=fmtSprint(args)

findthesymbol

substrs=stringsSplit(s)

iflen(substrs)=2

returns

replacethebyat

return(substrs[0]+at+substrs[1])

funcmain()

f1=FriendFnameminuxma

f2=FriendFnamexushiwei

t=templateNew(fieldnameexample)

t=tFuncs(templateFuncMapemailDealEmailDealWith)

t_=tParse(`helloUserName

rangeEmails

anemails|emailDeal

end

withFriends

range

myfriendnameisFname

end

end

`)

p=PersonUserNameAstaxie

Emails[]stringastaxiebeegomeastaxiegmailcom

Friends[]Friendampf1ampf2

tExecute(osStdoutp)

Hereisalistofbuilt-intemplatefunctions

Templates

171

varbuiltins=FuncMap

andand

callcall

htmlHTMLEscaper

indexindex

jsJSEscaper

lenlength

notnot

oror

printfmtSprint

printffmtSprintf

printlnfmtSprintln

urlqueryURLQueryEscaper

MustThetemplatepackagehasafunctioncalledMustwhichisforvalidatingtemplateslikethematchingofbracescommentsandvariablesLetstakealookatanexampleofMust

packagemain

import(

fmt

texttemplate

)

funcmain()

tOk=templateNew(first)

templateMust(tOkParse(somestatictextandacomment))

fmtPrintln(ThefirstoneparsedOK)

templateMust(templateNew(second)Parse(somestatictextName))

fmtPrintln(ThesecondoneparsedOK)

fmtPrintln(Thenextoneoughttofail)

tErr=templateNew(checkparseerrorwithMust)

templateMust(tErrParse(somestatictextName))

Output

ThefirstoneparsedOK

ThesecondoneparsedOK

Thenextoneoughttofail

panictemplatecheckparseerrorwithMust1unexpectedincommand

NestedtemplatesJustlikeinmostwebapplicationscertainpartsoftemplatescanbereusedacrossothertemplatesliketheheadersandfootersofablogWecandeclareheadercontentandfooterassub-templatesanddeclaretheminGousingthefollowingsyntax

definesub-templatecontentend

Thesub-templateiscalledusingthefollowingsyntax

templatesub-template

Templates

172

Heresacompleteexamplesupposingthatwehavethefollowingthreefilesheadertmplcontenttmplandfootertmplinthefoldertemplateswewillreadthefolderandstorethefilenamesinastringarraywhichwewillthenusetoparsefiles

Maintemplate

raw

headertmpl

defineheader

lthtmlgt

ltheadgt

lttitlegtSomethingherelttitlegt

ltheadgt

ltbodygt

end

contenttmpl

definecontent

templateheader

lth1gtNestedherelth1gt

ltulgt

ltligtNestedusagltligt

ltligtCalltemplateltligt

ltulgt

templatefooter

end

footertmpl

definefooter

ltbodygt

lthtmlgt

end

Whenusingsubtemplatingmakesurethatyouhaveparsedeachsubtemplatefile

otherwisethecompilerwouldntunderstandwhattosubstitutewhenitreadsthetemplateheader

endraw

Code

Templates

173

packagemain

import(

fmt

os

ioioutil

texttemplate

)

vartemplatestemplateTemplate

funcmain()

varallFiles[]string

fileserr=ioutilReadDir(templates)

iferr=nil

fmtPrintln(err)

for_file=rangefiles

filename=fileName()

ifstringsHasSuffix(filenametmpl)

allFiles=append(allFilestemplates+filename)

templateserr=templateParseFiles(allFiles)parsesalltmplfilesinthetemplatesfolder

s1=templatesLookup(headertmpl)

s1ExecuteTemplate(osStdoutheadernil)

fmtPrintln()

s2=templatesLookup(contenttmpl)

s2ExecuteTemplate(osStdoutcontentnil)

fmtPrintln()

s3=templatesLookup(footertmpl)

s3ExecuteTemplate(osStdoutfooternil)

fmtPrintln()

s3Execute(osStdoutnil)

HerewecanseethattemplateParseFilesparsesallnestedtemplatesintocacheandthateverytemplatedefinedbydefineareindependentofeachotherTheyarepersistedinsomethinglikeamapwherethetemplatenamesarekeysandthevaluesarethetemplatebodiesWecanthenuseExecuteTemplatetoexecutethecorrespondingsub-templatessothattheheaderandfooterareindependentandcontentcontainsthembothNotethatifwetrytoexecutes1Executenothingwillbeoutputtedbecausethereisnodefaultsub-templateavailable

Whenyoudontwanttousedefinethenyoucanjustcreateatextfilewiththenameofthesubtemplateforinstance_headtmplisasubtemplatewhichyoulluseacrossyourprojectthencreatethisfileinthetemplatesfolderandusethenormalsyntaxLookupcacheisbasicallycreatedsothatyoudontreadthefileeverytimeyouservearequestbecauseifyoudothenyouarewastingalotofresourcesforreadingafilewhichwontchangeunlessthecodebaseisbeingrewrittenitdoesntmakesensetoparsethetemplatefilesduringeachHTTPGETrequestsothetechniqueisusedwhereweparsethefilesonceandthendoaLookup()onthecachetoexecutethetemplatewhenweneedittodisplaydata

Templatesinonesetknoweachotherbutyoumustparsethemforeverysingleset

Sometimesyouwanttocontextualizetemplatesforinstanceyouhavea_headhtmlyoumighthaveaheaderwhosvalueyouhavetopopulatebasedonwhichdatayouareloadingforinstanceforatodolistmanageryoucanhavethreecategoriespendingcompleteddeletedforthissupposeyouhaveanifstatementlikethis

lttitlegtifeqNavigationpendingTasks

elseifeqNavigationcompletedCompleted

elseifeqNavigationdeletedDeleted

elseifeqNavigationeditEdit

end

lttitlegt

Templates

174

NoteGotemplatesfollowthePolishnotationwhileperformingthecomparisonwhereyougivetheoperatorfirstandthecomparisonvalueandthevaluetobecomparedwithTheelseifpartisprettystraightforward

Typicallyweusearangeoperatortoloopthroughthecontextvariablewhichwepasstothetemplatewhileexecutionlikethis

presentinviewspackage

context=dbGetTasks(pending)truewhenyouwantnondeletednotes

homeTemplateExecute(wcontext)

Wegetthecontextobjectfromthedatabaseasastructobjectthedefinitionisasbelow

Taskisthestructusedtoidentifytasks

typeTaskstruct

Idint

Titlestring

Contentstring

Createdstring

Contextisthestructpassedtotemplates

typeContextstruct

Tasks[]Task

Navigationstring

Searchstring

Messagestring

presentindatabasepackage

vartask[]typesTask

varcontexttypesContext

context=typesContextTaskstaskNavigationstatus

Thislineisinthedatabasepackagewherethecontextisreturnedbacktotheview

WeusethetaskarrayandtheNavigationinourtemplateswesawhowweusetheNavigationinthetemplatewellseehowwellusetheactualtaskarrayinourtemplate

HereintheifTaskswefirstcheckiftheTasksfieldofourcontextobjectwhichwepassedtothetemplatewhileexecutingisemptyornotIfitisnotemptythenwewillrangethroughthatarraytopopulatethetitleandcontentofTaskThebelowexampleisveryimportantwhenitcomestoloopingthroughanarrayinatemplatewestartwiththeRangeoperatorthenwecangiveanymemberofthatstructasNamemyTaskstructurehasaTitleandaContent(pleasenotethecapitalTandCtheyareexportednamesandtheyneedtobecapitalisedunlessyouwanttomakethemprivate)

rangeTasks

Title

Content

end

ThisblockofcodewillprinteachtitleandcontentoftheTaskarrayBelowisafullexamplefromgithubcomthewhitetulipTaskshomehtmltemplate

Templates

175

ltdivclass=timelinegt

ifTasksrangeTasks

ltdivclass=notegt

ltpclass=noteHeadinggtTitleltpgt

lthrgt

ltpclass=noteContentgtContentltpgt

ltulgt

ltspangt

ltdivgt

endelse

ltdivclass=notegt

ltpclass=noteHeadinggtNoTaskshereltpgt

ltpclass=notefootergt

Createnewtaskltbuttonclass=floating-action-icon-addgthereltbuttongtltpgt

ltdivgt

end

SummaryInthissectionyoulearnedhowtocombinedynamicdatawithtemplatesusingtechniquesincludingprintingdatainloopstemplatefunctionsandnestedtemplatesBylearningabouttemplateswecanconcludediscussingtheV(View)partoftheMVCarchitectureInthefollowingchapterswewillcovertheM(Model)andC(Controller)aspectsofMVC

LinksDirectoryPrevioussectionRegexpNextsectionFiles

Templates

176

75FilesFilesareessentialobjectsoneverysinglecomputerdeviceItwontcomeasanysurprisetoyouthatwebapplicationsalsomakeheavyuseofthemInthissectionweregoingtolearnhowtooperateonfilesinGo

DirectoriesInGomostofthefileoperationfunctionsarelocatedintheospackageHerearesomedirectoryfunctions

funcMkdir(namestringpermFileMode)error

Createadirectorywithnamepermisthedirectorypermissionsie0777

funcMkdirAll(pathstringpermFileMode)error

Createmultipledirectoriesaccordingtopathlikeastaxietest1test2

funcRemove(namestring)error

RemovesdirectorywithnameReturnserrorifitsnotadirectoryornotempty

funcRemoveAll(pathstring)error

RemovesmultipledirectoriesaccordingtopathDirectorieswillnotbedeletedifpathisasinglepath

Codesample

packagemain

import(

fmt

os

)

funcmain()

osMkdir(astaxie0777)

osMkdirAll(astaxietest1test20777)

err=osRemove(astaxie)

iferr=nil

fmtPrintln(err)

osRemoveAll(astaxie)

Files

Createandopenfiles

Therearetwofunctionsforcreatingfiles

funcCreate(namestring)(fileFileerrError)

Createafilewithnameandreturnaread-writablefileobjectwithpermission0666

funcNewFile(fduintptrnamestring)File

Createafileandreturnafileobject

Therearealsotwofunctionstoopenfiles

funcOpen(namestring)(fileFileerrError)

Files

177

Opensafilecallednamewithread-onlyaccesscallingOpenFileunderthecovers

funcOpenFile(namestringflagintpermuint32)(fileFileerrError)

Opensafilecallednameflagisopenmodelikeread-onlyread-writeetcpermarethefilepermissions

WritefilesFunctionsforwritingfiles

func(fileFile)Write(b[]byte)(ninterrError)

Writebytetypecontenttoafile

func(fileFile)WriteAt(b[]byteoffint64)(ninterrError)

Writebytetypecontenttoaspecificpositionofafile

func(fileFile)WriteString(sstring)(retinterrError)

Writeastringtoafile

Codesample

packagemain

import(

fmt

os

)

funcmain()

userFile=astaxietxt

fouterr=osCreate(userFile)

iferr=nil

fmtPrintln(userFileerr)

return

deferfoutClose()

fori=0ilt10i++

foutWriteString(Justatestrn)

foutWrite([]byte(Justatestrn))

ReadfilesFunctionsforreadingfiles

func(fileFile)Read(b[]byte)(ninterrError)

Readdatatob

func(fileFile)ReadAt(b[]byteoffint64)(ninterrError)

Readdatafrompositionofftob

Codesample

Files

178

packagemain

import(

fmt

os

)

funcmain()

userFile=asatxietxt

flerr=osOpen(userFile)

iferr=nil

fmtPrintln(userFileerr)

return

deferflClose()

buf=make([]byte1024)

for

n_=flRead(buf)

if0==n

break

osStdoutWrite(buf[n])

DeletefilesGousesthesamefunctionforremovingfilesanddirectories

funcRemove(namestring)Error

Removeafileordirectorycalledname(anameendingwithsignifiesthatitsadirectory)

LinksDirectoryPrevioussectionTemplatesNextsectionStrings

Files

179

76StringsOnthewebalmosteverythingwesee(includinguserinputsdatabaseaccessetc)isrepresentedbystringsTheyareaveryimportantpartofwebdevelopmentInmanycaseswealsoneedtosplitjoinconvertandotherwisemanipulatestringsInthissectionwearegoingtointroducethestringsandstrconvpackagesfromtheGostandardlibrary

stringsThefollowingfunctionsarefromthestringspackageSeetheofficialdocumentationformoredetails

funcContains(ssubstrstring)bool

Checkifstringscontainsstringsubstrreturnsabooleanvalue```GofmtPrintln(stringsContains(seafoodfoo))fmtPrintln(stringsContains(seafoodbar))fmtPrintln(stringsContains(seafood))fmtPrintln(stringsContains())

Outputtruefalsetruetrue

-funcJoin(a[]stringsepstring)string

Combinestringsfromslicewithseparator`sep`

```Go

s=[]stringfoobarbaz

fmtPrintln(stringsJoin(s))

Outputfoobarbaz

funcIndex(ssepstring)int

Findindexofsepinstringsreturns-1ifitsnotfound

fmtPrintln(stringsIndex(chickenken))

fmtPrintln(stringsIndex(chickendmr))

Output4

-1

funcRepeat(sstringcountint)string

Repeatstringscounttimes

fmtPrintln(ba+stringsRepeat(na2))

Outputbanana

funcReplace(soldnewstringnint)string

ReplacestringoldwithstringnewinstringsnisthenumberofreplacementsIfnislessthan0replaceallinstances

fmtPrintln(stringsReplace(oinkoinkoinkkky2))

fmtPrintln(stringsReplace(oinkoinkoinkoinkmoo-1))

Outputoinkyoinkyoink

moomoomoo

funcSplit(ssepstring)[]string

Splitstringswithseparatorsepintoaslice

Strings

180

fmtPrintf(qnstringsSplit(abc))

fmtPrintf(qnstringsSplit(amanaplanacanalpanamaa))

fmtPrintf(qnstringsSplit(xyz))

fmtPrintf(qnstringsSplit(BernardoOHiggins))

Output[abc]

[manplancanalpanama]

[xyz]

[]

funcTrim(sstringcutsetstring)string

Removecutsetofstringsifitsleftmostorrightmost

fmtPrintf([q]stringsTrim(Achtung))

Output[Achtung]

funcFields(sstring)[]string

Removespaceitemsandsplitstringwithspaceintoaslice

fmtPrintf(FieldsareqstringsFields(foobarbaz))

OutputFieldsare[foobarbaz]

strconvThefollowingfunctionsarefromthestrconvpackageAsusualpleaseseeofficialdocumentationformoredetails

Appendseriesconvertdatatostringandappendtocurrentbyteslice```Gopackagemain

import(fmtstrconv)

funcmain()str=make([]byte0100)str=strconvAppendInt(str456710)str=strconvAppendBool(strfalse)str=strconvAppendQuote(strabcdefg)str=strconvAppendQuoteRune(str单)fmtPrintln(string(str))

-Formatseriesconvertotherdatatypesintostring

```Go

packagemain

import(

fmt

strconv

)

funcmain()

a=strconvFormatBool(false)

b=strconvFormatFloat(12323g1264)

c=strconvFormatInt(123410)

d=strconvFormatUint(1234510)

e=strconvItoa(1023)

fmtPrintln(abcde)

Parseseriesconvertstringstoothertypes```Gopackagemain

import(fmtstrconv)

funcmain()aerr=strconvParseBool(false)iferr=nilfmtPrintln(err)berr=strconvParseFloat(1232364)iferr=nilfmtPrintln(err)cerr=strconvParseInt(12341064)iferr=nilfmtPrintln(err)derr=strconvParseUint(123451064)iferr=nilfmtPrintln(err)eerr=strconvItoa(1023)iferr=nilfmtPrintln(err)fmtPrintln(abcde)```

Strings

181

LinksDirectoryPrevioussectionFilesNextsectionSummary

Strings

182

77SummaryInthischapterweintroducedsometextprocessingtoolslikeXMLJSONRegexpandwealsotalkedabouttemplatesXMLandJSONaredataexchangetoolsYoucanrepresentalmostanykindofinformationusingthesetwoformatsRegexpisapowerfultoolforsearchingreplacingandcuttingtextcontentWithtemplatesyoucaneasilycombinedynamicdatawithstaticfilesThesetoolsareallusefulwhendevelopingwebapplicationsIhopethatyounowhaveabetterunderstandingofprocessinganddisplayingcontentusingGo

LinksDirectoryPrevioussectionStringsNextchapterWebservices

Summary

183

8WebservicesWebservicesallowyouuseformatslikeXMLorJSONtoexchangeinformationthroughHTTPForexampleifyouwanttoknowtheweatherinShanghaitomorrowthecurrentsharepriceofAppleorproductinformationonAmazonyoucanwriteapieceofcodetofetchthatinformationfromopenplatformsInGothisprocesscanbecomparabletocallingalocalfunctionandgettingitsreturnvalue

ThekeypointisthatwebservicesareplatformindependentThisallowsyoutodeployyourapplicationsonLinuxandinteractwithASPNETapplicationsinWindowsforexamplejustlikeyouwouldnthaveaprobleminteractingwithJSPonFreeBSDeither

TheRESTarchitectureandSOAPprotocolarethemostpopularstylesinwhichwebservicescanbeimplementedthesedays

RESTrequestsareprettystraightforwardbecauseitsbasedonHTTPEveryRESTrequestisactuallyanHTTPrequestandservershandlerequestsusingdifferentmethodsBecausemanydevelopersarefamiliarwithHTTPalreadyRESTshouldfeellikeitsalreadyintheirbackpocketsWearegoingtoshowyouhowtoimplementRESTinGoinsection83SOAPisastandardforcross-networkinformationtransmissionandremotecomputerfunctioncallslaunchedbyW3CTheproblemwithSOAPisthatitsspecificationisverylongandcomplicatedanditsstillgettinglongerGobelievesthatthingsshouldbesimplesowerenotgoingtotalkaboutSOAPFortunatelyGoprovidessupportforRPC(RemoteProcedureCalls)whichhasgoodperformanceandiseasytodevelopwithsowewillintroducehowtoimplementRPCinGoinsection84

GoistheClanguageofthe21stcenturyaspiringtobesimpleyetperformantWiththesequalitiesinmindwellintroduceyoutosocketprogramminginGoinsection81Nowadaysmanyreal-timeserversusesocketstoovercomethelowperformanceofHTTPAlongwiththerapiddevelopmentofHTML5websocketsarenowusedbymanywebbasedgamecompaniesandwewilltalkaboutthismoreinsection82

LinksDirectoryPreviousChapterChapter7SummaryNextsectionSockets

Webservices

184

81SocketsSomenetworkapplicationdeveloperssaythatthelowerapplicationlayersareallaboutsocketprogrammingThismaynotbetrueforallcasesbutmanymodernwebapplicationsdoindeedusesocketstotheiradvantageHaveyoueverwonderedhowbrowserscommunicatewithwebserverswhenyouaresurfingtheinternetOrHowMSNconnectsyouandyourfriendstogetherinachatroomrelayingeachmessageinreal-timeManyservicesliketheseusesocketstotransferdataAsyoucanseesocketsoccupyanimportantpositioninnetworkprogrammingtodayandweregoingtolearnaboutusingsocketsinGointhissection

WhatisasocketSocketsoriginatefromUnixandgiventhebasiceverythingisafilephilosophyofUnixeverythingcanbeoperatedonwithopen-gtwriteread-gtcloseSocketsareoneimplementationofthisphilosophySocketshaveafunctioncallforopeningasocketjustlikeyouwouldopenafileThisreturnsanintdescriptorofthesocketwhichcanthenbeusedforoperationslikecreatingconnectionstransferringdataetc

Twotypesofsocketsthatarecommonlyusedarestreamsockets(SOCK_STREAM)anddatagramsockets(SOCK_DGRAM)Streamsocketsareconnection-orientedlikeTCPwhiledatagramsocketsdonotestablishconnectionslikeUDP

SocketcommunicationBeforeweunderstandhowsocketscommunicatewithoneanotherweneedtofigureouthowtomakesurethateverysocketisuniqueotherwiseestablishingareliablecommunicationchannelisalreadyoutofthequestionWecangiveeveryprocessauniquePIDwhichservesourpurposelocallyhoweverthatsnotabletoworkoveranetworkFortunatelyTCPIPhelpsussolvethisproblemTheIPaddressesofthenetworklayerareuniqueinanetworkofhostsandprotocol+portisalsouniqueamonghostapplicationsSowecanusetheseprinciplestomakesocketswhichareunique

Figure81networkprotocollayers

ApplicationsthatarebasedonTCPIPallusesocketAPIsintheircodeinonewayoranotherGiventhatnetworkedapplicationsarebecomingmoreandmoreprevalentinthemoderndayitsnowondersomedevelopersaresayingthateverythingisaboutsockets

SocketbasicknowledgeWeknowthatsocketshavetwotypeswhichareTCPsocketsandUDPsocketsTCPandUDPareprotocolsandasmentionedwealsoneedanIPaddressandportnumbertohaveauniquesocket

IPv4TheglobalinternetusesTCPIPasitsprotocolwhereIPisthenetworklayerandacorepartofTCPIPIPv4signifiesthatitsversionis4infrastructuredevelopmenttodatehasspannedover30years

ThenumberofbitsinanIPv4addressis32whichmeansthat2^32devicesareabletouniquelyconnecttotheinternetDuetotherapiddevelopoftheinternetIPaddressesarealreadyrunningoutofstockinrecentyears

Addressformat127001172122121111

IPv6

Sockets

185

IPv6isthenextversionornextgenerationoftheinternetItsbeingdevelopedforsolvingmanyoftheproblemsinherentwithIPv4DevicesusingIPv6haveanaddressthats128bitslongsowellneverneedtoworryaboutashortageofuniqueaddressesToputthisintoperspectiveyoucouldhavemorethan1000IPaddressesforeverysquaremeteronearthwithIPv6Otherproblemslikepeertopeerconnectionservicequality(QoS)securitymultiplebroadcastetcarealsobeimproved

Addressformat2002c0e882e7000c0e882e7

IPtypesinGo

ThenetpackageinGoprovidesmanytypesfunctionsandmethodsfornetworkprogrammingThedefinitionofIPasfollows

typeIP[]byte

FunctionParseIP(sstring)IPistoconverttheIPv4orIPv6formattoanIP

packagemain

import(

net

os

fmt

)

funcmain()

iflen(osArgs)=2

fmtFprintf(osStderrUsagesip-addrnosArgs[0])

osExit(1)

name=osArgs[1]

addr=netParseIP(name)

ifaddr==nil

fmtPrintln(Invalidaddress)

else

fmtPrintln(TheaddressisaddrString())

osExit(0)

ItreturnsthecorrespondingIPformatforagivenIPaddress

TCPsocketWhatcanwedowhenweknowhowtovisitawebservicethroughanetworkportAsaclientwecansendarequesttoanappointednetworkportandgetsitsresponseasaserverweneedtobindaservicetoanappointednetworkportwaitforclientsrequestsandsupplyaresponse

InGosnetpackagetheresatypecalledTCPConnthatfacilitatesthiskindofclientsserversinteractionThistypehastwokeyfunctions

func(cTCPConn)Write(b[]byte)(ninterrosError)

func(cTCPConn)Read(b[]byte)(ninterrosError)

TCPConncanbeusedbyeitherclientorserverforreadingandwritingdata

WealsoneedaTCPAddrtorepresentTCPaddressinformation

Sockets

186

typeTCPAddrstruct

IPIP

Portint

WeusetheResolveTCPAddrfunctiontogetaTCPAddrinGo

funcResolveTCPAddr(netaddrstring)(TCPAddrosError)

Argumentsofnetcanbeoneoftcp4tcp6ortcpwhicheachsignifyIPv4-onlyIPv6-onlyandeitherIPv4orIPv6respectivelyaddrcanbeadomainnameorIPaddresslikewwwgooglecom80or12700122

TCPclientGoclientsusetheDialTCPfunctioninthenetpackagetocreateaTCPconnectionwhichreturnsaTCPConnobjectafteraconnectionisestablishedtheserverhasthesametypeofconnectionobjectforthecurrentconnectionandclientandservercanbeginexchangingdatawithoneanotherIngeneralclientssendrequeststoserversthroughaTCPConnandreceiveinformationfromtheserverresponseserversreadandparseclientrequeststhenreturnfeedbackThisconnectionwillremainvaliduntileithertheclientorserverclosesitThefunctionforcreatingaconnectionisasfollows

funcDialTCP(netstringladdrraddrTCPAddr)(cTCPConnerrosError)

Argumentsofnetcanbeoneoftcp4tcp6ortcpwhicheachsignifyIPv4-onlyIPv6-onlyandeitherIPv4orIPv6respectivelyladdrrepresentsthelocaladdresssetittonilinmostcasesraddrrepresentstheremoteaddress

LetswriteasimpleexampletosimulateaclientrequestingaconnectiontoaserverbasedonanHTTPrequestWeneedasimpleHTTPrequestheader

HEADHTTP10rnrn

Serverresponseinformationformatmaylooklikethefollowing

HTTP10200OK

ETag-9985996

Last-ModifiedThu25Mar2010175110GMT

Content-Length18074

Connectionclose

DateSat28Aug2010004348GMT

Serverlighttpd1423

Clientcode

Sockets

187

packagemain

import(

fmt

ioioutil

net

os

)

funcmain()

iflen(osArgs)=2

fmtFprintf(osStderrUsageshostportosArgs[0])

osExit(1)

service=osArgs[1]

tcpAddrerr=netResolveTCPAddr(tcp4service)

checkError(err)

connerr=netDialTCP(tcpniltcpAddr)

checkError(err)

_err=connWrite([]byte(HEADHTTP10rnrn))

checkError(err)

resulterr=ioutilReadAll(conn)

checkError(err)

fmtPrintln(string(result))

osExit(0)

funccheckError(errerror)

iferr=nil

fmtFprintf(osStderrFatalerrorserrError())

osExit(1)

IntheaboveexampleweuseuserinputastheserviceargumentofnetResolveTCPAddrtogetatcpAddrPassingtcpAddrtotheDialTCPfunctionwecreateaTCPconnectionconnWecanthenuseconntosendrequestinformationtotheserverFinallyweuseioutilReadAlltoreadallthecontentfromconnwhichcontainstheserverresponse

TCPserver

WehaveaTCPclientnowWecanalsousethenetpackagetowriteaTCPserverOntheserversideweneedtobindourservicetoaspecificinactiveportandlistenforanyincomingclientrequests

funcListenTCP(netstringladdrTCPAddr)(lTCPListenererrosError)

func(lTCPListener)Accept()(cConnerrosError)

TheargumentsrequiredhereareidenticaltothoserequiredbytheDialTCPfunctionweusedearlierLetsimplementatimesyncingserviceusingport7777

Sockets

188

packagemain

import(

fmt

net

os

time

)

funcmain()

service=7777

tcpAddrerr=netResolveTCPAddr(tcp4service)

checkError(err)

listenererr=netListenTCP(tcptcpAddr)

checkError(err)

for

connerr=listenerAccept()

iferr=nil

continue

daytime=timeNow()String()

connWrite([]byte(daytime))dontcareaboutreturnvalue

connClose()werefinishedwiththisclient

funccheckError(errerror)

iferr=nil

fmtFprintf(osStderrFatalerrorserrError())

osExit(1)

AftertheserviceisstarteditwaitsforclientrequestsWhenitreceivesaclientrequestitAcceptsitandreturnsaresponsetotheclientcontaininginformationaboutthecurrenttimeItsworthnotingthatwhenerrorsoccurintheforlooptheservicecontinuesrunninginsteadofexitingInsteadofcrashingtheserverwillrecordtheerrortoaservererrorlog

TheabovecodeisstillnotgoodenoughhoweverWedidntmakeuseofgoroutineswhichwouldhaveallowedustoacceptsimultaneousrequestsLetsdothisnow

Sockets

189

packagemain

import(

fmt

net

os

time

)

funcmain()

service=1200

tcpAddrerr=netResolveTCPAddr(tcp4service)

checkError(err)

listenererr=netListenTCP(tcptcpAddr)

checkError(err)

for

connerr=listenerAccept()

iferr=nil

continue

gohandleClient(conn)

funchandleClient(connnetConn)

deferconnClose()

daytime=timeNow()String()

connWrite([]byte(daytime))dontcareaboutreturnvalue

werefinishedwiththisclient

funccheckError(errerror)

iferr=nil

fmtFprintf(osStderrFatalerrorserrError())

osExit(1)

ByseparatingoutourbusinessprocessfromthehandleClientfunctionandbyusingthegokeywordwevealreadyimplementedconcurrencyinourserviceThisisagooddemonstrationofthepowerandsimplicityofgoroutines

SomeofyoumaybethinkingthefollowingthisserverdoesnotdoanythingmeaningfulWhatifweneededtosendmultiplerequestsfordifferenttimeformatsoverasingleconnectionHowwouldwedothat

Sockets

190

packagemain

import(

fmt

net

os

time

strconv

)

funcmain()

service=1200

tcpAddrerr=netResolveTCPAddr(tcp4service)

checkError(err)

listenererr=netListenTCP(tcptcpAddr)

checkError(err)

for

connerr=listenerAccept()

iferr=nil

continue

gohandleClient(conn)

funchandleClient(connnetConn)

connSetReadDeadline(timeNow()Add(2timeMinute))set2minutestimeout

request=make([]byte128)setmaximumrequestlengthto128Btopreventfloodbasedattacks

deferconnClose()closeconnectionbeforeexit

for

read_lenerr=connRead(request)

iferr=nil

fmtPrintln(err)

break

ifread_len==0

breakconnectionalreadyclosedbyclient

elseifstring(request[read_len])==timestamp

daytime=strconvFormatInt(timeNow()Unix()10)

connWrite([]byte(daytime))

else

daytime=timeNow()String()

connWrite([]byte(daytime))

funccheckError(errerror)

iferr=nil

fmtFprintf(osStderrFatalerrorserrError())

osExit(1)

InthisexampleweuseconnRead()toconstantlyreadclientrequestsWecannotclosetheconnectionbecauseclientsmayissuemorethanonerequestDuetothetimeoutwesetusingconnSetReadDeadline()theconnectionclosesautomaticallyafterourallottedtimeperiodWhentheexpirytimehaselapsedourprogrambreaksfromtheforloopNoticethatrequestneedstobecreatedwithamaxsizelimitationinordertopreventfloodattacks

ControllingTCPconnections

ControllingTCPfunctions

funcDialTimeout(netaddrstringtimeouttimeDuration)(Connerror)

Sockets

191

SettingthetimeoutofconnectionsThesearesuitableforuseonbothclientsandservers

func(cTCPConn)SetReadDeadline(ttimeTime)error

func(cTCPConn)SetWriteDeadline(ttimeTime)error

Settingthewritereadtimeoutofoneconnection

func(cTCPConn)SetKeepAlive(keepalivebool)osError

ItsworthtakingsometimetothinkabouthowlongyouwantyourconnectiontimeoutstobeLongconnectionscanreducetheamountofoverheadinvolvedincreatingconnectionsandaregoodforapplicationsthatneedtoexchangedatafrequently

FormoredetailedinformationjustlookuptheofficialdocumentationforGosnetpackage

UDPsocketsTheonlydifferencebetweenaUDPsocketandaTCPsocketistheprocessingmethodfordealingwithmultiplerequestsonserversideThisarisesfromthefactthatUDPdoesnothaveafunctionlikeAcceptAlloftheotherfunctionshaveUDPcounterpartsjustreplaceTCPwithUDPinthefunctionsmentionedabove

funcResolveUDPAddr(netaddrstring)(UDPAddrosError)

funcDialUDP(netstringladdrraddrUDPAddr)(cUDPConnerrosError)

funcListenUDP(netstringladdrUDPAddr)(cUDPConnerrosError)

func(cUDPConn)ReadFromUDP(b[]byte)(nintaddrUDPAddrerrosError

func(cUDPConn)WriteToUDP(b[]byteaddrUDPAddr)(ninterrosError)

UDPclientcodesample

packagemain

import(

fmt

net

os

)

funcmain()

iflen(osArgs)=2

fmtFprintf(osStderrUsageshostportosArgs[0])

osExit(1)

service=osArgs[1]

udpAddrerr=netResolveUDPAddr(udp4service)

checkError(err)

connerr=netDialUDP(udpniludpAddr)

checkError(err)

_err=connWrite([]byte(anything))

checkError(err)

varbuf[512]byte

nerr=connRead(buf[0])

checkError(err)

fmtPrintln(string(buf[0n]))

osExit(0)

funccheckError(errerror)

iferr=nil

fmtFprintf(osStderrFatalerrorerrError())

osExit(1)

Sockets

192

UDPservercodesample

packagemain

import(

fmt

net

os

time

)

funcmain()

service=1200

udpAddrerr=netResolveUDPAddr(udp4service)

checkError(err)

connerr=netListenUDP(udpudpAddr)

checkError(err)

for

handleClient(conn)

funchandleClient(connnetUDPConn)

varbuf[512]byte

_addrerr=connReadFromUDP(buf[0])

iferr=nil

return

daytime=timeNow()String()

connWriteToUDP([]byte(daytime)addr)

funccheckError(errerror)

iferr=nil

fmtFprintf(osStderrFatalerrorerrError())

osExit(1)

SummaryThroughdescribingandcodingsomesimpleprogramsusingTCPandUDPsocketswecanseethatGoprovidesexcellentsupportforsocketprogrammingandthattheyarefunandeasytouseGoalsoprovidesmanyfunctionsforbuildinghighperformancesocketapplications

LinksDirectoryPrevioussectionWebservicesNextsectionWebSocket

Sockets

193

82WebSocketsWebSocketsareanimportantfeatureofHTML5Itimplementsbrowserbasedremotesocketswhichallowsbrowserstohavefull-duplexcommunicationswithserversMainstreambrowserslikeFirefoxGoogleChromeandSafariprovidesupportforthisWebSockets

PeopleoftenusedrollpollingforinstantmessagingservicesbeforeWebSocketswerebornwhichallowclientstosendHTTPrequestsperiodicallyTheserverthenreturnsthelatestdatatoclientsThedownsidetothismethodisthatitrequiresclientstokeepsendingmanyrequeststotheserverwhichcanconsumealargeamountofbandwidth

WebSocketsuseaspecialkindofheaderthatreducesthenumberofhandshakesrequiredbetweenbrowserandservertoonlyoneforestablishingaconnectionThisconnectionwillremainactivethroughoutitslifetimeandyoucanuseJavaScripttowriteorreaddatafromthisconnectionasinthecaseofaconventionalTCPsocketsItsolvesmanyoftheheadacheinvolvedwithreal-timewebdevelopmentandhasthefollowingadvantagesovertraditionalHTTP

OnlyoneTCPconnectionforasinglewebclientWebSocketserverscanpushdatatowebclientsLightweightheadertoreducedatatransmissionoverhead

WebSocketURLsbeginwithwsorwss(SSL)ThefollowingfigureshowsthecommunicationprocessofWebSocketsAparticularHTTPheaderissenttotheserveraspartofthehandshakingprotocolandtheconnectionisestablishedThenserversorclientsareabletosendorreceivedatathroughJavaScriptviaWebSocketThissocketcanthenbeusedbyaneventhandlertoreceivedataasynchronously

Figure82WebSocketprinciple

WebSocketprinciplesTheWebSocketprotocolisactuallyquitesimpleAftersuccessfullycompletingtheinitialhandshakeaconnectionisestablishedSubsequentdatacommunicationswillallbeginwithx00andendwithxFFThisprefixandsuffixwillbevisibletoclientsbecausetheWebSocketwillbreakoffbothendyieldingtherawdataautomatically

WebSocketconnectionsarerequestedbybrowsersandrespondedtobyserversafterwhichtheconnectionisestablishedThisprocessisoftencalledhandshaking

Considerthefollowingrequestsandresponses

Figure83WebSocketrequestandresponse

Sec-WebSocket-keyisgeneratedrandomlyasyoumayhavealreadyguessedanditsbase64encodedServersneedtoappendthiskeytoafixedstringafteracceptingarequest

258EAFA5-E914-47DA-95CA-C5AB0DC85B11

Supposewehavef7cb4ezEAl6C3wRaU6JORA==thenwehave

f7cb4ezEAl6C3wRaU6JORA==258EAFA5-E914-47DA-95CA-C5AB0DC85B11

Usesha1tocomputethebinaryvalueandusebase64toencodeitWewillthenwehave

rE91AJhfC+6JdVcVXOGJEADEJdQ=

WebSocket

194

UsethisasthevalueoftheSec-WebSocket-Acceptresponseheader

WebSocketinGoTheGostandardlibrarydoesnotsupportWebSocketsHoweverthewebsocketpackagewhichisasub-packageofgonetdoesandisofficiallymaintainedandsupported

Usegogettoinstallthispackage

gogetgolangorgxnetwebsocket

WebSocketshavebothclientandserversidesLetsseeasimpleexamplewhereauserinputssomeinformationontheclientsideandsendsittotheserverthroughaWebSocketfollowedbytheserverpushinginformationbacktotheclient

Clientcode

lthtmlgt

ltheadgtltheadgt

ltbodygt

ltscripttype=textjavascriptgt

varsock=null

varwsuri=ws1270011234

windowonload=function()

consolelog(onload)

sock=newWebSocket(wsuri)

sockonopen=function()

consolelog(connectedto+wsuri)

sockonclose=function(e)

consolelog(connectionclosed(+ecode+))

sockonmessage=function(e)

consolelog(messagereceived+edata)

functionsend()

varmsg=documentgetElementById(message)value

socksend(msg)

ltscriptgt

lth1gtWebSocketEchoTestlth1gt

ltformgt

ltpgt

Messageltinputid=messagetype=textvalue=Helloworldgt

ltpgt

ltformgt

ltbuttononclick=send()gtSendMessageltbuttongt

ltbodygt

lthtmlgt

AsyoucanseeitsveryeasytousetheclientsideJavaScriptfunctionstoestablishaconnectionTheonopeneventgetstriggeredaftersuccessfullycompletingtheaforementionedhandshakingprocessIttellstheclientthattheconnectionhasbeencreatedsuccessfullyClientsattemptingtoopenaconnectiontypicallybindtofourevents

1)onopentriggeredafterconnectionhasbeenestablished2)onmessagetriggeredafterreceivingamessage3)onerrortriggeredafteranerrorhasoccurred

WebSocket

195

4)onclosetriggeredaftertheconnectionhasclosed

Servercode

packagemain

import(

golangorgxnetwebsocket

fmt

log

nethttp

)

funcEcho(wswebsocketConn)

varerrerror

for

varreplystring

iferr=websocketMessageReceive(wsampreply)err=nil

fmtPrintln(Cantreceive)

break

fmtPrintln(Receivedbackfromclient+reply)

msg=Received+reply

fmtPrintln(Sendingtoclient+msg)

iferr=websocketMessageSend(wsmsg)err=nil

fmtPrintln(Cantsend)

break

funcmain()

httpHandle(websocketHandler(Echo))

iferr=httpListenAndServe(1234nil)err=nil

logFatal(ListenAndServeerr)

WhenaclientSendsuserinputinformationtheserverReceivesitandusesSendonceagaintoreturnaresponse

Figure84WebSocketserverreceivedinformation

ThroughtheexampleabovewecanseethattheclientandserversideimplementationofWebSocketsisveryconvenientWecanusethenetpackagedirectlyinGoWiththerapiddevelopmentofHTML5IthinkthatWebSocketswilltakeonamuchmoreimportantroleinmoderndaywebdevelopmentweshouldallbeatleastalittlebitfamiliarwiththem

LinksDirectoryPrevioussectionSocketsNextsectionREST

WebSocket

196

83RESTRESTisthemostpopularsoftwarearchitectureontheinternettodaybecauseitisfoundedonwelldefinedstrictstandardsanditseasytounderstandandexpandMoreandmorewebsitesarebasingtheirdesignsontopofRESTInthissectionwearegoingtohaveacloselookatimplementingtheRESTarchitectureinGoand(hopefully)learnhowtoleverageittoourbenefit

WhatisRESTThefirstdeclarationoftheconceptofREST(REpresentationalStateTransfer)wasintheyear2000inRoyThomasFieldingsdoctoraldissertationwhoalsojusthappenstobetheco-founderoftheHTTPprotocolItspecifiesthearchitecturesconstraintsandprinciplesandanythingimplementedwiththisarchitecturecanbecalledaRESTfulsystem

BeforeweunderstandwhatRESTisweneedtocoverthefollowingconcepts

Resources

RESTisthePresentationLayerStateTransferwherethepresentationlayerisactuallytheresourcepresentatio

nlayer

SowhatareresourcesPicturesdocumentsorvideosetcareallexamplesofresourcesandcanbelocatedby

URI

Representation

ResourcesarespecificinformationentitiesthatcanbeshowninavarietyofwayswithinthepresentationlayerForinstanceaTXTdocumentcanberepresentedasHTMLJSONXMLetcanimagecanberepresentedasjpgpngetc

URIsareusedtoidentifyresourcesbuthowdowedetermineitsspecificmanifestationsYouarereferredtotheAcceptandContent-TypeinanHTTPrequestheaderthesetwofieldsdescribethepresentationlayer

StateTransfer

AninteractiveprocessisinitiatedbetweenclientandservereachtimeyouvisitanypageofawebsiteDuringthisprocesscertaindatarelatedtothecurrentpagestateneedtobesavedHoweveryoullrecallthatHTTPisastatelessprotocolItsobviousthatweneedtosavethisclientstateonourserversideItfollowsthatifaclientmodifiessomedataandwantstopersistthechangestheremustbeawaytoinformtheserversideaboutthenewstate

MostofthetimeclientsinformserversofstatechangesusingHTTPTheyhavefouroperationswithwhichtodothis

-GETisusedtoobtainresources-POSTsisusedtocreateorupdateresources-PUTupdatesresources-DELETEdeletesresources

Tosummarizetheabove

(1)EveryURIrepresentsaresource(2)Thereisarepresentationlayerfortransferringresourcesbetweenclientsandservers(3)ClientsusefourHTTPmethodstoimplementPresentationLayerStateTransferallowingthemtooperateonremoteresources

ThemostimportantprincipleofwebapplicationsthatimplementRESTisthattheinteractionbetweenclientsandserversarestatelesseveryrequestshouldencapsulatealloftherequiredinformationServersshouldbeabletorestartatanytimewithouttheclientsbeingnotifiedInadditionrequestscanberespondedbyanyserverofthesameservicewhichisidealforcloudcomputingLastlybecauseitsstatelessclientscancachedataforimprovingperformance

REST

197

AnotherimportantprincipleofRESTissystemdelaminationwhichmeansthatcomponentsinonelayerhavenowayofinteractingdirectlywithcomponentsinotherlayersThiscanlimitsystemcomplexityandencourageindependenceintheunderlyingcomponents

Figure85RESTarchitecture

WhenRESTfulconstraintsarejudiciouslyabidedbywebapplicationscanbescaledtoaccommodatemassivenumbersofclientsUsingtheRESTarchitecturecanalsohelpreducedelaysbetweenclientsandserverssimplifysystemarchitectureandimprovethevisibilityofsub-systemendpoints

Figure86RESTsexpansibility

RESTfulimplementationGodoesnthavedirectsupportforRESTbutsinceRESTfulwebapplicationsareallHTTP-basedwecanusethenethttppackagetoimplementitonourownOfcoursewewillfirstneedtomakesomemodificationsbeforeweareabletofullyimplementREST

RESTusesdifferentmethodstohandleresourcesdependingontheinteractionthatsrequiredwiththatresourceManyexistingapplicationsclaimtobeRESTfulbuttheydonotactuallyimplementRESTImgoingtocategorizetheseapplicationsintoseverallevelsdependsonwhichHTTPmethodstheyimplement

Figure87RESTslevel

ThepictureaboveshowsthreelevelsthatarecurrentlyimplementedinRESTYoumaynotchoosetofollowalltherulesandconstraintsofRESTwhendevelopingyourownapplicationsbecausesometimesitsrulesarenotagoodfitforallsituationsRESTfulwebapplicationsuseeverysingleHTTPmethodincludingDELETEandPUTbutinmanycasesHTTPclientscanonlysendGETandPOSTrequests

HTMLstandardallowsclientssendGETandPOSTrequeststhroughlinksandformsItsnotpossibletosendPUTorDELETErequestswithoutAJAXsupportSomefirewallsinterceptPUTandDELETErequestsandclientshavetousePOSTinordertoimplementthemFullyRESTfulservicesareinchargeoffindingtheoriginalHTTPmethodsandrestoringthem

WecansimulatePUTandDELETErequestsbyaddingahidden_methodfieldinourPOSTrequestshowevertheserequestsmustbeconvertedontheserversidebeforetheyareprocessedMypersonalapplicationsusethisworkflowtoimplementRESTinterfacesStandardRESTfulinterfacesareeasilyimplementedinGoasthefollowingexampledemonstrates

REST

198

packagemain

import(

fmt

githubcomjulienschmidthttprouter

log

nethttp

)

funcIndex(whttpResponseWriterrhttpRequest_httprouterParams)

fmtFprint(wWelcomen)

funcHello(whttpResponseWriterrhttpRequestpshttprouterParams)

fmtFprintf(whellosnpsByName(name))

funcgetuser(whttpResponseWriterrhttpRequestpshttprouterParams)

uid=psByName(uid)

fmtFprintf(wyouaregetusersuid)

funcmodifyuser(whttpResponseWriterrhttpRequestpshttprouterParams)

uid=psByName(uid)

fmtFprintf(wyouaremodifyusersuid)

funcdeleteuser(whttpResponseWriterrhttpRequestpshttprouterParams)

uid=psByName(uid)

fmtFprintf(wyouaredeleteusersuid)

funcadduser(whttpResponseWriterrhttpRequestpshttprouterParams)

uid=rFormValue(uid)

uid=psByName(uid)

fmtFprintf(wyouareaddusersuid)

funcmain()

router=httprouterNew()

routerGET(Index)

routerGET(hellonameHello)

routerGET(useruidgetuser)

routerPOST(adduseruidadduser)

routerDELETE(deluseruiddeleteuser)

routerPUT(moduseruidmodifyuser)

logFatal(httpListenAndServe(8080router))

ThissamplecodeshowsyouhowtowriteaverybasicRESTapplicationOurresourcesareusersandweusedifferentfunctionsfordifferentmethodsHereweimportedathird-partypackagecalledgithubcomjulienschmidthttprouterWevealreadycoveredhowtoimplementacustomrouterinpreviouschapters-thejulienschmidthttprouterpackageimplementssomeveryconvenientroutermappingrulesthatmakeitveryconvenientforimplementingRESTfularchitectureAsyoucanseeRESTrequiresyoutoimplementdifferentlogicfordifferentHTTPmethodsofthesameresource

SummaryRESTisastyleofwebarchitecturebuildingonpastsuccessfulexperienceswithWWWstatelessnessresource-centricfulluseofHTTPandURIprotocolsandtheprovisionofunifiedinterfacesThesesuperiordesignconsiderationshaveallowedRESTtobecomethemostpopularwebservicesstandardInasensebyemphasizingtheURIandleveraging

REST

199

earlyInternetstandardssuchasHTTPRESThaspavedthewayforlargeandscalablewebapplicationsCurrentlythesupportthatGohasForRESTisstillverybasicHoweverbyimplementingcustomroutingrulesanddifferentrequesthandlersforeachtypeofHTTPrequestwecanachieveRESTfularchitectureinourGowebapps

LinksDirectoryPrevioussectionWebSocketNextsectionRPC

REST

200

84RPCInprevioussectionswetalkedabouthowtowritenetworkapplicationsbasedonSocketsandHTTPWelearnedthatbothofthemusetheinformationexchangemodelinwhichclientssendrequestsandserversrespondtothemThiskindofdataexchangeisbasedonaspecificformatsothatbothsidesareabletocommunicatewithoneanotherHowevermanyindependentapplicationsdonotusethismodelbutinsteadcallservicesjustliketheywouldcallnormalfunctions

RPCwasintendedtobethefunctioncallmodefornetworkedsystemsClientsexecuteRPCsliketheycallnativefunctionsexcepttheypackagethefunctionparametersandsendthemthroughthenetworktotheserverTheservercanthenunpacktheseparametersandprocesstherequestexecutingtheresultsbacktotheclient

Incomputersciencearemoteprocedurecall(RPC)isatypeofinter-processcommunicationthatallowsacomputerprogramtocauseasubroutineorproceduretoexecuteinanotheraddressspace(commonlyonanothercomputeronasharednetwork)withouttheprogrammerexplicitlycodingthedetailsforthisremoteinteractionThatistheprogrammerwritesessentiallythesamecodewhetherthesubroutineislocaltotheexecutingprogramorremoteWhenthesoftwareinquestionusesobject-orientedprinciplesRPCiscalledremoteinvocationorremotemethodinvocation

RPCworkingprinciple

Figure88RPCworkingprinciple

NormallyanRPCcallfromclienttoserverhasthefollowingtensteps

1 Calltheclienthandleexecutetransferarguments

1 Calllocalsystemkerneltosendnetworkmessages

1 Sendmessagestoremotehosts

1 Theserverreceiveshandleandarguments

1 Executeremoteprocesses

1 Returnexecutionresulttocorrespondinghandle

1 Theserverhandlecallsremotesystemkernel

1 Messagessentbacktolocalsystemkernel

1 Theclienthandlereceivesmessagesfromsystemkernel

1 Theclientgetsresultsfromcorrespondinghandle

GoRPCGohasofficialsupportforRPCinitsstandardlibraryonthreelevelswhichareTCPHTTPandJSONRPCNotethatGoRPCisnotlikeothertraditionalRPCsystemsItrequiresyoutouseGoapplicationsonbothclientandserversidesbecauseitencodescontentusingGob

RPC

201

FunctionsofGoRPCmustabidebythefollowingrulesforremoteaccessotherwisethecorrespondingcallswillbeignored

Functionsareexported(capitalized)FunctionsmusthavetwoargumentswithexportedtypesThefirstargumentisforreceivingfromtheclientandthesecondonehastobeapointerandisforreplyingtotheclientFunctionsmusthaveareturnvalueoferrortype

Forexample

func(tT)MethodName(argTypeT1replyTypeT2)error

WhereTT1andT2mustbeabletobeencodedbythepackagegobpackage

AnykindofRPChastogothroughanetworktotransferdataGoRPCcaneitheruseHTTPorTCPThebenefitsofusingHTTPisthatyoucanreusesomefunctionsfromthenethttppackage

HTTPRPCHTTPserversidecode

RPC

202

packagemain

import(

errors

fmt

nethttp

netrpc

)

typeArgsstruct

ABint

typeQuotientstruct

QuoRemint

typeArithint

func(tArith)Multiply(argsArgsreplyint)error

reply=argsAargsB

returnnil

func(tArith)Divide(argsArgsquoQuotient)error

ifargsB==0

returnerrorsNew(dividebyzero)

quoQuo=argsAargsB

quoRem=argsAargsB

returnnil

funcmain()

arith=new(Arith)

rpcRegister(arith)

rpcHandleHTTP()

err=httpListenAndServe(1234nil)

iferr=nil

fmtPrintln(errError())

WeregisteredaRPCserviceofAriththenregisteredthisserviceonHTTPthroughrpcHandleHTTPAfterthatweareabletotransferdatathroughHTTP

Clientsidecode

RPC

203

packagemain

import(

fmt

log

netrpc

os

)

typeArgsstruct

ABint

typeQuotientstruct

QuoRemint

funcmain()

iflen(osArgs)=2

fmtPrintln(UsageosArgs[0]server)

osExit(1)

serverAddress=osArgs[1]

clienterr=rpcDialHTTP(tcpserverAddress+1234)

iferr=nil

logFatal(dialingerr)

Synchronouscall

args=Args178

varreplyint

err=clientCall(ArithMultiplyargsampreply)

iferr=nil

logFatal(aritherrorerr)

fmtPrintf(Arithdd=dnargsAargsBreply)

varquotQuotient

err=clientCall(ArithDivideargsampquot)

iferr=nil

logFatal(aritherrorerr)

fmtPrintf(Arithdd=dremainderdnargsAargsBquotQuoquotRem)

WecompiletheclientandtheserversidecodeseparatelythenstarttheserverandclientYoullthenhavesomethingsimilarasfollowsafteryouinputsomedata

$http_clocalhost

Arith178=136

Arith178=2remainder1

AsyoucanseewedefinedastructforthereturntypeWeuseitastypeoffunctionargumentontheserversideandasthetypeofthesecondandthirdargumentsontheclientclientCallThiscallisveryimportantIthasthreeargumentswherethefirstoneisthenameofthefunctionthatisgoingtobecalledthesecondistheargumentyouwanttopassandthelastoneisthereturnvalue(ofpointertype)SofarweseethatitseasytoimplementRPCinGo

TCPRPCLetstrytheRPCthatisbasedonTCPhereistheserversidecode

RPC

204

packagemain

import(

errors

fmt

net

netrpc

os

)

typeArgsstruct

ABint

typeQuotientstruct

QuoRemint

typeArithint

func(tArith)Multiply(argsArgsreplyint)error

reply=argsAargsB

returnnil

func(tArith)Divide(argsArgsquoQuotient)error

ifargsB==0

returnerrorsNew(dividebyzero)

quoQuo=argsAargsB

quoRem=argsAargsB

returnnil

funcmain()

arith=new(Arith)

rpcRegister(arith)

tcpAddrerr=netResolveTCPAddr(tcp1234)

checkError(err)

listenererr=netListenTCP(tcptcpAddr)

checkError(err)

for

connerr=listenerAccept()

iferr=nil

continue

rpcServeConn(conn)

funccheckError(errerror)

iferr=nil

fmtPrintln(FatalerrorerrError())

osExit(1)

ThedifferencebetweenHTTPRPCandTCPRPCisthatwehavetocontrolconnectionsbyourselvesifweuseTCPRPCthenpassconnectionstoRPCforprocessing

AsyoumayhaveguessedthisisablockingpatternYouarefreetousegoroutinestoextendthisapplicationasamoreadvancedexperiment

Theclientsidecode

RPC

205

packagemain

import(

fmt

log

netrpc

os

)

typeArgsstruct

ABint

typeQuotientstruct

QuoRemint

funcmain()

iflen(osArgs)=2

fmtPrintln(UsageosArgs[0]serverport)

osExit(1)

service=osArgs[1]

clienterr=rpcDial(tcpservice)

iferr=nil

logFatal(dialingerr)

Synchronouscall

args=Args178

varreplyint

err=clientCall(ArithMultiplyargsampreply)

iferr=nil

logFatal(aritherrorerr)

fmtPrintf(Arithdd=dnargsAargsBreply)

varquotQuotient

err=clientCall(ArithDivideargsampquot)

iferr=nil

logFatal(aritherrorerr)

fmtPrintf(Arithdd=dremainderdnargsAargsBquotQuoquotRem)

TheonlydifferenceintheclientsidecodeisthatHTTPclientsuseDialHTTPwhereasTCPclientsuseDial(TCP)

JSONRPC

JSONRPCencodesdatatoJSONinsteadofgobLetsseeanexampleofaGoJSONRPContheserver

RPC

206

packagemain

import(

errors

fmt

net

netrpc

netrpcjsonrpc

os

)

typeArgsstruct

ABint

typeQuotientstruct

QuoRemint

typeArithint

func(tArith)Multiply(argsArgsreplyint)error

reply=argsAargsB

returnnil

func(tArith)Divide(argsArgsquoQuotient)error

ifargsB==0

returnerrorsNew(dividebyzero)

quoQuo=argsAargsB

quoRem=argsAargsB

returnnil

funcmain()

arith=new(Arith)

rpcRegister(arith)

tcpAddrerr=netResolveTCPAddr(tcp1234)

checkError(err)

listenererr=netListenTCP(tcptcpAddr)

checkError(err)

for

connerr=listenerAccept()

iferr=nil

continue

jsonrpcServeConn(conn)

funccheckError(errerror)

iferr=nil

fmtPrintln(FatalerrorerrError())

osExit(1)

JSONRPCisbasedonTCPanddoesntsupportHTTPyet

Theclientsidecode

RPC

207

packagemain

import(

fmt

log

netrpcjsonrpc

os

)

typeArgsstruct

ABint

typeQuotientstruct

QuoRemint

funcmain()

iflen(osArgs)=2

fmtPrintln(UsageosArgs[0]serverport)

logFatal(1)

service=osArgs[1]

clienterr=jsonrpcDial(tcpservice)

iferr=nil

logFatal(dialingerr)

Synchronouscall

args=Args178

varreplyint

err=clientCall(ArithMultiplyargsampreply)

iferr=nil

logFatal(aritherrorerr)

fmtPrintf(Arithdd=dnargsAargsBreply)

varquotQuotient

err=clientCall(ArithDivideargsampquot)

iferr=nil

logFatal(aritherrorerr)

fmtPrintf(Arithdd=dremainderdnargsAargsBquotQuoquotRem)

SummaryGohasgoodsupportforHTTPTPCandJSONRPCimplementationwhichallowustoeasilydevelopdistributedwebapplicationshoweveritisregrettablethatGodoesnthavebuilt-insupportforSOAPRPCalthoughsomeopensourcethird-partypackagesdoofferthis

LinksDirectoryPrevioussectionRESTNextsectionSummary

RPC

208

85SummaryInthischapterIintroducedyoutoseveralmainstreamwebapplicationdevelopmentmodelsInsection81IdescribedthebasicsofnetworkprogrammingsocketsBecauseoftherapidevolutionofnetworktechnologyandinfrastructureandgiventhattheSocketisthecornerstoneofthesechangesyoumustmastertheconceptsbehindsocketprogramminginordertobeacompetentwebdeveloperInsection82IdescribedHTML5WebSocketswhichsupportfull-duplexcommunicationsbetweenclientandserverandeliminatetheneedforpollingwithAJAXInsection83weimplementedasimpleapplicationusingtheRESTarchitecturewhichisparticularlysuitableforthedevelopmentofnetworkAPIsduetotherapidriseofmobileapplicationsIbelievethatRESTfulAPIswillbeanongoingtrendInsection84welearnedaboutGoRPCs

GoprovidesexcellentsupportforthefourkindsofdevelopmentmethodsmentionedaboveNotethatthenetpackageanditssub-packagesistheplacewhereGosnetworkprogrammingtoolsGoresideIfyouwantamorein-depthunderstandingoftherelevantimplementationdetailsyoushouldtryreadingthesourcecodeofthosepackages

LinksDirectoryPrevioussectionRPCNextchapterSecurityandencryption

Summary

209

9SecurityandencryptionSecurityisanextremelyimportantaspectofmostwebapplicationsThistopichasbeengettingmoreandmoreattentionlatelyespeciallyinlightoftherecentCSDNLinkedinandYahoopasswordleaksAsGodeveloperswemustbeawareofvulnerabilitiesinourapplicationsandtakeprecautionsinordertopreventattackersfromtakingoveroursystems

Manyofthesecurityproblemsthatariseinmodernwebapplicationsoriginatefromdataprovidedbythird-partiesForexampleuserinputshouldalwaysbevalidatedandsanitizedbeforebeingstoredassecuredataIfthisisntdonewhenthedataisoutputtedtoaclientitmaycauseacross-sitescriptingattack(XSS)SimilarlyifunsafedataisuseddirectlyasyourapplicationsdatabasequeriesthenyoumaybevulnerabletoSQLinjectionattacksInsections93and94welllookathowtoavoidtheseproblems

Whenusingthird-partydata(whichincludesuser-supplieddata)firstverifytheintegrityofthedatabyfilteringtheinputSection92willdescribehowtofilterinput

UnfortunatelyfilteringinputandescapingoutputdoesnotsolveallsecurityproblemsInsection91wewillexplaincross-siterequestforgery(CSRF)attacksThisisamaliciousexploitwhereunauthorizedcommandsaretransmittedfromauserthatthewebsitetrusts

KeepingconfidentialdataencryptedcanalsohelpyoutosecureyourwebapplicationsInsection95wewilldescribehowtostorepasswordssafelyusingGosencryptionpackage

AgoodhashfunctionmakesithardtofindtwostringsthatwouldproducethesamehashvalueandthisisonewaywithwhichwecanencryptourdataThereisalsotwo-wayencryptionwhereyouuseasecretkeytodecryptencrypteddataInsection96wewilldescribehowtoperformbothone-wayandtwo-wayencryption

LinksDirectoryPreviousChapterChapter8SummaryNextsectionCSRFattacks

Securityandencryption

210

91CSRFattacks

WhatisCSRFCSRFandXSRFbothstandforCross-siterequestforgeryItsalsoknownasaoneclickattackorsessionriding

SohowdoesaCSRFattackworkACSRFattackhappenswhenanattackertricksatrusteduserintoaccessingawebsiteorclickingaURLthattransmitsmaliciousrequests(withouttheuserrsquosconsent)toatargetedwebsiteHeresasimpleexampleusingafewsocialengineeringtricksanattackercouldusetheQQchatsoftwaretofindandsendmaliciouslinkstovictimstargetedattheirusersonlinebankingwebsiteIfthevictimlogsintotheironlinebankaccountanddoesnotexitthenclickingonamaliciouslinksentfromtheattackercouldallowtheattackertostealalloftheusersbankaccountfunds

WhenunderaCSRFattackasingleend-userwithanadministratoraccountcanthreatentheintegrityoftheentirewebapplication

CSRFprincipleThefollowingdiagramprovidesasimpleoverviewofaCSRFattack

Figure91CSRFattackprocess

AscanbeseenfromthefiguretocompleteaCSRFattackthevictimmustcompletethefollowingtwosteps

-1LogintotrustedsiteAandstorealocalCookie-2WithoutgoingthroughexistingsiteAaccessthedangerouslinktositeB

AsareaderyoumaybeaskingIfIdonotmeettheabovetwoconditionsIwillnotbesubjectedtoCSRFattacksYesthisistruehoweveryoucannotguaranteethatthefollowingdoesnotoccur

YoucannotguaranteethatwhenyouareloggedintoasitethesitedidntlaunchanyhiddentabsYoucannotguaranteethatwhenyoucloseyourbrowseryourcookieswillimmediatelyexpireandyourlastsessionwillhaveendedTrustedhightrafficwebsiteswilllikelynothavehiddenvulnerabilitieseasilyexploitablebyCSRFbasedattacks

ThusitcanbedifficultforuserstovisitawebsitethroughalinkandknowthatitwillnotcarryoutunknownoperationsintheformofaCSRFattack

CSRFattacksworkmostlybecauseoftheprocessthroughwhichusersareauthenticatedAlthoughyoucanreasonablyguaranteethatarequestoriginatesfromausersbrowserthereisnoguaranteethattheusergrantedapprovalfortherequest

HowtopreventCSRFattacksYoumightbealittlescaredafterreadingthesectionaboveButfearisagoodthingItwillforceyoutoeducateyourselfonhowtopreventvulnerabilitieslikethisfromhappeningtoyou

PreventativemeasuresagainstCSRFattackscanbetakenonboththeserverandclientsidesofawebapplicationHoweverCSRFattacksaremosteffectivelythwartedontheserverside

TherearemanywaysofpreventingCSRFattacksontheserversideMostapproachesstemfromthefollowingtwoaspects

1 MaintainingproperuseofGETPOSTandcookies

CSRFattacks

211

2 Includingapseudo-randomnumberwithnon-GETrequests

InthepreviouschapteronRESTwesawhowmostwebapplicationsarebasedonGETandPOSTHTTPrequestsandthatcookieswereincludedalongwiththeserequestsWegenerallydesignapplicationsaccordingtothefollowingprinciples

1 GETiscommonlyusedtoviewinformationwithoutalteringanydata

2 POSTisusedinplacingorderschangingthepropertiesofaresourceorperformingothertasks

ImnowgoingtousetheGolanguagetoillustratehowtorestrictaccesstoresourcesmethods

muxGet(useruidgetuser)

muxPost(useruidmodifyuser)

SincewevestipulatedthatmodificationscanonlyusePOSTwhenaGETmethodisissuedinsteadofaPOSTwecanrefusetorespondtotherequestAccordingtothefigureaboveattacksutilizingGETasaCSRFexploitcanbepreventedIsthisenoughtopreventallpossibleCSRFattacksOfcoursenotbecausePOSTscanalsobeforged

Weneedtoimplementasecondstepwhichis(inthecaseofnon-GETrequests)toincreasethelengthofthepseudo-randomnumberincludedwiththerequestThisusuallyinvolvessteps

Foreachusergenerateauniquecookietokenwithapseudo-randomvalueAllformsmustcontainthesamepseudo-randomvalueThisproposalisthesimplestonebecauseintheoryanattackercannotreadthirdpartycookiesAnyformthatanattackermaysubmitwillfailthevalidationprocesswithoutknowingwhattherandomvalueisDifferentformscontaindifferentpseudo-randomvaluesasweveintroducedinsection44HowtopreventmultipleformsubmissionWecanreusetherelevantcodefromthatsectiontomeetourneeds

Generatingarandomnumbertoken

h=md5New()

ioWriteString(hstrconvFormatInt(crutime10))

ioWriteString(hganraomaxxxxxxxxx)

token=fmtSprintf(xhSum(nil))

t_=templateParseFiles(logingtpl)

tExecute(wtoken)

Outputtoken

ltinputtype=hiddenname=tokenvalue=gt

Authenticationtoken

rParseForm()

token=rFormGet(token)

iftoken=

Verificationtokenoflegitimacy

Else

Errortokendoesnotexist

WecanusetheprecedingcodetosecureourPOSTsYoumightbewonderinginaccordancewithourtheorywhethertherecouldbesomewayforamaliciousthirdpartytosomehowfigureoutoursecrettokenvalueInfactcrackingitisbasicallyimpossible-successfullycalculatingthecorrectstringvalueusingbruteforcemethodsneedsabout2tothe11thtime

Summary

CSRFattacks

212

Cross-siterequestforgeryalsoknownasCSRFisaverydangerouswebsecuritythreatItisknowninwebsecuritycirclesasasleepinggiantsecurityissueasyoucantellCSRFattackshavequitethereputationThissectionnotonlyintroducedcross-siterequestforgeryitselfbutfactorsunderlyingthisvulnerabilityItconcludeswithsomesuggestionsandmethodsforpreventingsuchattacksIhopethissectionwillhaveinspiredyouasareadertowritebetterandmoresecurewebapplications

LinksDirectoryPrevioussectionSecurityandencryptionNextsectionFilterinputs

CSRFattacks

213

92FilteringinputsFilteringuserdataisonewaywecanimprovethesecurityofourwebappsusingittoverifythelegitimacyofincomingdataAlloftheinputdataisfilteredinordertoavoidmaliciouscodeordatafrombeingmistakenlyexecutedorstoredMostwebapplicationvulnerabilitiesariseformneglectingtofilterinputdataandnaivelytrustingit

Ourintroductiontofilteringdataisdividedintothreesteps

1 identifyingthedataweneedtofilterthedatatofigureoutwhereitoriginatedfrom2 filteringofthedataitselfweneedtofigureoutwhatkindofdatawehavereceived3 distinguishbetweenfiltered(sanitized)andtainteddataafterthedatahasbeenfilteredwecanbeassuredthatitis

secure

IdentifyingdataIdentifyingthedataisourfirststepbecausemostofthetimeasmentionedwedontknowwhereitoriginatesfromWithoutthisknowledgewewouldbeunabletoproperlyfilteritThedatahereisprovidedinternallyallfromnon-codedataForexamplealldatacomesfromclientshoweverclientsthatareusersarenottheonlyexternalsourcesofdataAdatabaseinterfaceprovidingthirdpartydatacouldalsobeanexternaldatasource

DatathathasbeenenteredbyauserisveryeasytorecognizeinGoWeuserParseFormaftertheuserPOSTsaformtogetallofthedatainsidetherFormOthertypesofinputaremuchhardertoidentifyForexampleinrHeadersmanyoftheelementsareoftenmanipulatedbytheclientItcanoftenbedifficulttoidentifywhichoftheseelementshavebeenmanipulatedbyclientssoitsbesttoconsiderallofthemashavingbeentaintedTherHeaderGet(Accept-Charset)headerfieldforinstanceisalsoconsideredasuserinputalthoughthesearetypicallyonlymanipulatedbybrowsers

FilteringdataIfweknowthesourceofthedatawecanfilteritFilteringisabitofaformaluseofthetermTheprocessisknownbymanyothertermssuchasinputcleaningvalidationandsanitizationDespitethefactthatthesetermsdiffersomewhatintheirmeaningtheyallrefertothesamethingtheprocessofpreventingillegaldatafrommakingitswayintoyourapplications

TherearemanywaystofilterdatasomeofwhicharelesssecurethanothersThebestmethodistocheckwhetherornotthedataitselfmeetsthelegalrequirementsdictatedbyyourapplicationWhenattemptingtodosoitsveryimportantnottomakeanyattemptsatcorrectingtheillegaldatathiscouldallowmalicioususerstomanipulateyourvalidationrulesfortheirownneedsaltogetherdefeatingthepurposeoffilteringthedatainthefirstplaceHistoryhasproventhatattemptingtocorrectinvaliddataoftenleadstosecurityvulnerabilitiesLetstakealookatanoverlysimpleexampleforillustrationpurposesSupposethatabankingsystemasksuserstosupplyasecure6digitpasswordThesystemvalidatesthelengthofallpasswordsOnemightnaivelywriteavalidationrulethatcorrectspasswordsofillegallengthsIfapasswordisshorterthanthelegallengthfillintheremainingdigitswith0sThissimplerulewouldallowattackerstoguessjustthefirstfewdigitsofapasswordtosuccessfullygainaccesstouseraccounts

Wecanuseseverallibrariestohelpustofilterdata

ThestrconvpackagecanhelpustoconvertstringsinputbyusersintospecifictypessincerFormsaremapsofstringvaluesSomecommonstringconversionsprovidedbystrconvareAtoiParseBoolParseFloatandParseIntGosstringspackagecontainssomefilterfunctionslikeTrimToLowerandToTitlewhichcanhelpustoobtaindatainaspecificformatsaccordingtoourneedsGosregexppackagecanbeusedtohandlecaseswhicharemorecomplexinnaturesuchasdeterminingwhetheraninputisanemailaddressabirthdayetc

Filterinputs

214

FilteringincomingdatainadditiontoauthenticationcanbequiteeffectiveLetsaddanothertechniquetoourrepertoirecalledwhitelistingWhitelistingisagoodwayofconfirmingthelegitimacyofincomingdataUsingthismethodifanerroroccursitcanonlymeanthattheincomingdataisillegalandnottheoppositeOfcoursewedontwanttomakeanymistakesinourwhitelistbyfalselylabellinglegitimatedataasillegalbutthisscenarioismuchbetterthanillegaldatabeinglabeledaslegitimateandthusmuchmoresecure

DistinguishingbetweenfilteredandtainteddataIfyouhavecompletedtheabovestepsthejoboffilteringdatahasbasicallybeencompletedHoweverwhenwritingwebapplicationswealsoneedtodistinguishbetweenfilteredandtainteddatabecausedoingsocanguaranteetheintegrityofourdatafilteringprocesswithoutaffectingtheinputdataLetsputallofourfiltereddataintoaglobalmapvariablecalledCleanMapThentwoimportantstepsarerequiredtopreventcontaminationviadatainjection

EachrequestmustinitializeCleanMapasanemptymapPreventvariablesfromexternaldatasourcesnamedCleanMapfrombeingintroducedintotheapp

Nextletsuseanexampleformtoreinforcetheseconcepts

ltformaction=whoamimethod=POSTgt

WhoamI

ltselectname=namegt

ltoptionvalue=astaxiegtastaxieltoptiongt

ltoptionvalue=herrygtherryltoptiongt

ltoptionvalue=marrygtmarryltoptiongt

ltselectgt

ltinputtype=submitgt

ltformgt

IndealingwiththistypeofformitcanbeveryeasytomakethemistakeofthinkingthatuserswillonlybeabletosubmitoneofthethreeselectoptionsInfactPOSToperationscaneasilybesimulatedbyattackersForexamplebysubmittingthesameformwithname=attackamalicioususercouldintroduceillegaldataintooursystemWecanuseasimplewhitelisttocounterthesetypesofattacks

rParseForm()

name=rFormGet(name)

CleanMap=make(map[string]interface0)

ifname==astaxie||name==herry||name==marry

CleanMap[name]=name

TheabovecodeinitializesaCleanMapvariableandanameisonlyassignedaftercheckingitagainstaninternalwhitelistoflegitimatevalues(astaxieherryandmarryinthiscase)WestorethedataintheCleanMapinstancesoyoucanbesurethatCleanMap[name]holdsavalidatedvalueAnycodewishingtoaccessthisvaluecanthenfreelydosoWecanalsoaddanadditionalelsestatementtotheaboveifwhitelistfordealingwithillegaldataapossibilitybeingthattheformwasdisplayedwithanerrorDonottrytobetooaccommodatingthoughoryouruntheriskofaccidentallycontaminatingyourCleanMap

TheabovemethodforfilteringdataagainstasetofknownlegitimatevaluesisveryeffectiveThereisanothermethodforcheckingwhetherornotincomingdataconsistsoflegalcharactersusingregexphoweverthiswouldbeineffectualintheabovecasewherewerequirethatthenamebeanoptionfromtheselectForexampleyoumayrequirethatusernamesonlyconsistoflettersandnumbers

rParseForm()

username=rFormGet(username)

CleanMap=make(map[string]interface0)

ifok_=regexpMatchString(^[a-zA-Z0-9]$username)ok

CleanMap[username]=username

Filterinputs

215

SummaryDatafilteringplaysavitalroleinthesecurityofmodernwebapplicationsMostsecurityvulnerabilitiesaretheresultofimproperlyfilteringdataorneglectingtoproperlyvalidateitBecausetheprevioussectiondealtwithCSRFattacksandthenexttwowillbeintroducingXSSattacksandSQLinjectiontherewasnonaturalsegueintodealingwithatopicasimportantasdatasanitizationsointhissectionwepaidspecialattentiontoit

LinksDirectoryPrevioussectionCSRFattacksNextsectionXSSattacks

Filterinputs

216

93XSSattacksWiththedevelopmentofInternettechnologywebapplicationsareoftenpackedwithdynamiccontenttoimproveuserexperienceDynamiccontentiscontentthatreactsandchangesaccordingtouserrequestsandactionsDynamicsitesareoftensusceptibletocross-sitescriptingattacks(oftenreferredtobysecurityexpertsinitsabbreviatedformXSS)somethingwhichstaticwebsitesarecompletelyunaffectedby

WhatisXSSAsmentionedthetermXSSisanacronymforCross-SiteScriptingwhichisatypeofattackcommononthewebInordernottoconfuseitwithanothercommonwebacronymCSS(CascadingStyleSheets)weuseanXinsteadofaCforthecrossincross-sitescriptingXSSisacommonwebsecurityvulnerabilitywhichallowsattackerstoinjectmaliciouscodeintowebpagesUnlikemosttypesofattackswhichgenerallyinvolveonlyanattackerandavictimXSSinvolvesthreepartiesanattackeraclientandawebapplicationThegoalofanXSSattackistostealcookiesstoredonclientsbywebapplicationsforthepurposeofreadingsensitiveclientinformationOnceanattackergetsaholdofthisinformationtheycanimpersonateusersandinteractwithwebsiteswithouttheirknowledgeorapproval

XSSattackscanusuallybedividedintotwocategoriesoneisastoredXSSattackThisformofattackariseswhenusersareallowedtoinputdataontoapublicpagewhichafterbeingsavedbytheserverwillbereturned(unescaped)tootherusersthathappentobebrowsingitSomeexamplesofthetypesofpagesthatareoftenaffectedincludecommentsreviewsblogpostsandmessageboardsTheprocessoftengoeslikethisanattackerenterssomehtmlfollowedbyahiddenltscriptgttagcontainingsomemaliciouscodethenhitssaveThewebapplicationsavesthistothedatabaseWhenanotheruserrequeststhispagetheapplicationqueriesthistainteddatafromthedatabaseandservesthepagetotheuserTheattackersscriptthenexecutesarbitrarycodeontheclientscomputer

TheothertypeisareflectedXSSattackThemainideaistoembedamaliciousscriptdirectlyintothequeryparametersofaURLaddressAserverthatimmediatelyparsesthisdataintoapageofresultsandreturnsit(totheclientwhomadetherequest)unsanitizedcanunwittinglycausetheclientscomputertoexecutethiscodeAnattackercansendauseralegitimatelookinglinktoatrustedwebsitewiththeencodedpayloadclickingonthislinkcancausetheusersbrowsertoexecutethemaliciousscript

XSSpresentthemainmeansandendsasfollows

TheftofcookiesaccesstosensitiveinformationTheuseofembeddedFlashthroughcrossdomainpermissionscanalsobeusedbyanattackertoobtainhigheruserprivilegesThisalsoappliesforothersimilarattackvectorssuchasJavaandVBScriptTheuseofiframesframesXMLHttpRequestsetccanallowanattackertoassumetheidentityofausertoperformadministrativeactionssuchasmicro-bloggingaddingfriendssendingprivatemessagesandotherroutineoperationsAwhileagotheSinamicrobloggingplatformsufferedfromthistypeofXSSvulnerabilityWhenmanyusersvisitapageaffectedbyanXSSattacktheeffectonsomesmallersitescanbecomparabletothatofaDDoSattack

XSSprinciplesWebapplicationsthatreturnrequesteddatatouserswithoutfirstinspectingandfilteringitcanallowmalicioususerstoinjectscripts(typicallyembeddedinsideHTMLwithinltscriptgttags)ontootherusersbrowsersWhenthismaliciouscodeisrenderedonausersbrowserwithoutfirsthavingbeenescapedfromtheusersbrowserwillinterpretthiscodethisisthedefinitionofanXSSattackandthistypeofmistakeistheleadingcauseofXSSvulnerabilities

LetsgothroughtheprocessofareflectiveXSSattackLetssaytheresawebsitethatoutputsausersnameaccordingtotheURLqueryparametersaccessthefollowingURLhttp127001name=astaxiewillcausetheservertooutputthefollowing

XSSattacks

217

helloastaxie

Letssaywepassthefollowingparameterinsteadaccessingthesameurlhttp127001name=ltscriptgtalert(astaxiexss)ltscriptgtIfthiscausesthebrowsertoproduceanalertpop-upboxwecanconfirmthatthesiteisvulnerabletoXSSattacksSohowdomalicioususersstealcookiesusingthesametypeofattack

JustlikebeforewehaveaURL

http127001

name=amp60scriptamp62documentlocationhref=httpwwwxxxcomcookie+documentcookieamp60scriptamp62

ByclickingonthisURLyoudbesendingthecurrentcookietothespecifiedsitewwwxxxcomYoumightbewonderingwhywouldanybodyclickonsuchastrangelookingURLinthefirstplaceWhileitstruethatthiskindofURLwillmakemostpeopleskepticalifanattackerweretouseoneofthemanypopularURLshorteningservicestoobscureitwouldyoustillbeabletoseeitMostattackerswouldobfuscatetheURLinonewayoranotherandyoudonlyknowthelegitimacyofthelinkafterclickingonitHoweverbythispointcookiedatawillhavealreadybeensenttothe3rdpartywebsitecompromisingyoursensitiveinformationYoucanusetoolslikeWebsleuthtoauditthesecurityofyourwebapplicationsforthesetypesofvulnerabilities

ForamoredetailedanalysisonanXSSattackhavealookatthearticle[SinamicrobloggingXSSeventanalysis](httpwwwrisingcomcnnewsletternews2011-08-189621html)

HowtopreventXSSTheanswerissimplenevertrustuserinputandalwaysfilteroutallspecialcharactersinanyinputdatayoumayreceiveThiswilleliminatethemajorityofXSSattacks

UsethefollowingtechniquestodefendagainstXSSattacks

Filterspecialcharacters

OnewaytoavoidXSSistofilteruser-suppliedcontentTheGolanguageprovidessomeHTMLfilteringfunctionsinitstexttemplatepackgesuchasHTMLEscapeStringandJSEscapeStringtonameafew

SpecifythecontenttypeinyourHTTPheaders

wHeader()Set(Content-Typetextjavascript)

Thisallowsclientbrowserstoparsetheresponseasjavascriptcode(applyingtheneccessaryfilters)insteadofrenderingthecontentinanunspecifiedandpotentiallydangerousmanner

SummaryIntroducingXSSvulnerabilitiesisaveryrealhazardwhendevelopingwebapplicationsItisimportanttoremembertofilteralldataespeciallybeforeoutputtingittoclientsthisisnowawell-establishedmeansofpreventingXSS

LinksDirectoryPrevioussectionFilterinputsNextsectionSQLinjection

XSSattacks

218

94SQLinjection

WhatisSQLinjectionSQLinjectionattacksare(asthenamewouldsuggest)oneofthemanytypesofscriptinjectionattacksInwebdevelopmentthesearethemostcommonformofsecurityvulnerabilitiesAttackerscanuseittoobtainsensitiveinformationfromdatabasesandaspectsofanattackcaninvolveaddinguserstothedatabaseexportingprivatefilesandevenobtainingthehighestsystemprivilegesfortheirownnefariouspurposes

SQLinjectionoccurswhenwebapplicationsdonoteffectivelyfilteroutuserinputleavingthedoorwideopenforattackerstosubmitmaliciousSQLquerycodetotheserverApplicationsoftenreceiveinjectedcodeaspartofanattackersinputwhichaltersthelogicoftheoriginalqueryinsomewayWhentheapplicationattemptstoexecutethequerytheattackersmaliciouscodeisexecutedinstead

SQLinjectionexamplesManywebdevelopersdonotrealizehowSQLqueriescanbetamperedwithandmayholdthemisconceptionthattheyaretrustedcommandsAseveryoneknowsSQLqueriesareabletocircumventaccesscontrolstherebybypassingthestandardauthenticationandauthorizationchecksWhatsmoreitspossibletorunSQLqueriesthroughcommandsatthelevelofthehostsystem

LetshavealookatsomerealexamplestoexplaintheprocessofSQLinjectionindetail

Considerthefollowingsimpleloginform

ltformaction=loginmethod=POSTgt

ltpgtUsernameltinputtype=textname=usernamegtltpgt

ltpgtPasswordltinputtype=passwordname=passwordgtltpgt

ltpgtltinputtype=submitvalue=Logingtltpgt

ltformgt

Ourformprocessingmightlooklikethis

username=rFormGet(username)

password=rFormGet(password)

sql=SELECTFROMuserWHEREusername=+username+ANDpassword=+password+

Iftheuserinputsausernameorpasswordas

myuserorfoo=foo--

ThenourSQLbecomesthefollowing

SELECTFROMuserWHEREusername=myuserorfoo=foo--ANDpassword=xxx

InSQLanythingafter--isacommentThusinsertingthe--astheattackerdidabovealtersthequeryinafatalwayallowinganattackertosuccessfullyloginasauserwithoutavalidpassword

FarmoredangerousexploitsexistforMSSQLSQLinjectionsandsomecanevenperformsystemcommandsThefollowingexampleswilldemonstratehowterribleSQLinjectionscanbeinsomeversionsofMSSQLdatabases

sql=SELECTFROMproductsWHEREnameLIKE+prod+

DbExec(sql)

SQLinjection

219

Ifanattackersubmitsaexecmasterxp_cmdshellnetusertesttestpassADD--astheprodvariablethenthesqlwillbecome

sql=SELECTFROMproductsWHEREnameLIKEaexecmasterxp_cmdshellnetusertesttestpassADD--

TheMSSQLServerexecutestheSQLstatementincludingthecommandsintheusersuppliedprodvariablewhichaddsnewuserstothesystemIfthisprogramisrunasisandtheMSSQLSERVERservicehassufficientprivilegesanattackercanregisterasystemaccounttoaccessthismachine

AlthoughtheexamplesabovearetiedtoaspecificdatabasesystemthisdoesnotmeanthatotherdatabasesystemscannotbesubjectedtosimilartypesofattacksTheprinciplesbehindSQLinjectionattacksremainthesamethoughthemethodwithwhichtheyareperpetratedmayvary

HowtopreventSQLinjectionYoumightbethinkingthatanattackerwouldhavetoknowinformationaboutthetargetdatabasesstructureinordertocarryoutanSQLinjectionattackWhilethisistrueitsdifficulttoguaranteethatanattackerwontbeabletofindthisinformationandoncetheygetitthedatabasecanbecompromisedIfyouareusingopensourcesoftwaretoaccessthedatabasesuchasaforumapplicationintruderscaneasilygettherelatedcodeObviouslywithpoorlydesignedcodethesecurityrisksareevengreaterDiscuzphpwindandphpcmsaresomeexamplesofpopularopensourceprogramsthathavebeenvulnerabletoSQLinjectionattacks

TheseattackshappentosystemswheresafetyprecautionsarenotprioritizedWevesaiditbeforewellsayitagainnevertrustanykindofinputespeciallyuserdataThisincludesdatacomingfromselectionboxeshiddeninputfieldsorcookiesAsourfirstexampleabovehasshownevensupposedlynormalqueriescancausedisasters

SQLinjectionattackscanbedevastating-howcandoweevenbegintodefendagainstthemThefollowingsuggestionsareagoodstartingpointforpreventingSQLinjection

1 Strictlylimitpermissionsfordatabaseoperationssothatusersonlyhavetheminimumsetofpermissionsrequiredtoaccomplishtheirworkthusminimizingtheriskofdatabaseinjectionattacks

2 CheckthatinputdatahastheexpecteddataformatandstrictlylimitthetypesofvariablesthatcanbesubmittedThiscaninvolveregexpmatchingorusingthestrconvpackagetoconvertstringsintootherbasictypesforsanitizationandevaluation

3 Transcodeorescapefrompairsofspecialcharacters(ampetc)beforepersistingthemintothedatabaseGostexttemplatepackagehasaHTMLEscapeStringfunctionthatcanbeusedtoreturnescapedHTML

4 UseyourdatabasesparameterizedqueryinterfaceParameterizedstatementsuseparametersinsteadofconcatenatinguserinputvariablesinembeddedSQLstatementsinotherwordstheydonotdirectlyspliceSQLstatementsForexampleusingthePreparefunctioninGosdatabasesqlpackagewecancreatepreparedstatementsforlaterexecutionwithQueryorExec(querystringargsinterface)

5 BeforereleasingyourapplicationthoroughlytestitusingprofessionaltoolsfordetectingSQLinjectionvulnerabilitiesandtorepairthemiftheyexistTherearemanyonlineopensourcetoolsthatdojustthissuchassqlmapSQLninjatonameafew

6 AvoidprintingoutSQLerrorinformationonpublicwebpagesAttackerscanusetheseerrormessagestocarryoutSQLinjectionattacksExamplesofsucherrorsaretypeerrorsfieldsnotmatchingerrorsoranyerrorscontainingSQLstatements

SummaryThroughtheaboveexampleswevelearnedthatSQLinjectionisaveryrealandverydangerouswebsecurityvulnerabilityWhenwewritewebapplicationweshouldpayattentiontoeverylittledetailandtreatsecurityissueswiththeutmostcareDoingsowillleadtobetterandmoresecurewebapplicationsandcanultimatelybethedetermingfactorinwhetherornotyourapplicationsucceeds

SQLinjection

220

LinksDirectoryPrevioussectionXSSattacksNextsectionPasswordstorage

SQLinjection

221

95PasswordstorageOvertheyearsmanywebsiteshavesufferedfrombreachesinuserpassworddataEventopinternetcompaniessuchasLinkedinandCSDNnethavebeenaffectedTheimpactoftheseeventshasbeenfeltacrosstheentireinternetandcannotbeunderestimatedThisisespeciallythecasefortodaysinternetuserswhooftenadoptthehabitofusingthesamepasswordformanydifferentwebsites

AswebdeveloperswehavemanychoiceswhenitcomestoimplementingapasswordstorageschemeHoweverthisfreedomisoftenadoubleedgedswordSowhatarethecommonpitfallsandhowcanweavoidfallingintothem

BadsolutionCurrentlythemostfrequentlyusedpasswordstorageschemeistoone-wayhashplaintextpasswordsbeforestoringthemThemostimportantcharacteristicofone-wayhashingisthatitisnotfeasibletorecovertheoriginaldatagiventhehasheddata-hencetheone-wayinone-wayhashingCommonlyusedcryptographicone-wayhashalgorithmsincludeSHA-256SHA-1MD5andsoon

YoucaneasilyusethethreeaforementionedhashingalgorithmsinGoasfollows

importcryptosha256

h=sha256New()

ioWriteString(hHismoneyistwicetaintedtaintyoursandtaintmine)

fmtPrintf(xhSum(nil))

importcryptosha1

h=sha1New()

ioWriteString(hHismoneyistwicetaintedtaintyoursandtaintmine)

fmtPrintf(xhSum(nil))

importcryptomd5

h=md5New()

ioWriteString(h需要加密的密码)

fmtPrintf(xhSum(nil))

Therearetwokeyfeaturesofone-wayhashing

1)givenaone-wayhashofapasswordtheresultingsummaryisalwaysuniquelydetermined2)calculationspeedAstechnologyadvancesitonlytakesasecondtocompletebillionsofone-wayhashcalculations

GiventhecombinationoftheabovetwocharacteristicsandtakingintoaccountthefactthatthemajorityofpeopleusesomecombinationofcommonpasswordsanattackercancomputeacombinationofallthecommonpasswordsEventhoughthepasswordsyoustoreinyourdatabasemaybehashvaluesonlyifattackersgainaccesstothisdatabasetheycancomparethestoredhashestotheirprecomputedhashestoobtainthecorrespondingpasswordsThistypeofattackreliesonwhatistypicallycalledarainbowtable

Wecanseethathashinguserdatausingone-wayhashesmaynotbeenoughOnceawebsitesdatabasegetsleakedtheusersoriginalpasswordcouldpotentiallyberevealedtotheworld

GoodsolutionThemethodmentionedabovemayhavebeensecureenoughtothwartmosthackingattemptsafewyearsagosincemostattackerswouldnothavehadthecomputingresourcestocomputelargerainbowtablesHoweverwiththeriseofparallelcomputingcapabilitiesthesetypesofattacksarebecomingmoreandmorefeasible

Passwordstorage

222

HowdowesecurelystoreapasswordsothatitcannotbedecipheredbyathirdpartygivenreallifelimitationsintimeandmemoryresourcesThesolutionistocalculateahashedpasswordtodeliberatelyincreasetheamountofresourcesandtimeitwouldtaketocrackitWewanttodesignahashsuchthatnobodycouldpossiblyhavetheresourcesrequiredtocomputetherequiredrainbowtable

VerysecuresystemsutilizehashalgorithmsthattakeintoaccountthetimeandresourcesitwouldrequiretocomputeagivenpassworddigestThisallowsustocreatepassworddigeststhatarecomputationallyexpensivetoperformonalargescaleThegreatertheintensityofthecalculationthemoredifficultitwillbeforanattackertopre-computerainbowtables-somuchsothatitmayevenbeinfeasibletotry

InGoitsrecommendedthatyouusethebcryptpackage

Thepackagessourcecodecanbefoundatthefollowinglinkhttpsgithubcomgolangcryptoblobmasterbcryptbcryptgo

Hereisanexamplecodesnippetwhichcanbeusedtohashstoreandvalidateuserpasswords

packagemain

import(

fmt

log

golangorgxcryptobcrypt

)

funcmain()

userPassword1=someuser-providedpassword

Generatehashtostorefromuserpassword

hasherr=bcryptGenerateFromPassword([]byte(userPassword1)bcryptDefaultCost)

iferr=nil

TODOProperlyhandleerror

logFatal(err)

fmtPrintln(Hashtostorestring(hash))

Storethishashsomewhereeginyourdatabase

Afterawhiletheuserwantstologinandyouneedtocheckthepasswordheentered

userPassword2=someuser-providedpassword

hashFromDatabase=hash

Comparingthepasswordwiththehash

iferr=bcryptCompareHashAndPassword(hashFromDatabase[]byte(userPassword2))err=nil

TODOProperlyhandleerror

logFatal(err)

fmtPrintln(Passwordwascorrect)

SummaryIfyoureworriedaboutthesecurityofyouronlinelifeyoucantakethefollowingsteps

1)AsaregularinternetuserwerecommendusingLastPassforpasswordstorageandgenerationondifferentsitesusedifferentpasswords

2)AsaGowebdeveloperwestronglysuggestthatyouuseoneoftheprofessionalwelltestedmethodsaboveforstoringuserpasswords

LinksDirectory

Passwordstorage

223

PrevioussectionSQLinjectionNextsectionEncryptanddecryptdata

Passwordstorage

224

96EncryptinganddecryptingdataTheprevioussectiondescribeshowtosecurelystorepasswordsbutsometimesitmightbeneccessarytomodifysomesensitiveencrypteddatathathasalreadybeenstoredintoourdatabaseWhendatadecryptionisrequiredweshoulduseasymmetricencryptionalgorithminsteadoftheone-wayhashingtechniqueswevepreviouslycovered

AdvancedencryptionanddecryptionTheGolanguagesupportssymmetricencryptionalgorithmsinitscryptopackageDonotuseanythingexceptAESinGCMmodeifyoudontknowwhatyouredoing

cryptoaespackageAES(AdvancedEncryptionStandard)alsoknownasRijndaelencryptionmethodisusedbytheUSfederalgovernmentasablockencryptionstandard

InthefollowingexamplewedemonstratehowtoencryptdatausingAESinGCMmode

Encryptanddecryptdata

225

packagemain

import(

cryptoaes

cryptocipher

cryptorand

errors

fmt

io

log

)

funcmain()

text=[]byte(MynameisAstaxie)

key=[]byte(the-key-has-to-be-32-bytes-long)

ciphertexterr=encrypt(textkey)

iferr=nil

TODOProperlyhandleerror

logFatal(err)

fmtPrintf(s=gtxntextciphertext)

plaintexterr=decrypt(ciphertextkey)

iferr=nil

TODOProperlyhandleerror

logFatal(err)

fmtPrintf(x=gtsnciphertextplaintext)

funcencrypt(plaintext[]bytekey[]byte)([]byteerror)

cerr=aesNewCipher(key)

iferr=nil

returnnilerr

gcmerr=cipherNewGCM(c)

iferr=nil

returnnilerr

nonce=make([]bytegcmNonceSize())

if_err=ioReadFull(randReadernonce)err=nil

returnnilerr

returngcmSeal(noncenonceplaintextnil)nil

funcdecrypt(ciphertext[]bytekey[]byte)([]byteerror)

cerr=aesNewCipher(key)

iferr=nil

returnnilerr

gcmerr=cipherNewGCM(c)

iferr=nil

returnnilerr

nonceSize=gcmNonceSize()

iflen(ciphertext)ltnonceSize

returnnilerrorsNew(ciphertexttooshort)

nonceciphertext=ciphertext[nonceSize]ciphertext[nonceSize]

returngcmOpen(nilnonceciphertextnil)

Encryptanddecryptdata

226

CallingtheabovefunctionaesNewCipher(whose[]bytekeyparametermustbe1624or32correspondingtotheAES-128AES-192orAES-256algorithmsrespectively)returnsacipherBlockInterfacethatimplementsthreefunctions

typeBlockinterface

BlockSizereturnstheciphersblocksize

BlockSize()int

Encryptencryptsthefirstblockinsrcintodst

Dstandsrcmaypointatthesamememory

Encrypt(dstsrc[]byte)

Decryptdecryptsthefirstblockinsrcintodst

Dstandsrcmaypointatthesamememory

Decrypt(dstsrc[]byte)

ThesethreefunctionsimplementencryptionanddecryptionoperationsseetheGodocumentationforamoredetailedexplanation

SummaryThissectiondescribesencryptionalgorithmswhichcanbeusedindifferentwaysaccordingtoyourwebapplicationsencryptionanddecryptionneedsForapplicationswithevenbasicsecurityrequirementsitisrecommendedtouseAESinGCMmode

LinksDirectoryPreviousstorepasswordsNextSummary

Encryptanddecryptdata

227

97SummaryInthischapterwevedescribedCSRFXSSandSQLinjectionbasedattacksMostwebapplicationsarevulnerabletothesetypesofattacksduetoalackofadequateinputfilteringonthepartoftheapplicationSoinadditiontointroducingtheprinciplesbehindtheseattackswevealsointroducedafewtechniquesforeffectivelyfilteringuserdataandpreventingtheseattacksfromevertakingplaceWethendiscussedafewmethodsforsecurelystoringuserpasswordsfirstintroducingbasicone-wayhashingforwebapplicationswithloosesecurityrequirementsthenpasswordsaltingandencryptionalgorithmsformoreseriousapplicationsFinallywebrieflydiscussedtwo-wayhashingandtheencryptionanddecryptionofsensitivedataWelearnedthattheGolanguageprovidespackagesforthreesymmetricencryptionalgorithmsbase64AESandDESThepurposeofthischapteristohelpreadersbecomemoreconsciousofthesecurityissuesthatexistinmoderndaywebapplicationsHopefullyitcanhelpdeveloperstoplananddesigntheirwebapplicationsalittlemorecarefullysotheycanwritesystemsthatareabletopreventhackersfromexploitinguserdataTheGolanguagehasalargeandwelldesignedanti-attacktoolkitandeveryGodevelopershouldtakefulladvantageofthesepackagestobettersecuretheirwebapplications

LinksDirectoryPrevioussectionEncryptanddecryptdataNextchapterInternationalizationandlocalization

Summary

228

10InternationalizationandlocalizationInordertoadapttotheincreasingglobalizationoftheinternetasdeveloperswemaysometimesneedtobuildmultilingualinternationalwebapplicationsThismeansthatsomepageswillappearindifferentlanguagesaccordingtouserregionsandperhapstheUIandUXwillalsobeadaptedtoshowdifferenteffectsbasedonlocalholidaysorcultureForexampleatruntimetheapplicationwillbeabletorecognizeandprocessrequestscomingfromdifferentgeographicalregionsandrenderpagesinthelocaldialectordisplaydifferentuserinterfaceAscompetentdeveloperswedontwanttohavetomanuallymodifyourapplicationssourcecodetocatertoeverypossibleregionoutthereWhenanapplicationneedstoaddsupportforanewlanguageweshouldbeabletosimplydropintheappropriatelanguagepackandbedonewithit

Inthissectionwellbetalkingaboutinternationalizationandlocalization(usuallyexpressedasi18nandL10Nrespectively)InternationalizationistheprocessofdesigningapplicationsthatareflexibleenoughtobeservedtomultipleregionsaroundtheworldInsomewayswecanthinkofinternationalizationassomethingthathelpstofacilitatelocalizationwhichistheadaptationofawebapplicationscontentanddesigntosuitthelanguageorculturalneedsofspecificlocales

CurrentlyGosstandardpackagedoesnotprovidei18nsupportbuttherearesomeusefulandrelativelysimplethird-partyimplementationsavailableInthischapterwellbeusingtheopen-sourcego-i18nlibrarytosupportinternationalizationinourexamples

WhenwetalkaboutmakingourwebapplicationsinternationalwemeanthateachwebpageshouldbeconstructedwithlocalespecificinformationandassembledwiththecorrespondinglocalstringstimeandcurrencyformatsetcThisinvolvesthreethings

1 howtodeterminetheuserslocale

2 howtosavestringsorotherinformationassociatedwiththelocale

3 howtoembedstringsandotherinformationaccordingtotheuserslocale

InthefirstsectionwelldescribehowtodetectandsetthecorrectlocaleinordertoallowwebsiteusersaccesstotheirlanguagespecificpagesThesecondsectiondescribeshowtohandleorstorestringscurrenciestimesdatesandotherlocalerelatedinformationFinallythethirdsectionwilldescribehowtointernationalizeyourwebapplicationmorespecificallywelldiscusshowtoreturndifferentpageswithlocaleappropriatecontentThroughthesethreesectionswellbeabletosupportfulli18ninourwebapplications

LinksDirectoryPreviousChapterChapter9SummaryNextsectionSettingthedefaultregion

Internationalizationandlocalization

229

101Settingthedefaultregion

FindingoutthelocaleAlocaleisasetofdescriptorsforaparticulargeographicalregionandcanincludespecificlanguagehabitstextformattingculturalidiomsandamultitudeofothersettingsAlocalesnameisusuallycomposedofthreepartsFirst(andmandatory)isthelocaleslanguageabbreviationsuchasenforEnglishorzhforChineseThesecondpartisanoptionalcountryspecifierandfollowsthefirstwithanminussignThisspecifierallowswebapplicationstodistinguishbetweendifferentcountrieswhichspeakthesamelanguagesuchasen-USforUSEnglishanden-GBforBritishEnglishThelastpartisanotheroptionalspecifierandisaddedtothelocalewithaperiodItspecifieswhichcharactersettouseforinstancezh-CNgb2312specifiesthegb2312charactersetforChinese

GodefaultstotheUTF-8encodingsetsoi18ninGoapplicationsdonotneedtoconsiderthelastparameterThusinourexampleswellonlyusethefirsttwopartsoflocaledescriptionsasourstandardi18nlocalenames

OnLinuxandSolarissystemsyoucanusethelocale-acommandtogetalistofallsupportedregionalnamesYoucanusethislistasexamplesofsomecommonlocalesForBSDandothersystemsthereisnolocalecommandbuttheregionalinformationisstoredinusrsharelocale

SettingthelocaleNowthatwevedefinedwhatalocaleisweneedtobeabletosetitaccordingtovisitingusersinformation(eitherfromtheirpersonalsettingsthevisiteddomainnameetc)Herearesomemethodswecanusetosettheuserslocale

Fromthedomainname

WecansetauserslocaleviathedomainnameitselfwhentheapplicationusesdifferentdomainsfordifferentregionsForexamplewecanusewwwastacomasourdefaultEnglishwebsiteandthedomainnamewwwastacnasitsChinesecounterpartBysettingupseparatedomainsforseparateregionsyoucandetectandservetherequestedlocaleThistypeofsetuphasseveraladvantages

IdentifyingthelocaleviaURLisdistinctiveandunambiguousUsersintuitivelyknowwhichdomainnamestovisitfortheirspecificregionorlanguageImplementingthisschemeinaGoapplicationisverysimpleandconvenientandcanbeachievedthroughamapConducivetosearchenginecrawlerswhichcanimprovethesitesSEO

Wecanusethefollowingcodetoimplementacorrespondingdomainnamelocale

ifrHost==wwwastacom

i18nSetLocale(en)

elseifrHost==wwwastacn

i18nSetLocale(zh-CN)

elseifrHost==wwwastatw

i18nSetLocale(zh-TW)

Alternativelywecouldhavealsosetlocalesthroughtheuseofsub-domainsuchasenastacomforEnglishsitesandcnastacomforChinesesiteThisschemecanberealizedincodeasfollows

Timezone

230

prefix=stringsSplit(rHost)

ifprefix[0]==en

i18nSetLocale(en)

elseifprefix[0]==cn

i18nSetLocale(zh-CN)

elseifprefix[0]==tw

i18nSetLocale(zh-TW)

Settinglocalesfromthedomainnameaswevedoneabovehasitsadvantageshoweverl10nisgenerallynotimplementedinthiswayFirstofallthecostofdomainnames(althoughusuallyquiteaffordableindividually)canquicklyaddupgiventhateachlocalewillneeditsowndomainnameandoftenthenameofthedomainwillnotnecessarilyfitinwiththelocalcontextSecondlywedontwanttohavetoindividuallyconfigureeachwebsiteforeachlocaleRatherweshouldbeabletodothisprogrammaticallyforinstancebyusingURLparametersLetshavealookatthefollowingdescription

FromURLparameters

Themostcommonwayofimplementingl10nistosetthedesiredlocaledirectlyintheURLparameterssuchwwwastacomhellolocale=zhorwwwastacomzhhelloThiswaywecansettheregionlikesoi18nSetLocale(params[locale])

ThissetuphasalmostalltheadvantagesofprependingthelocaleinfrontofthedomainanditsRESTfulsowedontneedtoaddadditionalmethodstoimplementitThedownsidetothisapproachisthatitrequiresacorrespondinglocaleparameterinsideeachlinkwhichcanbequitecumbersomeandmayincreasecomplexityHoweverwecanwriteagenericfunctionthatproducestheselocale-specificURLssothatalllinksaregeneratedthroughitThisfunctionshouldautomaticallyaddalocaleparametertoeachlinksowhenusersclickthemweareabletoparsetheirrequestswitheaselocale=params[locale]

PerhapswewantourURLstolookevenmoreRESTfulForexamplewecouldmapeachofourresourcesunderaspecificlocalelikewwwastacomenbooksforourEnglishsiteandwwwastacomzhbooksfortheChineseoneThisapproachisnotonlymoreconducivetoURLSEObutisalsomorefriendlyforusersAnybodyvisitingthesiteshouldbeabletoaccesslocale-specificwebsiteresourcesdirectlyfromtheURLSuchURLaddressescanthenbepassedthroughtheapplicationrouterinordertoobtaintheproperlocale(refertotheRESTsectionwhichdescribestherouterplug-inimplementation)

muxGet(localebookslistbook)

Fromtheclientsettingsarea

InsomespecialcaseswerequireexplicitclientinformationinordertosetthelocaleratherthanobtainingitfromtheURLorURLparametersThisinformationmaycomedirectlyfromtheclientsbrowsersettingstheusersIPaddressorthelocationsettingsfilledoutbytheuseratthetimeofregistrationThisapproachismoresuitableforweb-basedapplications

Accept-Language

WhenaclientrequestsinformationusinganHTTPheadersetwiththeAccept-LanguagefieldwecanusethefollowingGocodetoparsetheheaderandsettheappropriateregioncode

AL=rHeaderGet(Accept-Language)

ifAL==en

i18nSetLocale(en)

elseifAL==zh-CN

i18nSetLocale(zh-CN)

elseifAL==zh-TW

i18nSetLocale(zh-TW)

Ofcourseinrealworldapplicationswemayrequiremorerigorousprocessesandrulesforsettinguserregions

Timezone

231

IPAddress

AnotherwayofsettingaclientsregionistolookattheusersIPaddressWecanusethepopularGeoIPGeoLiteCountryorCitylibrariestohelpusrelateuserIPaddressestotheircorrespondingregionalareasImplementingthismechanismisverysimpleweonlyneedtolookuptheusersIPaddressinsideourdatabaseandthenreturnlocale-specificcontentaccordingtowhichregionwasreturned

Userprofile

Youcanalsoletusersprovideyouwiththeirlocaleinformationthroughaninputelementsuchasadrop-downmenu(orsomethingsimilar)WhenwereceivethisinformationwecansaveittotheaccountassociatedwiththeusersprofileWhentheuserlogsinagainwewillbeabletocheckandsettheirlocalesettings-thisguaranteesthateverytimetheuseraccessesthewebsitethereturnedcontentwillbebasedontheirpreviouslysetlocale

SummaryInthissectionwevedemonstratedavarietyofwayswithwhichuserspecificlocalescanbedetectedandsetThesemethodsincludedsettingtheuserlocaleviadomainnamesubdomainnameURLparametersanddirectlyfromclientsettingsBycateringtothespecificneedsofspecificregionswecanprovideacomfortablefamiliarandintuitiveenvironmentforuserstoaccesstheservicesthatweprovide

LinksDirectoryPreviousoneInternationalizationandlocalizationNextsectionLocalizedresources

Timezone

232

102LocalizedResourcesTheprevioussectiondescribedhowtosetlocalesAfterthelocalehasbeensetwethenneedtoaddresstheproblemofstoringtheinformationcorrespondingtospecificlocalesThisinformationcanincludetextualcontenttimeanddatecurrencyvaluespicturesspecificfilesandotherviewresourcesInGoallofthiscontextualinformationisstoredinJSONformatonourbackendtobecalleduponandinjectedintoourviewswhenusersfromspecificregionsvisitourwebsiteForexampleEnglishandChinesecontentwouldbestoredinenjsonandzh-CNjsonfilesrespectively

LocalizedtextualcontentPlaintextisthemostcommonwayofrepresentinginformationinwebapplicationsandthebulkofyourlocalizedcontentwilllikelytakethisformThegoalistoprovidetextualcontentthatisbothidiomatictoregionalexpressionsandfeelsnaturalforforeignusersofyoursiteOnesolutionistocreateanestedmapoflocalesnativelanguagestringsandtheirlocalcounterpartsWhenclientsrequestpageswithsometextualcontentwefirstchecktheirdesiredlocalethenretrievethecorrespondingstringsfromtheappropriatemapThefollowingsnippetisasimpleexampleofthisprocess

packagemain

importfmt

varlocalesmap[string]map[string]string

funcmain()

locales=make(map[string]map[string]string2)

en=make(map[string]string10)

en[pea]=pea

en[bean]=bean

locales[en]=en

cn=make(map[string]string10)

cn[pea]=豌豆

cn[bean]=毛豆

locales[zh-CN]=cn

lang=zh-CN

fmtPrintln(msg(langpea))

fmtPrintln(msg(langbean))

funcmsg(localekeystring)string

ifvok=locales[locale]ok

ifv2ok=v[key]ok

returnv2

return

Theaboveexamplesetsupmapsoftranslatedstringsfordifferentlocales(inthiscasetheChineseandEnglishlocales)WemapourcntranslationstothesameEnglishlanguagekeyssothatwecanreconstructourEnglishtextmessageinChineseIfwewantedtoswitchourtexttoanyotherlocalewemayhaveimplementeditdbeasimplematterofsettingonelangvariable

Simplekey-valuesubstitutionscansometimesbeinadequateforourneedsForexampleifwehadaphrasesuchasIam30yearsoldwhere30isavariablehowwouldwelocalizeitIncaseslikethesewecancombineusethefmtPrintffunctiontoachievethedesiredresult

en[howold]=Iamdyearsold

cn[howold]=我今年d岁了

fmtPrintf(msg(langhowold)30)

Localizedresources

233

TheexamplecodeaboveisonlyforthepurposeofdemonstrationactuallocaledataistypicallystoredinJSONformatinourdatabaseallowingustoexecuteasimplejsonUnmarshaltopopulatemaplocaleswithourstringtranslations

LocalizeddateandtimeBecauseofourtimezoneconventionsthetimeinoneregionoftheworldcanbedifferentthanthetimeinanotherregionSimilarlythewayinwhichtimeisrepresentedcanalsovaryfromlocaletolocaleForexampleaChineseenvironmentmayread2012年10月24日星期三23时11分13秒CSTwhileinEnglishitmightbeWedOct24231113CST2012NotonlyaretherevariationsinlanguagebuttherearedifferencesinformattingalsoSowhenitcomestolocalizingdatesandtimesweneedtoaddressthefollowingtwopoints

1 timezones2 formattingissues

The$GOROOTlibtimepackagetimeinfozipdirectorycontainslocalescorrespondingtotimezonedefinitionsInordertoobtainthetimecorrespondingtoauserscurrentlocaleweshouldfirstusetimeLoadLocation(namestring)togetaLocationobjectcorrespondingtoourlocalepassinginastringrepresentingthelocalesuchasAsiaShanghaiorAmericaChicagoWecanthenusethisLocationobjectinconjunctionwithaTimeobject(obtainedbycallingtimeNow)togetthefinaltimeusingtheTimeobjectsInmethodAdetailedlookatthisprocesscanbeseenbelow(thisexampleusessomeofthevariablesfromtheexampleabove)

en[time_zone]=AmericaChicago

cn[time_zone]=AsiaShanghai

loc_=timeLoadLocation(msg(langtime_zone))

t=timeNow()

t=tIn(loc)

fmtPrintln(tFormat(timeRFC3339))

Wecanhandletextformattinginasimilarwaytosolveourtimeformattingproblem

en[date_format]=Y-m-dHMS

cn[date_format]=Y年m月d日H时M分S秒

fmtPrintln(date(msg(langdate_format)t))

funcdate(fomatstringttimeTime)string

yearmonthday=tDate()

hourminsec=tClock()

ParsingthecorrespondingYmdHMSandthenreturningtheinformation

Yreplacedby2012

mreplacedby10

dreplacedby24

LocalizedcurrencyvalueObviouslycurrencydiffersfromregiontoregionalsoWecantreatitthesamewaywetreatedourdates

en[money]=USDd

cn[money]=¥d元

fmtPrintln(date(msg(langdate_format)100))

funcmoney_format(fomatstringmoneyint64)string

returnfmtSprintf(fomatmoney)

Localizedresources

234

LocalizationofviewsandresourcesWecanservecustomizedviewswithdifferentimagescssjsandotherstaticresourcesdependingonthecurrentlocaleOnewaytoaccomplishthisisbyorganizingthesefilesintotheirrespectivelocalesHeresanexample

views

|--enEnglishTemplates

|--imagesstorepictureinformation

|--jsJSfiles

|--cssCSSfiles

indextplUserHome

logintplLogHome

|--zh-CNChineseTemplates

|--images

|--js

|--css

indextpl

logintpl

Withthisdirectorystructurewecanrenderlocale-specificviewslikeso

s1_=templateParseFiles(views+lang+indextpl)

VVLang=lang

s1Execute(osStdoutVV)

Theresourcesreferencedintheindextplfilecanbedealtwithasfollows

jsfile

ltscripttype=textjavascriptsrc=viewsVVLangjsjqueryjquery-180minjsgtltscriptgt

cssfile

ltlinkhref=viewsVVLangcssbootstrap-responsivemincssrel=stylesheetgt

Picturefiles

ltimgsrc=viewsVVLangimagesbtnpnggt

Withdynamicviewsandthewaywevelocalizedourresourceswewillbeabletoaddmorelocaleswithoutmucheffort

SummaryThissectiondescribedhowtouseandstorelocalresourcesWelearnedthatwecanuseconversionfunctionsandstringinterpolationforthisandsawthatmapscanbeaneffectivewayofstoringlocale-specificdataForthelatterwecouldsimplyextractthecorrespondinglocaleinformationwhenneeded-ifitwastextualcontentwedesiredourmappedtranslationsandidiomscouldbepipeddirectlytotheoutputIfitwassomethingmoresophisticatedliketimeorcurrencywesimplyusedthefmtPrintffunctiontoformatitbefore-handLocalizingourviewsandresourceswastheeasiestcaseandsimplyinvolvedorganizingourfilesintotheirrespectivelocalesthenreferencingthemfromtheirlocalerelativepaths

LinksDirectoryPrevioussectionSettingthedefaultregionNextsectionInternationalsites

Localizedresources

235

103InternationalsitesTheprevioussectionexplainedhowtodealwithlocalizedresourcesnamelybyusinglocaleconfigurationfilesSowhatcanwedoifweneedtodealwithmultiplelocalizedresourcesliketexttranslationstimesanddatesnumbersetcThissectionwilladdresstheseissuesonebyone

ManagingmultiplelocalepackagesInthedevelopmentofanapplicationoftenthefirstthingyouneedtodoistodecidewhetherornotyouwanttosupportmorethanonelanguageIfyoudodecidetosupportmultiplelanguagesyoullneedtodevelopanorganizationalstructuretofacilitatetheprocessofaddingmorelanguagesinthefutureOnewaywecandothisistoputallourrelatedlocalefilestogetherinaconfiglocalesdirectoryorsomethingofthelikeLetssupposeyouwanttosupportbothChineseandEnglishInthiscaseyoudbeplacingboththeenjsonandzhjsonlocalefilesintotheaforementionedfolderTheircontentswouldprobablylooksomethinglikethefollowing

zhjson

zh

submit提交

create创建

enjson

en

submitSubmit

createCreate

Wedecidedtousesome3rdpartyGopackagestohelpusinternationalizeourwebapplicationsInthecaseofgo-i18n(Amoreadvancedi18npackagecanbefoundhere)wefirsthavetoregisterourconfiglocalesdirectorytoloadallofourlocalefiles

Tr=i18nNewLocale()

TrLoadPath(configlocales)

ThispackageissimpletouseWecantestthatitworkslikeso

fmtPrintln(TrTranslate(submit))

Outputsubmit

TrSetLocale(zn)

fmtPrintln(TrTranslate(submit))

Outputs递交

AutomaticallyloadlocalpackageWevejustdescribedhowtoautomaticallyloadcustomlanguagepacksInfactthego-i18nlibrarycomespre-loadedwithabunchofdefaultformattinginformationsuchastimeandcurrencyformatsThesedefaultconfigurationscanbeoverriddenandcustomizedbyuserstosuittheirneedsConsiderthefollowingprocess

Internationalsites

236

Loadthedefaultconfigurationfileswhichareplacedbelowin`go-i18nlocales`

Fileshouldbenamedzhjsonen-jsonen-USjsonetcsowecancontinuouslysupportmorelanguages

func(ilIL)loadDefaultTranslations(dirPathstring)error

direrr=osOpen(dirPath)

iferr=nil

returnerr

deferdirClose()

nameserr=dirReaddirnames(-1)

iferr=nil

returnerr

for_name=rangenames

fullPath=pathJoin(dirPathname)

fierr=osStat(fullPath)

iferr=nil

returnerr

iffiIsDir()

iferr=illoadTranslations(fullPath)err=nil

returnerr

elseiflocale=ilmatchingLocaleFromFileName(name)locale=

fileerr=osOpen(fullPath)

iferr=nil

returnerr

deferfileClose()

iferr=illoadTranslation(filelocale)err=nil

returnerr

returnnil

Usingtheabovecodetoloadallofourdefaulttranslationswecanthenusethefollowingcodetoselectandusealocale

fmtPrintln(TrTime(timeNow()))

Output2009年1月08日星期四203758CST

fmtPrintln(TrTime(timeNow()long))

Output2009年1月08日

fmtPrintln(TrMoney(1111))

Outputyen1111

TemplatemapfuncAbovewevepresentedonewayofmanagingandintegratinganumberoflanguagepacksSomeofthefunctionsweveimplementedarebasedonthelogicallayerforexampleTrTranslateTrTimeTrMoneyandsoonInthelogicallayerwecanusethesefunctions(aftersupplyingtherequiredparameters)forapplyingyourtranslationsoutputtingtheresultsdirectlytothetemplatelayeratrendertimeWhatcanwedoifwewanttousethesefunctionsdirectlyinthetemplatelayerIncaseyouveforgottenearlierinthebookwementionedthatGotemplatessupportcustomtemplatefunctionsThefollowingcodeshowshoweasymapfuncistoimplement

1textinformation

Internationalsites

237

AsimpletextconversionfunctionimplementingamapfunccanbeseenbelowItusesTrTranslatetoperformtheappropriatetranslations

funcI18nT(argsinterface)string

ok=false

varsstring

iflen(args)==1

sok=args[0](string)

ifok

s=fmtSprint(args)

returnTrTranslate(s)

Weregisterthefunctionlikeso

tFuncs(templateFuncMapTI18nT)

Thenuseitfromyourtemplate

VSubmit|T

1 Thedateandtime

DatesandtimescalltheTrTimefunctiontoperformtheirtranslationsThemapfuncisimplementedasfollows

funcI18nTimeDate(argsinterface)string

ok=false

varsstring

iflen(args)==1

sok=args[0](string)

ifok

s=fmtSprint(args)

returnTrTime(s)

Registerthefunctionlikeso

tFuncs(templateFuncMapTDI18nTimeDate)

Thenuseitfromyourtemplate

VNow|TD

3CurrencyInformation

CurrenciesusetheTrMoneyfunctiontoconvertmoneyThemapFuncisimplementedasfollows

Internationalsites

238

funcI18nMoney(argsinterface)string

ok=false

varsstring

iflen(args)==1

sok=args[0](string)

ifok

s=fmtSprint(args)

returnTrMoney(s)

Registerthefunctionlikeso

tFuncs(templateFuncMapMI18nMoney)

Thenuseitfromyourtemplate

VMoney|M

SummaryInthissectionwelearnedhowtoimplementmultiplelanguagepacksinourwebapplicationsWesawthatthroughcustomlanguagepackswecannotonlyeasilyinternationalizeourapplicationsbutfacilitatetheadditionofotherlanguagesalso(throughtheuseofaconfigurationfile)Bydefaultthego-i18npackagewillprovidesomecommonconfigurationsfortimecurrencyetcwhichcanbeveryconvenienttouseWelearnedthatthesefunctionscanalsobeuseddirectlyfromourtemplatesusingmappingfunctionseachtranslatedstringcanbepipeddirectlytoourtemplatesThisenablesourwebapplicationstoaccommodatemultiplelanguageswithminimaleffort

LinksDirectoryPrevioussectionLocalizedresourcesNextsectionSummary

Internationalsites

239

104SummaryThroughthisintroductorychapteroni18nyoushouldnowbefamiliarwithsomeofthestepsandprocessesthatarenecessaryforinternationalizingandlocalizingyourwebsitesIvealsointroducedanopensourcesolutionfori18ninGogo-i18nUsingthisopensourcelibrarywecaneasilyimplementmulti-languageversionsofourwebapplicationsThisallowsourapplicationstobeflexibleandresponsivetolocalaudiencesallaroundtheworldIfyoufindanerrorinthisopensourcelibraryoranymissingfeaturespleaseopenanissueorapullrequestLetsstrivetomakeitoneofGosstandardlibraries

LinksDirectoryPrevioussectionInternationalsitesNextchapterErrorhandlingdebuggingandtesting

Summary

240

11ErrorHandlingDebuggingandTestingWeoftenseethemajorityofaprogrammersprogrammingtimespentoncheckingforbugsandworkingonbugfixesWhetheryouarerefactoringcodeorre-configuringsystemsmuchofyourtimewillundoubtedlybespenttroubleshootingandtestingFromtheoutsidepeoplemaythinkthatallwedoasprogrammersisdesignoursystemsandthenwriteourcodeTheymightthinkthatwehavetheidealjobWedoworkthatisveryengagingandimplementsystemsthathaveneverbeendonebeforeWhilethislastpartmaybetruewhattheydontknowisthatwespendthemajorityofourtimecyclingbetweentroubleshootingdebuggingandtestingourcodeOfcourseifyouhavegoodprogramminghabitsandthetechnologicalsolutionstohelpyoutakeonthesetasksthenyoucanminimizethetimespentdoingthesethingsenablingyoutofocusinsteadonmorevaluablethingsliketheapplicationlogic

UnfortunatelymanyprogrammersarenotthoroughinfulfillingtheirerrorhandlingdebuggingandtestingresponsibilitiesbeforehandInexperiencedprogrammerswilloftenonlymakeanefforttofinderrorsandflawsaftertheyhaveoccurredspendinghourslocatingandfixingproblemsaftertheapplicationisalreadyonlineItsgoodpractice(andprobablycommonsense)thatweshoulddesignourapplicationswithpropererrorhandlingtestcasesetcfromthegetgoThiswillmakeyourjobandthejobsofalltheotherdeveloperswhomaybeworkingonyourapplicationsomedaymucheasierwhentheyinevitablyneedtomodifythecodeorupgradethesystem

IntheprocessofdevelopingwebapplicationsyouwillinevitablyencounterunforeseenerrorsWhatsthemostefficientwayoffindingthecausesoftheseerrorsandsolvingthemSection111describeshowtohandleerrorsintheGolanguageaswellashowtodesignyourownerrorhandlingpackageandfunctionsSection112describeshowtouseGDBtodebugprogramsunderdynamicoperatingconditionsdependingonavarietyofvariableinformationWethendiscussapplicationmonitoringanddebuggingoperations

Section113willexplainunittestinginGoandfeaturesomein-depthdiscussionsandexamplesonhowtowriteunittestsaswellasdefiningGosunittestingrulesWellseehowfollowingtheseruleswillensurethatwhenupgradingormodifyingyourapplicationthetestcodewillbeabletorunsmoothly

ManyprogrammersavoidspendingtimetolearnandcultivategooddebuggingandtestinghabitsThischaptertakesontheseissueshead-onsoyouwonthavetorunawayfromthesetasksanylongerSinceyourejustlearninghowtobuildwebapplicationsinGoletsusethisopportunitytoestablishthesegoodhabitsfromtheverybeginning

LinksDirectoryPreviouschapterChapter10summaryNextsectionErrorhandling

Errorhandlingdebuggingandtesting

241

111ErrorhandlingGosmajordesignconsiderationsarerootedinthefollowingideasasimpleclearandconcisesyntax(similartoC)andstatementswhichareexplicitanddontcontainanyhiddenorunexpectedthingsGoserrorhandlingschemereflectsalloftheseprinciplesinthewaythatitsimplementedIfyourefamiliarwiththeClanguageyoullknowthatitscommontoreturn-1orNULLvaluestoindicatethatanerrorhasoccurredHoweveruserswhoarenotfamiliarwithCsAPIwillnotknowexactlywhatthesereturnvaluesmeanInCitsnotexplicitwhetheravalueof0indicatessuccessoffailureOntheotherhandGoexplicitlydefinesatypecallederrorforthesolepurposeofexpressingerrorsWheneverafunctionreturnswechecktoseewhethertheerrorvariableisnilornottodetermineiftheoperationwassuccessfulForexampletheosOpenfunctionfailsitwillreturnanon-nilerrorvariable

funcOpen(namestring)(fileFileerrerror)

HeresanexampleofhowwedhandleanerrorinosOpenFirstweattempttoopenafileWhenthefunctionreturnswechecktoseewhetheritsucceededornotbycomparingtheerrorreturnvaluewithnilcallinglogFataltooutputanerrormessageifitsanon-nilvalue

ferr=osOpen(filenameext)

iferr=nil

logFatal(err)

SimilartotheosOpenfunctionthefunctionsinGosstandardpackagesallreturnerrorvariablestofacilitateerrorhandlingThissectionwillgointodetailaboutthedesignoferrortypesanddiscusshowtoproperlyhandleerrorsinwebapplications

Errortypeerrorisaninterfacetypewiththefollowingdefinition

typeerrorinterface

Error()string

errorisabuilt-ininterfacetypeWecanfinditsdefinitioninthebuiltinpackagebelowWealsohavealotofinternalpackageswhichuseerrorinaprivatestructurecallederrorStringwhichimplementstheerrorinterface

errorStringisatrivialimplementationoferror

typeerrorStringstruct

sstring

func(eerrorString)Error()string

returnes

YoucanconvertaregularstringtoanerrorStringthrougherrorsNewinordertogetanobjectthatsatisfiestheerrorinterfaceItsinternalimplementationisasfollows

Newreturnsanerrorthatformatsasthegiventext

funcNew(textstring)error

returnamperrorStringtext

Errorhandling

242

ThefollowingexampledemonstrateshowtouseerrorsNew

funcSqrt(ffloat64)(float64error)

ifflt0

return0errorsNew(mathsquarerootofnegativenumber)

implementation

InthefollowingexamplewepassanegativenumbertoourSqrtfunctionCheckingtheerrvariablewecheckwhethertheerrorobjectisnon-nilusingasimplenilcomparisonTheresultofthecomparisonistruesofmtPrintln(thefmtpackagecallstheerrormethodwhendealingwitherrorcalls)iscalledtooutputanerror

ferr=Sqrt(-1)

iferr=nil

fmtPrintln(err)

CustomErrorsThroughtheabovedescriptionweknowthatagoErrorisaninterfaceBydefiningastructthatimplementsthisinterfacewecanimplementtheirerrordefinitionsHeresanexamplefromtheJSONpackage

typeSyntaxErrorstruct

msgstringerrordescription

Offsetint64wheretheerroroccurred

func(eSyntaxError)Error()stringreturnemsg

TheerrorsOffsetfieldwillnotbeprintedatruntimewhensyntaxerrorsoccurbutusingatypeassertionerrortypeyoucanprintthedesirederrormessage

iferr=decDecode(ampval)err=nil

ifserrok=err(jsonSyntaxError)ok

linecol=findLine(fserrOffset)

returnfmtErrorf(sddvfName()linecolerr)

returnerr

ItshouldbenotedthatwhenthefunctionreturnsacustomerrorthereturnvalueissettotherecommendedtypeoferrorratherthanacustomerrortypeBecarefulnottopre-declarevariablesofcustomerrortypesForexample

funcDecode()SyntaxError

errorwhichmayleadtothecallerserr=nilcomparisontoalwaysbetrue

varerrSyntaxErrorpre-declareerrorvariable

ifanerrorcondition

err=ampSyntaxError

returnerrerrorerralwaysequalnon-nilcausescallerserr=nilcomparisontoalwaysbetrue

Seehttpgolangorgdocfaqnil_errorforanindepthexplanation

TheaboveexampleshowshowtoimplementasimplecustomErrortypeButwhatifweneedmoresophisticatederrorhandlingInthiscasewehavetorefertothenetpackageapproach

Errorhandling

243

packagenet

typeErrorinterface

error

Timeout()boolIstheerroratimeout

Temporary()boolIstheerrortemporary

UsingtypeassertionwecancheckwhetherornotourerrorisoftypenetErrorasshowninthefollowingexampleThisallowsustorefineourerrorhandling-ifatemporaryerroroccursonthenetworkitwillsleepfor1secondthenretrytheoperation

ifnerrok=err(netError)okampampnerrTemporary()

timeSleep(1e9)

continue

iferr=nil

logFatal(err)

ErrorhandlingGohandleserrorsandchecksthereturnvaluesoffunctionsinaC-likefashionwhichisdifferenttohowmostoftheothermajorlanguagesdoThismakesthecodemoreexplicitandpredictablebutalsomoreverboseToreducetheredundancyofourerror-handlingcodewecanuseabstracterrorhandlingfunctionsthatallowustoimplementsimilarerrorhandlingbehaviour

funcinit()

httpHandleFunc(viewviewRecord)

funcviewRecord(whttpResponseWriterrhttpRequest)

c=appengineNewContext(r)

key=datastoreNewKey(cRecordrFormValue(id)0nil)

record=new(Record)

iferr=datastoreGet(ckeyrecord)err=nil

httpError(werrError()500)

return

iferr=viewTemplateExecute(wrecord)err=nil

httpError(werrError()500)

TheaboveexampledemonstratehowthedataaccessandtemplatecallhasdetectedanerrorWhenanerroroccursacalltounifiedhandlerhttpErrorreturnsa500errorcodetotheclientanddisplaysthecorrespondingerrordataButwhenmoreandmoreHandleFunccallsaremadesoerror-handlinglogiccodewillincreaseWecancustomizetheroutertoreducecode(refertothethirdchapterofHTTPformoredetail)

typeappHandlerfunc(httpResponseWriterhttpRequest)error

func(fnappHandler)ServeHTTP(whttpResponseWriterrhttpRequest)

iferr=fn(wr)err=nil

httpError(werrError()500)

AbovewevedefinedacustomrouterWecanthenregisterourhandlerasusual

Errorhandling

244

funcinit()

httpHandle(viewappHandler(viewRecord))

Theviewhandlercanthenbehandledbythefollowingcodeitisalotsimplerthanouroriginalimplementationisntit

funcviewRecord(whttpResponseWriterrhttpRequest)error

c=appengineNewContext(r)

key=datastoreNewKey(cRecordrFormValue(id)0nil)

record=new(Record)

iferr=datastoreGet(ckeyrecord)err=nil

returnerr

returnviewTemplateExecute(wrecord)

Theerrorhandlerexampleabovewillreturnthe500InternalErrorcodetouserswhenanyerrorsoccurinadditiontoprintingoutthecorrespondingerrorcodeInfactwecancustomizethetypeoferrorreturnedtooutputamoredeveloperfriendlyerrormessagewithinformationthatisusefulfordebugginglikeso

typeappErrorstruct

Errorerror

Messagestring

Codeint

Ourcustomroutercanbechangedaccordingly

typeappHandlerfunc(httpResponseWriterhttpRequest)appError

func(fnappHandler)ServeHTTP(whttpResponseWriterrhttpRequest)

ife=fn(wr)e=nileisappErrornotosError

c=appengineNewContext(r)

cErrorf(veError)

httpError(weMessageeCode)

Afterwevefinishedmodifyingourcustomerrorourlogiccanbechangedasfollows

funcviewRecord(whttpResponseWriterrhttpRequest)appError

c=appengineNewContext(r)

key=datastoreNewKey(cRecordrFormValue(id)0nil)

record=new(Record)

iferr=datastoreGet(ckeyrecord)err=nil

returnampappErrorerrRecordnotfound404

iferr=viewTemplateExecute(wrecord)err=nil

returnampappErrorerrCantdisplayrecord500

returnnil

AsshownabovewecanreturndifferenterrorcodesanderrormessagesinourviewsdependingonthesituationAlthoughthisversionofourcodefunctionssimilarlytothepreviousversionitsmoreexplicitanditserrormessagepromptsaremorecomprehensibleAllofthesefactorscanhelptomakeyourapplicationmorescalableascomplexityincreases

Summary

Errorhandling

245

FaulttoleranceisaveryimportantaspectofanyprogramminglanguageInGoitisachievedthrougherrorhandlingAlthoughErrorisonlyoneinterfaceitcanhavemanyvariationsinthewaythatitsimplementedandwecancustomizeitaccordingtoourneedsonacasebycasebasisByintroducingthesevariouserrorhandlingconceptswehopethatyouwillhavegainedsomeinsightonhowtoimplementbettererrorhandlingschemesinyourownwebapplications

LinksDirectoryPrevioussectionErrorhandlingdebuggingandtestingNextsectionDebuggingbyusingGDB

Errorhandling

246

112DebuggingwithGDBDuringthedevelopmentprocessofanyapplicationdeveloperswillalwaysneedtoperformsomekindofcodedebuggingPHPPythonandmostoftheotherdynamiclanguagesareabletobemodifiedatruntimeaslongasthemodificationsdonotexplicitlyneedtobecompiledWecaneasilyprintdataindynamicoperatingenvironmentsoutputtingourchangesandprintingvariableinformationdirectlyInGoyoucanofcoursespeckleyourcodewithPrintlnsbefore-handtodisplayvariableinformationfordebuggingpurposesbutanychangestoyourcodeneedtoberecompiledeverytimeThiscanquicklybecomecumbersomeIfyouveprogrammedinPythonorJavascriptyoullknowthattheformerprovidestoolssuchaspdbandipdbfordebuggingandthelatterhassimilartoolsthatareabletodynamicallydisplayvariableinformationandfacilitatesingle-stepdebuggingFortunatelyGohasnativesupportforasimilartoolwhichprovidessuchdebuggingfeaturesGDBThissectionservesasabriefintroductionintodebuggingGoapplicationsusingGDB

GDBdebuggingprofileGDBisapowerfuldebuggingtooltargetingUNIX-likesystemsreleasedbytheFSF(FreeSoftwareFoundation)GDBallowsustodothefollowingthings

1 Initialsettingscanbecustomizeaccordingtothespecificrequirementsofyourapplication2 Canbesetsothattheprogrambeingdebuggedinthedevelopersconsolestopsattheprescribedbreakpoints

(breakpointscanbeconditionalexpressions)3 Whentheprogramhasbeenstoppedyoucancheckitscurrentstatetoseewhathappened4 Dynamicallychangethecurrentprogramsexecutionenvironment

TodebugyourGoapplicationsusingGDBtheversionofGDByouusemustbegreaterthan71

WhencompilingGoprogramsthefollowingpointsrequireparticularattention

1 Using-ldflags-swillpreventthestandarddebugginginformationfrombeingprinted2 Using-gcflags-N-lwillpreventGofromperformingsomeofitsautomatedoptimizations-optimizationsof

aggregatevariablesfunctionsetcTheseoptimizationscanmakeitverydifficultforGDBtodoitsjobsoitsbesttodisablethematcompiletimeusingtheseflags

SomeofGDBsmostcommonlyusedcommandsareasfollows

list

AlsousedinitsabbreviatedformllistisusedtodisplaythesourcecodeBydefaultitdisplaystenlinesofcodeandyoucanspecifythelineyouwishtodisplayForexamplethecommandlist15displaystenlinesofcodecenteredaroundline15asshownbelow

10timeSleep(2timeSecond)

11clt-i

12

13close(c)

14

15

16funcmain()

17msg=Startingmain

18fmtPrintln(msg)

19bus=make(chanint)

break

AlsousedinitsabbreviatedformbbreakisusedtosetbreakpointsandtakesasanargumentthatdefineswhichpointtosetthebreakpointatForexampleb10setsabreakpointatthetenthrow

delete

DebuggingbyusingGDB

247

AlsousedinitsabbreviatedformddeleteisusedtodeletebreakpointsThebreakpointissetfollowedbytheserialnumberTheserialnumbercanbeobtainedthroughtheinfobreakpointscommandBreakpointssetwiththeircorrespondingserialnumbersaredisplayedasfollowstosetabreakpointnumber

NumTypeDispEnbAddressWhat

2breakpointkeepy0x0000000000400dc3inmainmainathomexiemengjungdbgo23

breakpointalreadyhit1time

backtrace

Abbreviatedasbtthiscommandisusedtoprinttheexecutionofthecodeforinstance

0mainmain()athomexiemengjungdbgo23

10x000000000040d61einruntimemain()athomexiemengjungosrcpkgruntimeprocc244

20x000000000040d6c1inschedunlock()athomexiemengjungosrcpkgruntimeprocc267

30x0000000000000000in()

info

TheinfocommandcanbeusedinconjunctionwithseveralparameterstodisplayinformationThefollowingparametersarecommonlyused

infolocals

Displaysthecurrentlyexecutingprogramsvariablevalues

infobreakpoints

Displaysalistofcurrentlysetbreakpoints

infogoroutines

Displaysthecurrentlistofrunninggoroutinesasshowninthefollowingcodewiththeindicatingthecurrentexecution

1runningruntimegosched

2syscallruntimeentersyscall

3waitingruntimegosched

4runnableruntimegosched

print

AbbreviatedaspthiscommandisusedtoprintvariablesorotherinformationIttakesasargumentsthevariablenamestobeprintedandofcoursetherearesomeveryusefulfunctionssuchas$len()and$cap()thatcanbeusedtoreturnthelengthorcapacityofthecurrentstringsslicesormaps

whatis

whatisisusedtodisplaythecurrentvariabletypefollowedbythevariablenameForinstancewhatismsgwilloutputthefollowing

type=structstring

next

Abbreviatedasnnextisusedinsingle-stepdebuggingtoskiptothenextstepWhenthereisabreakpointyoucanenterntojumptothenextsteptocontinue

continue

AbbreviatedasccontinueisusedtojumpoutofthecurrentbreakpointandcanbefollowedbyaparameterNwhichspecifiesthenumberoftimestoskipthebreakpoint

setvariable

DebuggingbyusingGDB

248

ThiscommandisusedtochangethevalueofavariableintheprocessItcanbeusedlikesosetvariableltvargt=ltvaluegt

ThedebuggingprocessNowletstakealookatthefollowingcodetoseehowGDBistypicallyusedtodebugGoprograms

packagemain

import(

fmt

time

)

funccounting(cchanlt-int)

fori=0ilt10i++

timeSleep(2timeSecond)

clt-i

close(c)

funcmain()

msg=Startingmain

fmtPrintln(msg)

bus=make(chanint)

msg=startingagofunc

gocounting(bus)

forcount=rangebus

fmtPrintln(countcount)

Nowwecompilethefilecreatinganexecutablefilecalledgdbfile

gobuild-gcflags-N-lgdbfilego

UsetheGDBcommandtostartdebugging

gdbgdbfile

AfterfirststartingGDByoullhavetoentertheruncommandtoseeyourprogramrunningYouwillthenseetheprogramoutputthefollowingexecutingtheprogramdirectlyfromthecommandlinewilloutputexactlythesamething

(gdb)run

Startingprogramhomexiemengjungdbfile

Startingmain

count0

count1

count2

count3

count4

count5

count6

count7

count8

count9

[LWP2771exited]

[Inferior1(process2771)exitednormally]

Oknowthatweknowhowtogettheprogramupandrunningletstakealookatsettingbreakpoints

DebuggingbyusingGDB

249

(gdb)b23

Breakpoint1at0x400d8dfilehomexiemengjungdbfilegoline23

(gdb)run

Startingprogramhomexiemengjungdbfile

Startingmain

[NewLWP3284]

[SwitchingtoLWP3284]

Breakpoint1mainmain()athomexiemengjungdbfilego23

23fmtPrintln(countcount)

Intheaboveexampleweusetheb23commandtosetabreakpointonline23ofourcodethenenterruntostarttheprogramWhenourprogramstopsatourbreakpointwetypicallyneedtolookatthecorrespondingsourcecodecontextEnteringthelistcommandintoourGDBsessionwecanseethefivelinesofcodeprecedingourbreakpoint

(gdb)list

18fmtPrintln(msg)

19bus=make(chanint)

20msg=startingagofunc

21gocounting(bus)

22forcount=rangebus

23fmtPrintln(countcount)

24

25

NowthatGDBisrunningthecurrentprogramenvironmentwehaveaccesstosomeusefuldebugginginformationthatwecanprintoutToseethecorrespondingvariabletypesandvaluestypeinfolocals

(gdb)infolocals

count=0

bus=0xf840001a50

(gdb)pcount

$1=0

(gdb)pbus

$2=(chanint)0xf840001a50

(gdb)whatisbus

type=chanint

Tolettheprogramcontinueitsexecutionuntilthenextbreakpointentertheccommand

(gdb)c

Continuing

count0

[NewLWP3303]

[SwitchingtoLWP3303]

Breakpoint1mainmain()athomexiemengjungdbfilego23

23fmtPrintln(countcount)

(gdb)c

Continuing

count1

[SwitchingtoLWP3302]

Breakpoint1mainmain()athomexiemengjungdbfilego23

23fmtPrintln(countcount)

AftereachcthecodewillexecuteoncethenjumptothenextiterationoftheforloopItwillofcoursecontinuetoprintouttheappropriateinformation

LetssaythatyouneedtochangethecontextvariablesinthecurrentexecutionenvironmentskiptheprocessthencontinuetothenextstepYoucandosobyfirstusinginfolocalstogetthevariablestatesthenthesetvariablecommandtomodifythem

DebuggingbyusingGDB

250

(gdb)infolocals

count=2

bus=0xf840001a50

(gdb)setvariablecount=9

(gdb)infolocals

count=9

bus=0xf840001a50

(gdb)c

Continuing

count9

[SwitchingtoLWP3302]

Breakpoint1mainmain()athomexiemengjungdbfilego23

23fmtPrintln(countcount)

FinallywhilerunningtheprogramcreatesanumberofgoroutinesWecanseewhateachgoroutineisdoingusinginfogoroutines

(gdb)infogoroutines

1runningruntimegosched

2syscallruntimeentersyscall

3waitingruntimegosched

4runnableruntimegosched

(gdb)goroutine1bt

00x000000000040e33binruntimegosched()athomexiemengjungosrcpkgruntimeprocc927

10x0000000000403091inruntimechanrecv(c=voidep=voidselected=voidreceived=void)

athomexiemengjungosrcpkgruntimechanc327

20x000000000040316finruntimechanrecv2(t=voidc=void)

athomexiemengjungosrcpkgruntimechanc420

30x0000000000400d6finmainmain()athomexiemengjungdbfilego22

40x000000000040d0c7inruntimemain()athomexiemengjungosrcpkgruntimeprocc244

50x000000000040d16ainschedunlock()athomexiemengjungosrcpkgruntimeprocc267

60x0000000000000000in()

FromthegoroutinescommandwecanhaveabetterpictureofwhatGosruntimesystemisdoinginternallythecallingsequenceforeachfunctionisplainlydisplayed

SummaryInthissectionweintroducedsomebasiccommandsfromtheGDBdebuggerthatyoucanusetodebugyourGoapplicationsTheseincludedtherunprintinfosetvariablecontinuelistandbreakcommandsamongothersFromthebriefexamplesaboveIhopethatyouwillhaveabetterunderstandingofhowthedebuggingprocessworksinGousingtheGDBdebuggerIfyouwanttogetmoredebuggingtipspleaserefertotheGDBmanualonitsofficialwebsite

LinksDirectoryPrevioussectionErrorhandlingNextsectionWritetestcases

DebuggingbyusingGDB

251

113WritingtestcasesInthecourseofdevelopmentaveryimportantstepistotestourcodetoensureitsqualityandintegrityWeneedtomakesurethateveryfunctionreturnstheexpectedresultandthatourcodeperformsoptimallyWealreadyknowthatthefocusofunittestsistofindlogicalerrorsinthedesignorimplementationofprogramsTheyareusedtodetectandexposeproblemsincodeearlyonsothatwecanmoreeasilyfixthembeforetheygetoutofhandWealsoknowthatperformancetestsareconductedforthepurposeofoptimizingourcodesothatitisstableunderloadandcanmaintainahighlevelofconcurrencyInthissectionwelltakealookatsomecommonlyaskedquestionsabouthowunitandperformancetestsareimplementedinGo

TheGolanguagecomeswithalightweighttestingframeworkcalledtestingandwecanusethegotestcommandtoexecuteunitandperformancetestsGostestingframeworkworkssimilarlytotestingframeworksinotherlanguagesYoucandevelopallsortsoftestsuiteswiththemwhichmayincludetestsforunittestesbenchmarkingstresstestsetcLetslearnabouttestinginGostepbystep

HowtowritetestcasesSincethegotestcommandcanonlybeexecutedinadirectorycontainingallcorrespondingfileswearegoingtocreateanewprojectdirectorygotestsothatallofourcodeandtestcodeareinthesamedirectory

Letsgoaheadandcreatetwofilesinthedirectorycalledgotestgoandgotest_testgo

1 GotestgoThisfiledeclaresourpackagenameandhasafunctionthatperformsadivisionoperation

packagegotest

import(

errors

)

funcDivision(abfloat64)(float64error)

ifb==0

return0errorsNew(Divisorcannotbe0)

returnabnil

2 Gotest_testgoThisisourunittestfileKeepinmindthefollowingprinciplesfortestfiles

3 Filenamesmustendin_testgosothatgotestcanfindandexecutetheappropriatecode

4 Youhavetoimportthetestingpackage5 AlltestcasefunctionsbeginwithTest6 Testcasesfollowthesourcecodeorder7 TestfunctionsoftheformTestXxx()takeatestingTargumentwecanusethistypetorecorderrorsortogetthe

testingstatus8 InfunctionsoftheformfuncTestXxx(ttestingT)theXxxsectioncanbeanyalphanumericcombinationbutthe

firstlettercannotbealowercaseletter[az]ForexampleTestintdivwouldbeaninvalidfunctionname9 BycallingoneoftheErrorErrorfFailNowFatalorFatalIfmethodsoftestingTonourtestingfunctions

wecanfailthetestInadditionwecancalltheLogmethodoftestingTtorecordtheinformationintheerrorlog

Hereisourtestcode

Writetestcases

252

packagegotest

import(

testing

)

funcTest_Division_1(ttestingT)

tryaunittestonfunction

ifie=Division(62)i=3||e=nil

Ifitisnotasexpectedthenthetesthasfailed

tError(divisionfunctiontestsdonotpass)

else

recordtheexpectedinformation

tLog(firsttestpassed)

funcTest_Division_2(ttestingT)

tError(justdoesnotpass)

Whenexecutinggotestintheprojectdirectoryitwilldisplaythefollowinginformation

---FAILTest_Division_2(000seconds)

gotest_testgo16isnotpassed

FAIL

exitstatus1

FAILgotest0013s

Wecanseefromthisresultthatthesecondtestfunctiondoesnotpasssincewewroteinadead-endusingtErrorButwhatabouttheperformanceofourfirsttestfunctionBydefaultexecutinggotestdoesnotdisplaytestresultsWeneedtosupplytheverboseargument-vlikegotest-vtodisplaythefollowingoutput

===RUNTest_Division_1

---PASSTest_Division_1(000seconds)

gotest_testgo11firsttestpassed

===RUNTest_Division_2

---FAILTest_Division_2(000seconds)

gotest_testgo16isnotpassed

FAIL

exitstatus1

FAILgotest0012s

TheaboveoutputshowsindetailtheresultsofourtestWeseethatthetestfunction1Test_Division_1passesandthetestfunction2Test_Division_2failsfinallyconcludingthatourtestsuitedoesnotpassNextwemodifythetestfunction2withthefollowingcode

funcTest_Division_2(ttestingT)

tryaunittestonfunction

if_e=Division(60)e==nil

Ifitisnotasexpectedthentheerror

tError(Divisiondidnotworkasexpected)

else

recordsomeoftheinformationyouexpecttorecord

tLog(onetestpassede)

Weexecutegotest-vonceagainThefollowinginformationshouldnowbedisplayed-thetestsuitehaspassed~

Writetestcases

253

===RUNTest_Division_1

---PASSTest_Division_1(000seconds)

gotest_testgo11firsttestpassed

===RUNTest_Division_2

---PASSTest_Division_2(000seconds)

gotest_testgo20onetestpasseddivisorcannotbe0

PASS

okgotest0013s

HowtowritestresstestsStresstestingisusedtodetectfunctionperformanceandbearssomeresemblancetounittesting(whichwewillnotgetintohere)howeverweneedtopayattentiontothefollowingpoints

StresstestsmustfollowthefollowingformatwhereXXXcanbeanyalphanumericcombinationanditsfirstlettercannotbealowercaseletter

funcBenchmarkXXX(btestingB)

BydefaultGotestdoesnotperformfunctionstresstestsIfyouwanttoperformstresstestsyouneedtosettheflag-testbenchwiththeformat-testbench=test_name_regexForinstancetorunallstresstestsinyoursuiteyouwouldrungotest-testbench=

InyourstresstestspleaseremembertousetestingBNanyloopbodiessothatthetestscanberunproperlyAsbeforetestfilenamesmustendin_testgo

Herewecreateastresstestfilecalledwebbench_testgo

packagegotest

import(

testing

)

funcBenchmark_Division(btestingB)

fori=0iltbNi++usebNforlooping

Division(45)

funcBenchmark_TimeConsumingFunction(btestingB)

bStopTimer()callthefunctiontostopthestresstesttimecount

Dosomeinitializationworksuchasreadingfiledatadatabaseconnectionsandthelike

Sothatourbenchmarksreflecttheperformanceofthefunctionitself

bStartTimer()re-starttime

fori=0iltbNi++

Division(45)

Wethenexecutethegotest-filewebbench_testgo-testbench=commandwhichoutputsthefollowingresults

PASS

Benchmark_Division500000000776nsop

Benchmark_TimeConsumingFunction500000000780nsop

okgotest9364s

TheaboveresultsshowthatwedidnotperformanyofourTestXXXunittestfunctionsandinsteadonlyperformedourBenchmarkXXXtests(whichisexactlyasexpected)ThefirstBenchmark_DivisiontestshowsthatourDivision()functionexecuted500milliontimeswithanaverageexecutiontimeof776nsThesecondBenchmark_TimeConsumingFunctionshows

Writetestcases

254

thatourTmeConsumingFunctionexecuted500milliontimeswithanaverageexecutiontimeof780nsFinallyitoutputsthetotalexecutiontimeofourtestsuite

SummaryFromourbriefencounterwithunitandstresstestinginGowecanseethatthetestingpackageisverylightweightyetpackedwithusefulutilitiesWesawthatwritingunitandstresstestscanbeverysimpleandrunningthemcanbeeveneasierwithGosbuilt-ingotestcommandEverytimewemodifyourcodewecansimplyrungotesttobeginregressiontesting

LinksDirectoryPrevioussectionDebuggingusingGDBNextsectionSummary

Writetestcases

255

114SummaryOverthecourseofthelastthreesectionsweveintroducedhowtohandleerrorsinGofirstlookingatgooderrorhandlingpracticesanddesignthenlearninghowtousetheGDBdebuggereffectivelyWesawthatwithGDBwecanperformsingle-stepdebuggingviewandmodifyourprogramvariablesduringexecutionandprintouttherelevantprocessinformationFinallywedescribedhowtouseGosbuilt-intestingframeworktowriteunitandstresstestsProperlyusingthisframeworkallowsustoeasilymakeanyfuturechangestoourcodeandperformthenecessaryregressiontestingGoodwebapplicationsmusthavegooderrorhandlingandpartofthatishavingreadableerrorsanderrorhandlingmechanismswhichcanscaleinapredictablemannerUsingthetoolsmentionedaboveaswellaswritinghighqualityandthoroughunitandstresstestswecanhavepeaceofmindknowingthatonceourapplicationsarelivetheycanmaintainoptimalperformanceandrunasexpected

LinksDirectoryPrevioussectionWritetestcasesNextchapterDeploymentandmaintenance

Summary

256

12DeploymentandmaintenanceSofarwevecoveredthebasicsofdevelopingdebuggingandtestingwebapplicationsinGoAsisoftensaidhoweverthelast10ofdevelopmenttakes90ofthetimeInthischapterwewillbeemphasizingthislast10ofapplicationdevelopmentinordertotrulycraftreliableandhighqualitywebapplicationsInthefirstsectionwewillexaminehowproductionservicesgeneratelogsandtheprocessofloggingitselfThesecondsectionwilldescribedealingwithruntimeerrorsandhowtomanagethemwhentheyoccursothattheimpactonendusersisminimizedInthethirdsectionwetacklethesubjectofdeployingstandaloneGoprogramswhichcanbetrickyatfirstAsyoumightknowGoprogramscannotbewrittenwithdaemonslikeyouwouldwithalanguagesuchasCWelldiscusshowbackgroundprocessesaretypicallymanagedinGoFinallyourfourthandlastsectionwilladdresstheprocessofbackingupandrecoveringapplicationdatainGoWelltakealookatsometechniquesforensuringthatintheeventofacrashwewillbeabletomaintaintheintegrityofourdata

LinksDirectoryPreviouschapterChapter11summaryNextsectionLogs

Deploymentandmaintenance

257

121LogsWewanttobuildwebapplicationsthatcankeeptrackofeventswhichhaveoccurredthroughoutexecutioncombiningthemallintooneplaceforeasyaccesslateronwhenweinevitablyneedtoperformdebuggingoroptimizationtasksGoprovidesasimplelogpackagewhichwecanusetohelpusimplementsimpleloggingfunctionalityLogscanbeprintedusingGosfmtpackagecalledinsideerrorhandlingfunctionsforgeneralerrorloggingGosstandardpackageonlycontainsbasicfunctionalityforlogginghoweverTherearemanythirdpartyloggingtoolsthatwecanusetosupplementitifyourneedsaremoresophisticated(toolssimilartolog4jandlog4cppifyouveeverhadtodealwithlogginginJavaorC++)Apopularandfullyfeaturedopen-sourceloggingtoolinGoistheseelogloggingframeworkLetstakealookathowwecanuseseelogtoperformlogginginourGoapplications

IntroductiontoseelogSeelogisaloggingframeworkforGothatprovidessomesimplefunctionalityforimplementingloggingtaskssuchasfilteringandformattingItsmainfeaturesareasfollows

DynamicconfigurationviaXMLyoucanloadconfigurationparametersdynamicallywithoutrecompilingyourprogramSupportshotupdatestheabilitytodynamicallychangetheconfigurationwithouttheneedtorestarttheapplicationSupportsmulti-outputstreamsthatcansimultaneouslypipelogoutputtomultiplestreamssuchasafilestreamnetworkflowetcSupportfordifferentlogoutputs

CommandlineoutputFileOutputCachedoutputSupportlogrotateSMTPMail

TheaboveisonlyapartiallistofseelogsfeaturesTofullytakeadvantageofallofseelogsfunctionalityhavealookatitsofficialwikiwhichthoroughlydocumentswhatyoucandowithitLetsseehowweduseseeloginourprojects

Firstinstallseelog

goget-ugithubcomcihubseelog

Thenletswriteasimpleexample

packagemain

importloggithubcomcihubseelog

funcmain()

deferlogFlush()

logInfo(HellofromSeelog)

CompileandruntheprogramIfyouseeaHellofromseeloginyourapplicationlogseeloghasbeensuccessfullyinstalledandisrunningoperatingnormally

CustomlogprocessingwithseelogSeelogsupportscustomlogprocessingThefollowingcodesnippetisbasedontheitscustomlogprocessingpartofitspackage

Logs

258

packagelogs

import(

errors

fmt

seeloggithubcomcihubseelog

io

)

varLoggerseelogLoggerInterface

funcloadAppConfig()

appConfig=`

ltseelogminlevel=warngt

ltoutputsformatid=commongt

ltrollingfiletype=sizefilename=datalogsrolllogmaxsize=100000maxrolls=5gt

ltfilterlevels=criticalgt

ltfilepath=datalogscriticallogformatid=criticalgt

ltsmtpformatid=criticalemailsenderaddress=astaxiegmailcomsendername=ShortUrlAPIhostname=smtp

gmailcomhostport=587username=mailusernamepassword=mailpasswordgt

ltrecipientaddress=xiemengjungmailcomgt

ltsmtpgt

ltfiltergt

ltoutputsgt

ltformatsgt

ltformatid=commonformat=DateTime[LEV]Msgngt

ltformatid=criticalformat=FileFullPathFuncMsgngt

ltformatid=criticalemailformat=CriticalerroronourservernTimeDateRelFileFuncMsgnSent

bySeeloggt

ltformatsgt

ltseeloggt

`

loggererr=seelogLoggerFromConfigAsBytes([]byte(appConfig))

iferr=nil

fmtPrintln(err)

return

UseLogger(logger)

funcinit()

DisableLog()

loadAppConfig()

DisableLogdisablesalllibrarylogoutput

funcDisableLog()

Logger=seelogDisabled

UseLoggerusesaspecifiedseelogLoggerInterfacetooutputlibrarylog

UsethisfuncifyouareusingSeelogloggingsysteminyourapp

funcUseLogger(newLoggerseelogLoggerInterface)

Logger=newLogger

Theaboveimplementsthethreemainfunctions

DisableLog

InitializesaglobalvariableLoggerwithseelogdisabledmainlyinordertopreventtheloggerfrombeingrepeatedlyinitialized

LoadAppConfig

InitializestheconfigurationsettingsofseelogaccordingtoaconfigurationfileInourexamplewearereadingtheconfigurationfromanin-memorystringbutofcourseyoucanreaditfromanXMLfilealsoInsidetheconfigurationwesetupthefollowingparameters

Logs

259

Seelog

TheminlevelparameterisoptionalIfconfiguredlogginglevelswhicharegreaterthanorequaltothespecifiedlevelwillberecordedTheoptionalmaxlevelparameterissimilarlyusedtoconfigurethemaximumloggingleveldesired

Outputs

ConfigurestheoutputdestinationInourparticularcasewechannelourloggingdataintotwooutputdestinationsThefirstisarollinglogfilewherewecontinuouslysavethemostrecentwindowofloggingdataTheseconddestinationisafilteredlogwhichrecordsonlycriticallevelerrorsWeadditionallyconfigureittoalertusviaemailwhenthesetypesoferrorsoccur

Formats

DefinesthevariousloggingformatsYoucanusecustomformattingorpredefinedformatting-afulllistofpredefinedformatscanbefoundonseelogswiki

UseLogger

Setthecurrentloggerasourlogprocessor

AbovewevedefinedandconfiguredacustomlogprocessingpackageThefollowingcodedemonstrateshowweduseit

packagemain

import(

nethttp

projectlogs

projectconfigs

projectroutes

)

funcmain()

addr_=configsMainConfigString(serveraddr)

logsLoggerInfo(Startserveratvaddr)

err=httpListenAndServe(addrroutesNewMux())

logsLoggerCritical(Servererrverr)

EmailnotificationsTheaboveexampleexplainshowtosetupemailnotificationswithseelogAsyoucanseeweusedthefollowingsmtpconfiguration

ltsmtpformatid=criticalemailsenderaddress=astaxiegmailcomsendername=ShortUrlAPIhostname=smtpgmailcom

hostport=587username=mailusernamepassword=mailpasswordgt

ltrecipientaddress=xiemengjungmailcomgt

ltsmtpgt

WesettheformatofouralertmessagesthroughthecriticalemailconfigurationprovidingourmailserverparameterstobeabletoreceivethemWecanalsoconfigureournotifiertosendoutalertstoadditionalusersusingtherecipientconfigurationItsasimplematterofaddingonelineforeachadditionalrecipient

Totestwhetherornotthiscodeisworkingproperlyyoucanaddafakecriticalmessagetoyourapplicationlikeso

logsLoggerCritical(testCriticalmessage)

Dontforgettodeleteitonceyouredonetestingorwhenyourapplicationgoesliveyourinboxmaybefloodedwithemailnotifications

NowwheneverourapplicationlogsacriticalmessagewhileonlineyouandyourspecifiedrecipientswillreceiveanotificationemailYouandyourteamcanthenprocessandremedythesituationinatimelymanner

Logs

260

UsingapplicationlogsWhenitcomestologseachapplicationsuse-casemayvaryForexamplesomepeopleuselogsfordataanalysispurposesothersforperformanceoptimizationSomelogsareusedtoanalyzeuserbehaviorandhowpeopleinteractwithyourwebsiteOfcoursetherearelogswhicharesimplyusedtorecordapplicationeventsasauxiliarydataforfindingproblems

AsanexampleletssayweneedtotrackuserattemptsatloggingintooursystemThisinvolvesrecordingbothsuccessfulandunsuccessfulloginattemptsintoourlogWedtypicallyusetheInfologleveltorecordthesetypesofeventsratherthansomethingmoreseriouslikewarnIfyoureusingalinux-typesystemyoucanconvenientlyviewallunsuccessfulloginattemptsfromthelogusingthegrepcommandlikeso

catdatalogsrolllog|grepfailedlogin

2012-12-11111200WARNfailedloginattemptfrom11223344usernamepassword

ThiswaywecaneasilyfindtheappropriateinformationinourapplicationlogwhichcanhelpustoperformstatisticalanalysisifneededInadditionwealsoneedtoconsiderthesizeoflogsgeneratedbyhigh-trafficwebapplicationsTheselogscansometimesgrowunpredictablyToresolvethisissuewecansetseelogupwiththelogrotateconfigurationtoensurethatsinglelogfilesdonotconsumeexcessivediskspace

SummaryInthissectionwevelearnedthebasicsofseelogandhowtobuildacustomloggingsystemwithitWesawthatwecaneasilyconfigureseelogintoaspowerfulalogprocessingsystemasweneedusingittosupplyuswithreliablesourcesofdataforanalysisThroughloganalysiswecanoptimizeoursystemandeasilylocatethesourcesofproblemswhentheyariseInadditionseelogshipswithvariousdefaultloglevelsWecanusetheminlevelconfigurationinconjunctionwithalogleveltoeasilysetuptestsorsendautomatednotificationmessages

LinksDirectoryPrevioussectionDeploymentandmaintenanceNextsectionErrorsandcrashes

Logs

261

122ErrorsandcrashesOnceourwebapplicationsgoliveitslikelythattherewillbesomeunforeseenerrorsAfewexampleofcommonerrorsthatmayoccurinthecourseofyourapplicationsdailyoperationsarelistedbelow

DatabaseErrorserrorsrelatedtoaccessingthedatabaseserverorstoreddataThefollowingaresomedatabaseerrorswhichyoumayencounter

ConnectionErrorsindicatesthataconnectiontothenetworkdatabaseservercouldnotbeestablishedasuppliedusernameorpasswordisincorrectorthatthedatabasedoesnotexist

QueryErrorstheillegalorincorrectuseofanSQLquerycanraiseanerrorsuchasthisThesetypesoferrorscanbeavoidedthroughrigoroustestingDataErrorsdatabaseconstraintviolationsuchasattemptingtoinsertafieldwithaduplicateprimarykeyThesetypesoferrorscanalsobeavoidedthroughrigoroustestingbeforedeployingyourapplicationintoaproductionenvironmentApplicationRuntimeErrorsThesetypesoferrorsvarygreatlycoveringalmostallerrorcodeswhichmayappearduringruntimePossibleapplicationerrorsareasfollows

FilesystemandpermissionerrorswhentheapplicationattemptstoreadafilewhichdoesnotexistordoesnothavepermissiontoreadorwhenitattemptstowritetoafilewhichitisnotallowedtowritetoerrorsofthiscategorywilloccurAfilesystemerrorwillalsooccurifanapplicationreadsafilewithanunexpectedformatforinstanceaconfigurationfilethatshouldbeintheINIformatbutisinsteadstructuredasJSON

Third-partyapplicationerrorsTheseerrorsoccurinapplicationswhichinterfacewithotherthird-partyapplicationsorservicesForinstanceifanapplicationpublishestweetsaftermakingcallstoTwittersAPIitsobviousthatTwittersservicesmustbeupandrunninginorderforourapplicationtocompleteitstaskWemustalsoensurethatwesupplythesethird-partyinterfaceswiththeappropriateparametersinourcallsorelsetheywillalsoreturnerrors

HTTPerrorsTheseerrorsvarygreatlyandarebasedonuserrequestsThemostcommonisthe404NotFounderrorwhichariseswhenusersattempttoaccessnon-existentresourcesinyourapplicationAnothercommonHTTPerroristhe401Unauthorizederror(authenticationisrequiredtoaccesstherequestedresource)403Forbiddenerror(usersarealtogetherrefusedaccesstothisresource)and503ServiceUnavailableerrors(indicativeofaninternalprogramerror)

OperatingsystemerrorsThesesortsoferrorsoccurattheoperatingsystemlayerandcanhappenwhenoperatingsystemresourcesareover-allocatedleadingtocrashesandsysteminstabilityAnothercommonoccurrenceatthisleveliswhentheoperatingsystemdiskgetsfilledtocapacitymakingitimpossibletowritetoThisnaturallyproducesinmanyerrorsNetworkerrorsnetworkerrorstypicallycomeintwoflavorsoneiswhenusersissuerequeststotheapplicationandthenetworkdisconnectsthusdisruptingitsprocessingandresponsephaseTheseerrorsdonotcausetheapplicationtocrashbutcanaffectuseraccesstothewebsitetheotheriswhenapplicationsattemptstoreaddatafromdisconnectednetworkscausingreadfailuresJudicioustestingisparticularlyimportantwhenmakingnetworkcallstoavoidsuchproblemswhichcancauseyourapplicationtocrash

ErrorhandlinggoalsBeforeimplementingerrorhandlingwemustbeclearaboutwhatgoalswearetryingtoachieveIngeneralerrorhandlingsystemsshouldaccomplishthefollowing

UsererrornotificationswhensystemorusererrorsoccurcausingcurrentuserrequeststofailtocompleteaffectedusersshouldbenotifiedoftheproblemForexampleforerrorscausebyuserrequestsweshowaunifiederrorpage(404html)Whenasystemerroroccursweuseacustomerrorpagetoprovidefeedbackforusersastowhathappened-forinstancethatthesystemistemporarilyunavailable(errorhtml)Logerrorswhensystemerrorsoccur(ingeneralwhenfunctionsreturnnon-nilerrorvariables)aloggingsystemsuch

Errorsandcrashes

262

astheonedescribedearliershouldbeusedtorecordtheeventintoalogfilefileIfitisafatalerrorthesystemadministratorshouldalsobenotifiedviae-mailIngeneralhowevermost404errorsdonotwarrantthesendingofemailnotificationsrecordingtheeventintoalogforlaterscrutinyisoftenadequateRollbackthecurrentrequestoperationIfauserrequestcausesaservererrorthenweneedtobeabletorollbackthecurrentoperationLetslookatanexampleasystemsavesauser-submittedformtoitsdatabasethensubmitsthisdatatoathird-partyserverHoweverthethird-partyserverdisconnectsandweareunabletoestablishaconnectionwithitwhichresultsinanerrorInthiscasethepreviouslystoredformdatashouldbedeletedfromthedatabase(voidshouldbeinformed)andtheapplicationshouldinformtheuserofthesystemerrorEnsurethattheapplicationcanrecoverfromerrorsweknowthatitsdifficultforanyprogramtoguarantee100uptimesoweneedtomakeprovisionforscenarioswhereourprogramsfailForinstanceifourprogramcrasheswefirstneedtologtheerrornotifytherelevantpartiesinvolvedthenimmediatelygettheprogramupandrunningagainThiswayourapplicationcancontinuetoprovideserviceswhileasystemadministratorinvestigatesandfixesthecauseoftheproblem

HowtohandleerrorsInchapter11weaddressedtheprocessoferrorhandlinganddesignusingsomeexamplesLetsgointotheseexamplesinabitmoredetailandseesomeothererrorhandlingscenarios

Notifytheuseroferrors

Whenanerroroccurswecanpresenttheuseraccessingthepagewithtwokindsoferrorspages404htmlanderrorhtmlHereisanexampleofwhatthesourcecodeofanerrorpagemightlooklike

lthtmllang=engt

ltheadgt

ltmetahttp-equiv=Content-Typecontent=texthtmlcharset=utf-8gt

lttitlegtPageNotFound

lttitlegt

ltmetaname=viewportcontent=width=device-widthinitial-scale=10gt

ltheadgt

ltbodygt

ltdivclass=containergt

ltdivclass=rowgt

ltdivclass=span10gt

ltdivclass=hero-unitgt

lth1gt404lth1gt

ltpgtErrorInfoltpgt

ltdivgt

ltdivgt

lt--span--gt

ltdivgt

ltdivgt

ltbodygt

lthtmlgt

Anotherexample

Errorsandcrashes

263

lthtmllang=engt

ltheadgt

ltmetahttp-equiv=Content-Typecontent=texthtmlcharset=utf-8gt

lttitlegtsystemerrorpage

lttitlegt

ltmetaname=viewportcontent=width=device-widthinitial-scale=10gt

ltheadgt

ltbodygt

ltdivclass=containergt

ltdivclass=rowgt

ltdivclass=span10gt

ltdivclass=hero-unitgt

lth1gtsystemistemporarilyunavailablelth1gt

ltpgtErrorInfoltpgt

ltdivgt

ltdivgt

lt--span--gt

ltdivgt

ltdivgt

ltbodygt

lthtmlgt

404error-handlinglogicintheoccurrenceofasystemerror

func(pMyMux)ServeHTTP(whttpResponseWriterrhttpRequest)

ifrURLPath==

sayhelloName(wr)

return

NotFound404(wr)

return

funcNotFound404(whttpResponseWriterrhttpRequest)

logError(pagenotfound)errorlogging

t_=tParseFiles(tmpl404htmlnil)parsethetemplatefile

ErrorInfo=FilenotfoundGetthecurrentuserinformation

tExecute(wErrorInfo)executethetemplatemergeroperation

funcSystemError(whttpResponseWriterrhttpRequest)

logCritical(SystemError)systemerrortriggeredCriticalthenloggingwillnotonly

sendamessage

t_=tParseFiles(tmplerrorhtmlnil)parsethetemplatefile

ErrorInfo=systemistemporarilyunavailableGetthecurrentuserinformation

tExecute(wErrorInfo)executethetemplatemergeroperation

HowtohandleexceptionsWeknowthatmanyotherlanguageshavetrycatchkeywordsusedtocapturetheunusualcircumstancesbutinfactmanyerrorscanbeexpectedtooccurwithouttheneedforexceptionhandlingandcanbeinsteadtreatedasanerrorsItsforthisreasonthatGofunctionsreturnerrorsbydesignForexampleifafileisnotfoundorifosOpenreturnsanerrorthesefunctionswillnotpanicasanotherexampleifanetworkconnectiongetsdisconnectedduringadatawriteoperationthenetConnfamilyofWritefunctionswillreturnerrorsinsteadofpanickingTheseerrorstatesaretobeexpectedinmostapplicationsandGoparticularlymakesitexplicitwhenoperationsmightfailbyreturningerrorvariablesLookingattheexampleabovewecanclearlyseetheerrorsthatcanbeexpectedtooccur

Errorsandcrashes

264

TherearehowevercaseswherepanicshouldbeusedForinstanceinoperationswherefailureisalmostimpossibleorincertainsituationswherethereisnowaytoreturnanerrorandtheoperationcannotcontinuepanicshouldbeusedTakeforexampleaprogramthattriestoobtainthevalueofanarrayatx[j]buttheindexjisoutofboundsThispartofthecodewillcausetheprogramtopanicaswillothercriticalunexpectederrorsofthisnatureBydefaultpanickingwillkillofftheoffendingprocess(goroutine)allowingthecodewhichdispatchedthegoroutineanopportunitytorecoverfromtheerrorThiswaythefunctioninwhichtheerroroccurredaswellasallsubsequentcodeafteritwillnotcontinuetoexecuteGospanicwasdeliberatelydesignedwiththisbehaviorinmindwhichisdifferentthantypicalerrorhandlingpanicisreallyjustexceptionhandlingIntheexamplebelowweexpectthatUser[UID]willreturnausernamefromtheUserarraybuttheUIDthatweuseisoutofboundsandthrowsanexceptionIfwedonothavearecoverymechanismtodealwiththisimmediatelytheprocesswillbekilledandthepanicwillpropagateupthestackuntilourprogramfinallycrashesInorderforourapplicationtoberobustandresilienttothesekindsofruntimeerrorsweneedtoimplementrecoverymechanismsincertainplaces

funcGetUser(uidint)(usernamestring)

deferfunc()

ifx=recover()x=nil

username=

()

username=User[uid]

return

TheabovedescribesthedifferencesbetweenerrorsandexceptionsSowhenitcomesdowntodevelopingourGoapplicationswhendoweuseoneortheotherTherulesaresimpleifyoudefineafunctionthatyouanticipatemightfailthenreturnanerrorvariableWhencallinganotherpackagesfunctionifitisimplementedwellthereshouldbenoneedtoworrythatitwillpanicunlessatrueexceptionhasoccurred(whetherrecoverylogichasbeenimplementedornot)PanicandrecovershouldonlybeusedinternallyinsidepackagestodealwithspecialcaseswherethestateoftheprogramcannotbeguaranteedorwhenaprogrammerserrorhasoccurredExternallyfacingAPIsshouldexplicitlyreturnerrorvalues

SummaryThisissectionsummarizeshowwebapplicationsshouldhandlevariouserrorssuchasnetworkdatabaseandoperatingsystemerrorsamongothersWeveoutlineseveraltechniquestoeffectivelydealwithruntimeerrorssuchasdisplayinguser-friendlyerrornotificationsrollingbackactionsloggingandalertingsystemadministratorsFinallyweexplainedhowtocorrectlyhandleerrorsandexceptionsTheconceptofanerrorisoftenconfusedwiththatofanexceptionhoweverinGothereisacleardistinctionbetweenthetwoForthisreasonwevediscussedtheprinciplesofprocessingbotherrorsandexceptionsinwebapplications

LinksDirectoryPrevioussectionLogsNextsectionDeployment

Errorsandcrashes

265

123DeploymentWhenourwebapplicationisfinallyproductionreadywhatarethestepsnecessarytogetitdeployedInGoanexecutablefileencapsulatingourapplicationiscreatedafterwecompileourprogramsProgramswritteninCcanrunperfectlyasbackgrounddaemonprocesseshoweverGodoesnotyethavenativesupportfordaemonsThegoodnewsisthatwecanusethirdpartytoolstohelpusmanagethedeploymentofourGoapplicationsexamplesofwhichareSupervisordupstartanddaemontoolsamongothersThissectionwillintroduceyoutosomebasicsoftheSupervisordprocesscontrolsystem

DaemonsCurrentlyGoprogramscannotberunasdaemonprocesses(foradditionalinformationseetheopenissueongithubhere)ItsdifficulttoforkexistingthreadsinGobecausethereisnowayofensuringaconsistentstateinallthreadsthathavebeenused

Wecanhoweverseemanyattemptsatimplementingdaemonsonlinesuchasinthetwofollowingways

MarGooneimplementationoftheconceptofusingCommandtodeployapplicationsIfyoureallywanttodaemonizeyourapplicationsitisrecommendedtousecodesimilartothefollowing

d=flagBool(dfalseWhetherornottolaunchinthebackground(likea

daemon))

ifd

cmd=execCommand(osArgs[0]

-close-fds

-addraddr

-callcall

)

serrerr=cmdStderrPipe()

iferr=nil

logFatalln(err)

err=cmdStart()

iferr=nil

logFatalln(err)

serr=ioutilReadAll(serr)

s=bytesTrimSpace(s)

ifbytesHasPrefix(s[]byte(addr))

fmtPrintln(string(s))

cmdProcessRelease()

else

logPrintf(unexpectedresponsefromMarGo`s`error`v`nserr)

cmdProcessKill()

Anothersolutionistousesyscallbutthissolutionisnotperfect

Deployment

266

packagemain

import(

log

os

syscall

)

funcdaemon(nochdirnocloseint)int

varretret2uintptr

varerruintptr

darwin=syscallOS==darwin

alreadyadaemon

ifsyscallGetppid()==1

return0

forkofftheparentprocess

retret2err=syscallRawSyscall(syscallSYS_FORK000)

iferr=0

return-1

failure

ifret2lt0

osExit(-1)

handleexceptionfordarwin

ifdarwinampampret2==1

ret=0

ifwegotagoodPIDthenwecallexittheparentprocess

ifretgt0

osExit(0)

Changethefilemodemask

_=syscallUmask(0)

createanewSIDforthechildprocess

s_rets_errno=syscallSetsid()

ifs_errno=0

logPrintf(ErrorsyscallSetsiderrnods_errno)

ifs_retlt0

return-1

ifnochdir==0

osChdir()

ifnoclose==0

fe=osOpenFile(devnullosO_RDWR0)

ife==nil

fd=fFd()

syscallDup2(fdosStdinFd())

syscallDup2(fdosStdoutFd())

syscallDup2(fdosStderrFd())

return0

Deployment

267

WhilethetwosolutionsaboveimplementdaemonizationinGoIstillcannotrecommendthatyouuseeithermethodssincethereisnoofficialsupportfordaemonsinGoNotwithstandingthisfactthefirstoptionisthemorefeasibleoneandiscurrentlybeingusedbysomewell-knownopensourceprojectslikeskynetforimplementingdaemons

SupervisordAbovewevelookedattwoschemesthatarecommonlyusedtoimplementdaemonsinGohoweverbothmethodslackofficialsupportSoitsrecommendedthatyouuseathird-partytooltomanageapplicationdeploymentHerewetakealookattheSupervisordprojectimplementedinPythonwhichprovidesextensivetoolsforprocessmanagementSupervisordwillhelpyoutodaemonizeyourGoapplicationsalsoallowingyoutodothingslikestartshutdownandrestartyourapplicationswithsomesimplecommandsamongmanyotheractionsInadditionSupervisordmanagedprocessescanautomaticallyrestartprocesseswhichhavecrashedensuringthatprogramscanrecoverfromanyinterruptions

AsanasideIrecentlyfellintoacommonpitfallwhiletryingtodeployanapplicationusingSupervisordAllapplicationsdeployedusingSupervisordarebornoutoftheSupervisordparentprocessWhenyouchangeanoperatingsystemfiledescriptordontforgettocompletelyrestartSupervisord-simplyrestartingtheapplicationitismanagingwillnotsufficeWhenIfirstdeployedanapplicationwithSupervisordImodifiedthedefaultfiledescriptorfieldchangingthedefaultnumberfrom1024to100000andthenrestartingmyapplicationInrealitySupervisordcontinuedusingonly1024filedescriptorstomanageallofmyapplicationsprocessesUpondeployingmyapplicationtheloggerbeganreportingalackoffiledescriptorsItwasalongprocessfindingandfixingthismistakesobeware

InstallingSupervisord

Supervisordcaneasilybeinstalledusingsudoeasy_installsupervisorOfcoursethereisalsotheoptionofdirectlydownloadingitfromitsofficialwebsiteuncompressingitgoingintothefolderthenrunningsetuppyinstalltoinstallitmanually

Ifyouregoingtheeasy_installroutethenyouneedtofirstinstallsetuptools

GotohttppypipythonorgpypisetuptoolsfilesanddownloadtheappropriatefiledependingonyoursystemspythonversionEnterthedirectoryandexecuteshsetuptoolsxxxxeggWhenthenscriptisdoneyoullbeabletousetheeasy_installcommandtoinstallSupervisord

ConfiguringSupervisord

SupervisordsdefaultconfigurationfilepathisetcsupervisordconfandcanbemodifiedusingatexteditorThefollowingiswhatatypicalconfigurationfilemaylooklike

Deployment

268

etcsupervisordconf

[unix_http_server]

file=varrunsupervisordsock

chmod=0777

chown=rootroot

[inet_http_server]

Webmanagementinterfacesettings

port=9001

username=admin

password=yourpassword

[supervisorctl]

Mustunix_http_servermatchthesettingsinside

serverurl=unixvarrunsupervisordsock

[supervisord]

logfile=varlogsupervisordsupervisordlog(mainlogfiledefault$CWDsupervisordlog)

logfile_maxbytes=50MB(maxmainlogfilebytesb4rotationdefault50MB)

logfile_backups=10(numofmainlogfilerotationbackupsdefault10)

loglevel=info(logleveldefaultinfoothersdebugwarntrace)

pidfile=varrunsupervisordpid(supervisordpidfiledefaultsupervisordpid)

nodaemon=true(startinforegroundiftruedefaultfalse)

minfds=1024(minavailstartupfiledescriptorsdefault1024)

minprocs=200(minavailprocessdescriptorsdefault200)

user=root(defaultiscurrentuserrequiredifroot)

childlogdir=varlogsupervisord(AUTOchildlogdirdefault$TEMP)

[rpcinterfacesupervisor]

supervisorrpcinterface_factory=supervisorrpcinterfacemake_main_rpcinterface

Managetheconfigurationofasingleprocessyoucanaddmultipleprogram

[programblogdemon]

command=datablogblogdemon

autostart=true

startsecs=5

user=root

redirect_stderr=true

stdout_logfile=varlogsupervisordblogdemonlog

SupervisordmanagementAfterinstallationiscompletetwoSupervisordcommandsbecomeavailabletoyouonthecommandlinesupervisorandsupervisorctlThecommandsareasfollows

supervisordinitialstartuplaunchandprocessconfigurationmanagementsupervisorctlstopprogramxxxstoptheprogramxxxprocesswhereprogramxxxisavalueconfiguredinyoursupervisordconffileForinstanceifyouhavesomethinglike[programblogdemon]configuredyouwouldusethesupervisorctlstopblogdemoncommandtokilltheprocesssupervisorctlstartprogramxxxstarttheprogramxxxprocesssupervisorctlrestartprogramxxxrestarttheprogramxxxprocesssupervisorctlstopallstopallprocessesnotestartrestartstopwillnotloadthelatestconfigurationfilessupervisorctlreloadloadthelatestconfigurationfilelaunchthemandmanageallprocesseswiththenewconfiguration

SummaryInthissectionwedescribedhowtoimplementdaemonsinGoWelearnedthatGodoesnotnativelysupportdaemonsandthatweneedtousethird-partytoolstohelpusmanagethemOnesuchtoolistheSupervisordprocesscontrolsystemwhichwecanusetoeasilydeployandmanageourGoprograms

Links

Deployment

269

DirectoryPrevioussectionErrorsandcrashesNextsectionBackupandrecovery

Deployment

270

124BackupandrecoveryInthissectionwelldiscussanotheraspectofapplicationmanagementdatabackupandrecoveryonproductionserversWeoftenencountersituationswhereproductionserversdontbehaveasweexpectthemtoServernetworkoutagesharddrivemalfunctionsoperatingsystemcrashesandothersimilareventscancausedatabasestobecomeunavailableTheneedtorecoverfromthesetypesofeventshasledtotheemergenceofmanycoldstandbyhotstandbytoolsthatcanhelptofacilitatedisasterrecoveryremotelyInthissectionwellexplainhowtobackupdeployedapplicationsinadditiontobackingupandrestoringanyMySQLandRedisdatabasesyoumightbeusing

ApplicationBackupInmostclusterenvironmentswebapplicationsdonotneedtobebackedupsincetheyareactuallycopiesofcodefromourlocaldevelopmentenvironmentorfromaversioncontrolsystemInmanycaseshoweverweneedtobackupdatawhichhasbeensuppliedbytheusersofoursiteForinstancewhensitesrequireuserstouploadfilesweneedtobeabletobackupanyfilesthathavebeenuploadedbyuserstoourwebsiteThecurrentapproachforprovidingthiskindofredundancyistoutilizeso-calledcloudstoragewhereuserfilesandotherrelatedresourcesarepersistedintoahighlyavailablenetworkofserversIfoursystemcrashesaslongasuserdatahasbeenpersistedontothecloudwecanatleastbesurethatnodatawillbelost

ButwhataboutthecaseswherewedidnotbackupourdatatoacloudserviceorwherecloudstoragewasnotanoptionHowdowebackupdatafromourwebapplicationsthenHerewedescribeatoolcalledrsyncwhichcanbecommonlyfoundonunix-likesystemsRsyncisatoolwhichcanbeusedtosynchronizefilesresidingondifferentsystemsandaperfectuse-caseforthisfunctionalityistokeepourwebsitebackedup

NoteCwrsyncisanimplementationofrsyncfortheWindowsenvironment

RsyncinstallationYoucanfindthelatestversionofrsyncfromitsofficialwebsiteOfcoursebecausersyncisveryusefulsoftwaremanyLinuxdistributionswillalreadyhaveitinstalledbydefault

PackageInstallation

sudoapt-getinstallrsyncNotedebianubuntuandotheronlineinstallationmethods

yuminstallrsyncNoteFedoraRedhatCentOSandotheronlineinstallationmethods

rpm-ivhrsyncNoteFedoraRedhatCentOSandotherrpmpackageinstallationmethods

FortheotherLinuxdistributionspleaseusetheappropriatepackagemanagementmethodstoinstallitAlternativelyyoucanbuildityourselffromthesource

tarxvfrsync-xxxtargz

cdrsync-xxx

configure-prefix=usrmakemakeinstall

NoteIfwanttocompileandinstallthersyncfromitssourceyouhavetoinstallgcccompilertoolssuchasjob

NoteBeforeusingsourcepackagescompiledandinstalledyouhavetoinstallgcccompilertoolssuchasjob

RsyncConfiguration

Rsynccanbeconfiguredfromthreemainconfigurationfilesrsyncdconfwhichisthemainconfigurationfilersyncdsecretswhichholdspasswordsandrsyncdmotdwhichcontainsserverinformation

Backupandrecovery

271

Youcanrefertotheofficialdocumentationonrsyncswebsiteformoredetailedexplanationsbutherewewillsimplyintroducethebasicsofsettinguprsync

Startinganrsyncdaemonserver-side

usrbinrsync--daemon--config=etcrsyncdconf

the--daemonparameterisforrunningrsyncinservermodeMakethisthedefaultboot-timesettingbyjoiningittotherclocalfile

echorsync--daemongtgtetcrcdrclocal

SetupanrsyncusernameandpasswordmakingsurethatitsownedonlybyrootsothatlocalunauthorizedusersorexploitsdonothaveaccesstoitIfthesepermissionsarenotsetcorrectlyrsyncmaynotboot

echoYourUsernameYourPasswordgtetcrsyncdsecrets

chmod600etcrsyncdsecrets

Clientsynchronization

Clientscansynchronizeserverfileswiththefollowingcommand

rsync-avzP--delete--password-file=rsyncdsecretsusername1921681455wwwvarrsyncbackup

Letsbreakthisdownintoafewkeypoints

1 -avzParesomecommonoptionsUsersync--helptoreviewwhatthesedo2 --deletedeletesextraneousfilesonthereceivingsideForexampleiffilesaredeletedonthesendingsidethenext

timethetwomachinesaresynchronizedthereceivingsideswillautomaticallydeletethecorrespondingfiles3 --password-filespecifiesapasswordfileforaccessinganrsyncdaemonOntheclientsidethisistypicallythe

clientetcrsyncdsecretsfileandontheserversideitsetcrsyncdsecretsWhenusingsomethinglikeCrontoautomatersyncyouwontneedtomanuallyenterapassword

4 usernamespecifiestheusernametobeusedinconjunctionwiththeserver-sideetcrsyncdsecretspassword5 1921681455istheIPaddressoftheserver6 www(notethedoublecolons)specifiescontactinganrsyncdaemondirectlyviaTCPforsynchronizingthewww

moduleaccordingtotheserver-sideconfigurationslocatedinetcrsyncdconfWhenonlyasinglecolonisusedthersyncdaemonisnotcontacteddirectlyinsteadaremote-shellprogramsuchassshisusedasthetransport

InordertoperiodicallysynchronizefilesyoucansetupacrontabfilethatwillrunrsynccommandsasoftenasneededOfcourseuserscanvarythefrequencyofsynchronizationaccordingtohowcriticalitistokeepcertaindirectoriesorfilesuptodate

MySQLbackupMySQLdatabasesarestillthemainstreamgo-tosolutionformostwebapplicationsThetwomostcommonmethodsofbackingupMySQLdatabasesarehotbackupsandcoldbackupsHotbackupsareusuallyusedwithsystemssetupinamasterslaveconfigurationtobackuplivedata(themasterslavesynchronizationmodeistypicallyusedforseparatingdatabasereadwriteoperationsbutcanalsobeusedforbackinguplivedata)ThereisalotofinformationavailableonlinedetailingthevariouswaysonecanimplementthistypeofschemeForcoldbackupsincomingdataisnotbackedupinreal-timeasisthecasewithhotbackupsInsteaddatabackupsareperformedperiodicallyThiswayifthesystemfailstheintegrityofdatabeforeacertainperiodoftimecanstillbeguaranteedForinstanceincaseswhereasystemmalfunctioncausesdatatobelostandthemasterslavemodelisunabletoretrieveitcoldbackupscanbeusedforapartialrestoration

Ashellscriptisgenerallyusedtoimplementregularcoldbackupsofdatabasesexecutingsynchronizationtasksusingrsyncinanon-localmode

Backupandrecovery

272

ThefollowingisanexampleofabackupscriptthatperformsscheduledbackupsforaMySQLdatabaseWeusethemysqldumpprogramwhichallowsustoexportthedatabasetoafile

binbash

Configurationinformationmodifyitasneeded

mysql_user=USERMySQLbackupuser

mysql_password=PASSWORDMySQLbackupuserspassword

mysql_host=localhost

mysql_port=3306

mysql_charset=utf8MySQLencoding

backup_db_arr=(db1db2)Nameofthedatabasetobebackedupseparatingmultipledatabaseswihspaces(DB1

DB2db3)

backup_location=varwwwmysqlBackupdatastoragelocationpleasedonotendwithaandleaveitatitsdefau

ltfortheprogramtoautomaticallycreateafolder

expire_backup_delete=ONWhethertodeleteoutdatedbackupsornot

expire_days=3Settheexpirationtimeofbackupsindays(defaultstothreedays)thisisonlyvalidwhenthe`ex

pire_backup_delete`optionisON

Wedonotneedtomodifythefollowinginitialsettingsbelow

backup_time=`date+YmdHM`Definethebackuptimeformat

backup_Ymd=`date+Y-m-d`Definethebackupdirectorydatetime

backup_3ago=`date-d3daysago+Y-m-d`3daysbeforethedate

backup_dir=$backup_location$backup_YmdFullpathtothebackupfolder

welcome_msg=WelcometouseMySQLbackuptoolsGreeting

DeterminewhethertoMySQLisrunningifnotthenabortthebackup

mysql_ps=`ps-ef|grepmysql|wc-l`

mysql_listen=`netstat-an|grepLISTEN|grep$mysql_port|wc-l`

if[[$mysql_ps==0]-o[$mysql_listen==0]]then

echoERRORMySQLisnotrunningbackupaborted

exit

else

echo$welcome_msg

fi

Connecttothemysqldatabaseifaconnectioncannotbemadeabortthebackup

mysql-h$mysql_host-P$mysql_port-u$mysql_user-p$mysql_passwordltltend

usemysql

selecthostuserfromuserwhereuser=rootandhost=localhost

exit

end

flag=`echo$`

if[$flag=0]then

echoERRORCantconnectmysqlserverbackupaborted

exit

else

echoMySQLconnectokPleasewait

DeterminewhetherabackupdatabaseisdefinedornotIfsobeginthebackupifnotthenabort

if[$backup_db_arr=]then

dbnames=$(cut-d-f1-5$backup_database)

echoarris($backup_db_arr[])

fordbnamein$backup_db_arr[]

do

echodatabase$dbnamebackupstart

`mkdir-p$backup_dir`

`mysqldump-h$mysql_host-P$mysql_port-u$mysql_user-p$mysql_password$dbname-default-character-set=

$mysql_charset|gzipgt$backup_dir$dbname-$backup_timesqlgz`

flag=`echo$`

if[$flag==0]then

echodatabase$dbnamesuccessfullybackedupto$backup_dir$dbname-$backup_timesqlgz

else

echodatabase$dbnamebackuphasfailed

fi

done

else

echoERRORNodatabasetobackupbackupaborted

exit

fi

Ifdeletingexpiredbackupsisenableddeleteallexpiredbackups

Backupandrecovery

273

if[$expire_backup_delete==ON-a$backup_location=]then

`find$backup_location-typed-o-typef-ctime+$expire_days-execrm-rf`

`find$backup_location-typed-mtime+$expire_days|xargsrm-rf`

echoExpiredbackupdatadeletecomplete

fi

echoAlldatabaseshavebeensuccessfullybackedupThankyou

exit

fi

Modifythepropertiesoftheshellscriptlikeso

chmod600rootmysql_backupsh

chmod+xrootmysql_backupsh

Thenaddthecrontabcommand

0000rootmysql_backupsh

Thissetsupregularbackupsofyourdatabasestothevarwwwmysqldirectoryeverydayat0000whichcanthenbesynchronizedusingrsync

MySQLRecoveryWevejustdescribedsomecommonlyusedbackuptechniquesforMySQLnamelyhotbackupsandcoldbackupsTorecapthemaingoalofahotbackupistobeabletorecoverdatainreal-timeafteranapplicationhasfailedinsomewaysuchasinthecaseofaserverhard-diskmalfunctionWelearnedthatthistypeofschemecanbeimplementedbymodifyingdatabaseconfigurationfilessothatdatabasesarereplicatedontoaslaveminimizinginterruptiontoservices

ButsometimesweneedtoperformacoldbackupoftheSQLdatarecoveryaswithdatabasebackupyoucanimportthroughthecommandHotbackupsarehoweversometimesinadequateTherearecertainsituationswherecoldbackupsarerequiredtoperformdatarecoveryevenifitsonlyapartialoneWhenyouhaveacoldbackupofyourdatabaseyoucanusethefollowingMySQLcommandtoimportit

mysql-uusername-pdatabseltbackupsql

AsyoucanseeimportingandexportingdatabaseisafairlysimplematterIfyouneedtomanageadministrativeprivilegesordealwithdifferentcharactersetsthisprocessmaybecomealittlemorecomplicatedthoughthereareanumberofcommandswhichwillhelpyoutodothis

RedisbackupRedisisoneofthemostpopularNoSQLdatabasesandbothhotandcoldbackuptechniquescanalsobeusedinsystemswhichuseitLikeMySQLRedisalsosupportsmasterslavemodewhichisidealforimplementinghotbackups(refertoRedisofficialdocumentationtolearnhowtoconfigurethistheprocessisverystraightforward)AsforcoldbackupsRedisroutinelysavescacheddatainmemorytothedatabasefileon-diskWecansimplyusethersyncbackupmethoddescribedabovetosynchronizeitwithanon-localmachine

RedisrecoverySimilarlyRedisrecoverycanbedividedintohotandcoldbackuprecoveryThemethodsandobjectivesofrecoveringdatafromahotbackupofaRedisdatabasearethesameasthosementionedaboveforMySQLaslongastheRedisapplicationisusingtheappropriatedatabaseconnection

Backupandrecovery

274

ARediscoldbackuprecoverysimplyinvolvescopyingbacked-updatabasefilesintotheworkingdirectorythenstartingRedisonitThedatabasefilesareautomaticallyloadedintomemoryatboottimethespeedwithwhichRedisbootswilldependonthesizeofthedatabasefiles

SummaryInthissectionwelookedatsometechniquesforbackingupdataaswellasrecoveringfromdisasterswhichmayoccurafterdeployingourapplicationsWealsointroducedrsyncatoolwhichcanbeusedtosynchronizefilesondifferentsystemsUsingrsyncwecaneasilyperformbackupandrestorationproceduresforbothMySQLandRedisdatabasesamongothersWehopethatbybeingintroducedtosomeoftheseconceptsyouwillbeabletodevelopdisasterrecoveryprocedurestobetterprotectthedatainyourwebapplications

LinksDirectoryPrevioussectionDeploymentNextsectionSummary

Backupandrecovery

275

125SummaryInthischapterwediscussedhowtodeployandmaintainourGowebapplicationsWealsolookedatsomecloselyrelatedtopicswhichcanhelpustokeepthemrunningsmoothlywithminimalmaintenance

Specificallywelookedat

CreatingarobustloggingsystemcapableofrecordingerrorsandnotifyingsystemadministratorsHandlingruntimeerrorsthatmayoccurincludingloggingthemandhowtorelaythisinformationinauser-friendlymannerthatthereisaproblemHandling404errorsandnotifyingusersthattherequestedpagecannotbefoundDeployingapplicationstoaproductionenvironment(includinghowtodeployupdates)HowtodeployhighlyavailableapplicationsBackingupandrestoringfilesanddatabases

Afterreadingthecontentsofthischapterthosethinkingaboutdevelopingawebapplicationfromscratchshouldalreadyhavethefullpictureonhowtodosothischapterprovidedanintroductiononhowtomanagedeploymentenvironmentswhilepreviouschaptershavefocusedonthedevelopmentofcode

LinksDirectoryPrevioussectionBackupandrecoveryNextchapterBuildingawebframework

Summary

276

13BuildingawebframeworkThePrecedingtwelvechaptersdescribehowtodevelopwebapplicationsinGointroducingalotofbasicknowledgedevelopmenttoolsandtechniquesInthischapterwewillbeusingthisknowledgetoimplementasimplewebframeworkThefirstsectionofthischapterwilltakeyouthroughtheplanninganddesignstageofbuildingawebframeworkWelllookatleveragingtheMVCpatternaswellasdesigningprogramexecutionflowamongotherthingsThesecondsectionwilldescribethefirstfeatureofourframeworkRoutingnamelyhowtomapURLstoprocessinglogicTheninthethirdsectionwedescribetheprocessinglogicitselfwhichinvolvesdesigninggenericcontrollersandhowtohandlerequestsandreturnresponsesafterinheritingfromanobjecthandlerNextwedescribesomeoftheauxiliaryfunctionalitycommontomostwebframeworkssuchaslogprocessinginformationconfigurationetcFinallywellimplementasimplebloggingsystemontopofourframeworkwhichwilldemonstratetheapplicationlogicnecessaryforpublishingmodifyingdeletinganddisplayinglistsofblogposts

Byseeingfirst-handhowtoimplementsuchacompleteprojectfromscratchyouwillhopefullyhaveabetterunderstandingoftheinnerworkingsofGowebapplicationsYoullbecomfortablebuildingyourownprojectdirectorystructuresimplementingURLroutersandutilizingMVCamongotheraspectsofwebdevelopmentAmongtheframeworksprevalenttodayMVCisnolongeramythItsnotuncommontohearprogrammersarguingaboutwhichframeworksaregoodandwhicharebadwhichisoftentooshallowofanapproachFrameworksareonlytoolsandsometoolsaremoresuitableforcertainapplicationsthanothersTherearenouniversallygoodorbadtoolsThusbyteachingyourselfhowtowriteaframeworkfromscratchyouwillbeabletotailor-maketheperfecttooltobestrealizeyourideas

LinksDirectoryPreviouschapterChapter12summaryNextsectionProjectprogram

Buildawebframework

277

131ProjectplanningAnythingyouintendtodowellmustfirstbeplannedwellInourcaseourintentionistodevelopabloggingsystemsothefirststepweshouldtakeistodesigntheflowoftheapplicationinitsentiretyWhenwehaveaclearunderstandingoftheourapplicationsprocessofexecutionthesubsequentdesignandcodingstepsbecomemucheasier

GOPATHandprojectsettingsLetsproceedbyassumingthatourGOPATHpointstoafolderwithanordinarydirectoryname(ifnotwecaneasilysetupasuitabledirectoryandsetitspathastheGOPATH)AswevedescribeearlieraGOPATHcancontainmorethanonedirectoryinWindowswecansetthisasanenvironmentvariableinlinuxOSXsystemsGOPATHcanbesetusingexportieexportgopath=pathtoyourdirectoryaslongasthedirectorywhichGOPATHpointstocontainsthethreesub-directoriespkgbinandsrcBelowweveplacedthesourcecodeofournewprojectinthesrcdirectorywiththetentativenamebeelogHerearesomescreenshotsoftheWindowsenvironmentvariablesaswellasofthedirectorystructure

Figure131SettingtheGOPATHenvironmentvariable

Figure132Theworkingdirectoryunder$gopathsrc

ApplicationflowchartOurbloggingsystemwillbebasedonthemodel-view-controllerdesignpatternMVCistheseparationoftheapplicationlogicfromthepresentationlayerInpracticewhenwekeepthepresentationlayerseparatedwecandrasticallyreducetheamountofcodeneededonourwebpages

ModelsrepresentdataaswellastherulesandlogicgoverningitInGeneralamodelclasswillcontainfunctionsforremovinginsertingandupdatingdatabaseinformationViewsarearepresentationofthestateofamodelAviewisusuallyapagebutinGoaviewcanalsobeafragmentofapagesuchasaheaderorfooterItcanalsobeanRSSfeedoranyothertypeofpageGostemplatepackageprovidesverygoodsupportforviewlayerfunctionalityControllersarethegluelogicbetweenthemodelandviewlayersandencompassesalltheintermediarylogicnecessaryforhandlingHTTPrequestsandgeneratingWebpages

Thefollowingfigureisanoverviewoftheprojectframeworkanddemonstrateshowdatawillflowthroughthesystem

Figure133frameworkdataflow

1 Maingoistheapplicationsentrypointandinitializessomebasicresourcesrequiredtoruntheblogsuchasconfigurationinformationlisteningportsetc

2 RoutingchecksallincomingHTTPrequestsandaccordingtothemethodURLandparametersmatchesitwiththecorrespondingcontrolleraction

3 Iftherequestedresourcehasalreadybeencachedtheapplicationwillbypasstheusualexecutionprocessandreturnaresponsedirectlytotheusersbrowser

4 SecuritydetectionTheapplicationwillfilterincomingHTTPrequestsandanyotherusersubmitteddatabeforehandingitofftothecontroller

5 ControllerloadsmodelscorelibrariesandanyotherresourcesrequiredtoprocessspecificrequestsThecontrollerisprimarilyresponsibleforhandlingbusinesslogic

Projectprogram

278

6 OutputtherenderedviewtobesenttotheclientswebbrowserIfcachinghasbeenenabledthefirstviewiscachedforfuturerequeststothesameresource

DirectorystructureAccordingtotheframeworkflowwevedesignedaboveourblogprojectsdirectorystructureshouldlooksomethinglikethefollowing

|mdashmdashmaingoimportdocuments

|mdashmdashconfconfigurationfilesandprocessingmodule

|mdashmdashcontrollerscontrollerentry

|mdashmdashmodelsdatabaseprocessingmodule

|mdashmdashutilsusefulfunctionlibrary

|mdashmdashstaticstaticfiledirectory

|mdashmdashviewsviewgallery

FrameworkdesignInordertoquicklybuildourblogweneedtodevelopaminimalframeworkbasedontheapplicationwevedesignedaboveTheframeworkshouldincluderoutingcapabilitiessupportforRESTfulcontrollersautomatedtemplaterenderingaloggingsystemconfigurationmanagementandmore

SummaryThissectiondescribestheinitialdesignofourbloggingsystemfromsettingupourGOPATHtobrieflyintroducingtheMVCpatternWealsolookedattheflowofdataandtheexecutionsequenceofourbloggingsystemFinallywedesignedthestructureofourprojectdirectoryAtthispointwevebasicallycompletedthegroundworkrequiredforassemblingourframeworkInthenextfewsectionswewillimplementeachofthecomponentswevediscussedonebyone

LinksDirectoryPrevioussectionBuildingawebframeworkNextsectionCustomizingrouters

Projectprogram

279

132Customizingrouters

HTTProutingTheHTTProutingcomponentisresponsibleformappingHTTPrequeststoacorrespondingfunctionorstructmethodTheroutertakestwokeypiecesofinformationfromincomingrequests

-Theuserrequestedpath(forexampleuser123article123)andanyquerystringsorparametersthatcomewithit(forexampleid=11)-TheHTTPrequestmethod(GETPOSTPUTandDELETEPATCHetc)

Therouterthenforwardstherequesttothehandlerfunction(controllerlayer)thathasbeenregisteredwiththatparticularHTTPmethodandpath

DefaultroutingimplementationInsection34weintroducedGoshttppackageindetailwhichincludedhowtodesignandimplementroutingHerewetakeanotherlookatanexamplethatillustratestheroutingprocess

funcfooHandler(whttpResponseWriterrhttpRequest)

fmtFprintf(wHelloqhtmlEscapeString(rURLPath))

httpHandle(foofooHandler)

httpHandleFunc(barfunc(whttpResponseWriterrhttpRequest)

fmtFprintf(wHelloqhtmlEscapeString(rURLPath))

)

logFatal(httpListenAndServe(8080nil))

TheexampleabovecallshttpsdefaultmuxcalledDefaultServeMuximplicitlyspecifiedbythenilparameterinthecalltohttpListenAndServeThehttpHandlefunctiontakestwoparametersthefirstparameteristheresourceyouwantuserstoaccessspecifiedbyitsURLpath(whichisstoredinrURLPath)andthesecondargumentbindsahandlerfunctionwiththispathTheRouterhastwomainjobs

ToaddandstoreroutinginformationToforwardrequeststoahandlerfunctionforprocessing

BydefaultGoroutesarehandledwithhttpHandleandhttpHandleFunctypesregisteredbydefaultthroughtheunderlyingDefaultServeMuxHandle(patternstringhandlerHandler)functionThisfunctionmapsresourcepathstohandlersandstorestheminamap[string]muxEntrymapThisisthefirstjobthatwementionedabove

WhentheapplicationisrunningtheGoserverlistenstoaportWhenitreceivesatcpconnectionitusesaHandlertoprocessitAsaforementionedsincetheHandlerintheexampleaboveisnilthedefaultrouterhttpDefaultServeMuxisusedUsingthemapofpreviouslystoredroutesDefaultServeMuxServeHTTPwilldispatchtherequesttothefirsthandlerwithamatchingpathThisistherouterssecondjob

forkv=rangemuxm

ifpathMatch(kpath)

continue

ifh==nil||len(k)gtn

n=len(k)

h=vh

Customizedrouters

280

RoutingwithBeegoAtpresentmostGowebapplicationsbasetheirroutingonhttpsdefaultrouterhoweverthishasseverallimitations

DoesnotsupportdynamicrouteswithparameterssuchastheuserUIDDoesnothavegoodsupportforRESTTheaccessmethodscannotberestrictedforinstanceintheaboveexamplewhenusersaccessfootheycanusetheGETPOSTDELETEandHEADHTTPmethodsamongothersInlargeappsroutingrulescanbecomerepetitiveandcumbersomePersonallyIvedevelopedsimplewebAPIscomposedofnearlythirtyroutingruleswheninfacttheserulescouldhavebeenfurthersimplifiedusingmethodstructs

TheBeegoframeworksrouterisdesignedtoovercometheselimitationstakingtheRESTparadigmintoconsiderationandsimplifyingthestoringandforwardingofroutesandrequests

Storingroutes

ToaddressthefirstlimitationofthedefaultrouterweneedtobeabletosupportdynamicURLparametersForthesecondandthirdpointsweadoptanalternativeapproachmappingRESTmethodstostructmethodsandroutingrequeststothisstructinsteadoftohandlerfunctionsThiswayaforwardedrequestcanbehandledaccordingtoitsHTTPmethod

BasedontheaboveideaswevedesignedtwodatatypescontrollerInfowhichsavesthepathandthecorrespondingcontrollerTypestructasareflectTypetypeandControllerRegistorwhichsavesroutinginformationforthespecifiedBeegoapplication

typecontrollerInfostruct

regexregexpRegexp

paramsmap[int]string

controllerTypereflectType

typeControllerRegistorstruct

routers[]controllerInfo

ApplicationApp

ControllerRegistorsexternalinterfacecontainsthefollowingmethod

func(pControllerRegistor)Add(patternstringcControllerInterface)

Itsdetailedimplementationisasfollows

Customizedrouters

281

func(pControllerRegistor)Add(patternstringcControllerInterface)

parts=stringsSplit(pattern)

j=0

params=make(map[int]string)

foripart=rangeparts

ifstringsHasPrefix(part)

expr=([^]+)

ausermaychoosetooverridethedefaultexpression

similartoexpressjslsquouserid([0-9]+)rsquo

ifindex=stringsIndex(part()index=-1

expr=part[index]

part=part[index]

params[j]=part

parts[i]=expr

j++

recreatetheurlpatternwithparametersreplaced

byregularexpressionsThencompiletheregex

pattern=stringsJoin(parts)

regexregexErr=regexpCompile(pattern)

ifregexErr=nil

TODOadderrorhandlingheretoavoidpanic

panic(regexErr)

return

nowcreatetheRoute

t=reflectIndirect(reflectValueOf(c))Type()

route=ampcontrollerInfo

routeregex=regex

routeparams=params

routecontrollerType=t

prouters=append(proutersroute)

StaticroutingWeveimplementeddynamicroutinginourexampleaboveBydefaultGoshttppackagesupportsservingstaticfileswithhttpFileServerwhichreturnsaHandlerSincewehaveimplementedacustomrouterwewillalsoneedawayofhandlingstaticfilesBeegosstaticfolderpathissavedinaglobalvariablecalledStaticDirwhichmapstheURLtocorrespondingpathsTheSetStaticPathsimplementationcanbeseenbelow

func(appApp)SetStaticPath(urlstringpathstring)App

StaticDir[url]=path

returnapp

Theapplicationsstaticroutescanbesetlikeso

beegoSetStaticPath(imgstaticimg)

Forwardingroutes

Customizedrouters

282

WecanforwardroutesbasedontheforwardinginformationcontainedwithinControllerRegistorThedetailedimplementationcanbeseeninthefollowingcodesnippet

AutoRoute

func(pControllerRegistor)ServeHTTP(whttpResponseWriterrhttpRequest)

deferfunc()

iferr=recover()err=nil

ifRecoverPanic

gobacktopanic

panic(err)

else

Critical(Handlercrashedwitherrorerr)

fori=1i+=1

_filelineok=runtimeCaller(i)

ifok

break

Critical(fileline)

()

varstartedbool

forprefixstaticDir=rangeStaticDir

ifstringsHasPrefix(rURLPathprefix)

file=staticDir+rURLPath[len(prefix)]

httpServeFile(wrfile)

started=true

return

requestPath=rURLPath

findamatchingRoute

for_route=rangeprouters

checkifRoutepatternmatchesurl

ifrouteregexMatchString(requestPath)

continue

getsubmatches(params)

matches=routeregexFindStringSubmatch(requestPath)

doublecheckthattheRoutematchestheURLpattern

iflen(matches[0])=len(requestPath)

continue

params=make(map[string]string)

iflen(routeparams)gt0

addurlparameterstothequeryparammap

values=rURLQuery()

forimatch=rangematches[1]

valuesAdd(routeparams[i]match)

params[routeparams[i]]=match

reassemblequeryparamsandaddtoRawQuery

rURLRawQuery=urlValues(values)Encode()+amp+rURLRawQuery

rURLRawQuery=urlValues(values)Encode()

Invoketherequesthandler

vc=reflectNew(routecontrollerType)

init=vcMethodByName(Init)

in=make([]reflectValue2)

ct=ampContextResponseWriterwRequestrParamsparams

in[0]=reflectValueOf(ct)

in[1]=reflectValueOf(routecontrollerTypeName())

initCall(in)

in=make([]reflectValue0)

Customizedrouters

283

method=vcMethodByName(Prepare)

methodCall(in)

ifrMethod==GET

method=vcMethodByName(Get)

methodCall(in)

elseifrMethod==POST

method=vcMethodByName(Post)

methodCall(in)

elseifrMethod==HEAD

method=vcMethodByName(Head)

methodCall(in)

elseifrMethod==DELETE

method=vcMethodByName(Delete)

methodCall(in)

elseifrMethod==PUT

method=vcMethodByName(Put)

methodCall(in)

elseifrMethod==PATCH

method=vcMethodByName(Patch)

methodCall(in)

elseifrMethod==OPTIONS

method=vcMethodByName(Options)

methodCall(in)

ifAutoRender

method=vcMethodByName(Render)

methodCall(in)

method=vcMethodByName(Finish)

methodCall(in)

started=true

break

ifnomatchestourlthrowanotfoundexception

ifstarted==false

httpNotFound(wr)

GettingstartedUsingourrouterdesignwecansolvethethreelimitationsmentionedearlierThethreemainuse-casesare

Registeringroutehandlers

beegoBeeAppRegisterController(ampcontrollersMainController)

Handlingdynamicparameters

beegoBeeAppRegisterController(paramampcontrollersUserController)

Regexmatching

beegoBeeAppRegisterController(usersuid([0-9]+)ampcontrollersUserController)

LinksDirectoryPrevioussectionProjectplanningNextsectionDesigningcontrollers

Customizedrouters

284

Customizedrouters

285

133DesigningcontrollersMosttraditionalMVCframeworksarebasedonsuffixactionmappingNowadaystheRESTstylewebarchitectureisbecomingincreasinglypopularOnecanimplementREST-styleURLsbyfilteringorrewritingthembutwhynotjustdesignanewREST-styleMVCframeworkinsteadThissectionisbasedonthisideaandfocusesondesigningandimplementingacontrollerbasedREST-styleMVCframeworkfromscratchOurgoalistosimplifythedevelopmentofwebapplicationsperhapsevenallowingustowriteasinglelineofcodecapableofservingHelloworld

ThecontrollersroleTheMVCdesignpatterniscurrentlythemostusedframeworkmodelforwebapplicationsBykeepingModelsViewsandControllersseparatedwecankeepourwebapplicationsmodularmaintainabletestableandextensibleAmodelencapsulatesdataandanyofthebusinesslogicthatgovernsthatdatasuchasaccessibilityrulespersistencevalidationetcViewsserveasthedatasrepresentationandinthecaseofwebapplicationstheyusuallyliveastemplateswhicharethenrenderedintoHTMLandservedControllersserveasthegluelogicbetweenModelsandViewsandtypicallyhavemethodsforhandlingdifferentURLsAsdescribedintheprevioussectionwhenaURLrequestisforwardedtoacontrollerbytherouterthecontrollerdelegatescommandstotheModeltoperformsomeactionthennotifiestheViewofanychangesIncertaincasesthereisnoneedformodelstoperformanykindoflogicalordataprocessingorforanyviewstoberenderedForinstanceinthecaseofanHTTP302redirectnoviewneedstoberenderedandnoprocessingneedstobeperformedbytheModelhowevertheControllersjobisstillessential

RESTfuldesigninBeegoTheprevioussectiondescribesregisteringroutehandlerswithRESTfulstructsNowweneedtodesignthebaseclassforalogiccontrollerthatwillbecomposedoftwopartsastructandinterfacetype

typeControllerstruct

CtContext

TpltemplateTemplate

Datamap[interface]interface

ChildNamestring

TplNamesstring

Layout[]string

TplExtstring

typeControllerInterfaceinterface

Init(ctContextcnstring)Initializethecontextandsubclassname

Prepare()someprocessingbeforeexecutionbegins

Get()method=GETprocessing

Post()method=POSTprocessing

Delete()method=DELETEprocessing

Put()method=PUThandling

Head()method=HEADprocessing

Patch()method=PATCHtreatment

Options()method=OPTIONSprocessing

Finish()executedaftercompletionoftreatment

Render()errormethodexecutedafterthecorrespondingmethodtorenderthepage

ThenaddtheroutehandlingfunctiondescribedearlierinthischapterWhenarouteisdefinedtobeaControllerInterfacetypesolongaswecanimplementthisinterfacewecanhaveaccesstothefollowingmethodsofourbaseclasscontroller

func(cController)Init(ctContextcnstring)

cData=make(map[interface]interface)

cLayout=make([]string0)

Designcontrollers

286

cTplNames=

cChildName=cn

cCt=ct

cTplExt=tpl

func(cController)Prepare()

func(cController)Finish()

func(cController)Get()

httpError(cCtResponseWriterMethodNotAllowed405)

func(cController)Post()

httpError(cCtResponseWriterMethodNotAllowed405)

func(cController)Delete()

httpError(cCtResponseWriterMethodNotAllowed405)

func(cController)Put()

httpError(cCtResponseWriterMethodNotAllowed405)

func(cController)Head()

httpError(cCtResponseWriterMethodNotAllowed405)

func(cController)Patch()

httpError(cCtResponseWriterMethodNotAllowed405)

func(cController)Options()

httpError(cCtResponseWriterMethodNotAllowed405)

func(cController)Render()error

iflen(cLayout)gt0

varfilenames[]string

for_file=rangecLayout

filenames=append(filenamespathJoin(ViewsPathfile))

terr=templateParseFiles(filenames)

iferr=nil

Trace(templateParseFileserrerr)

err=tExecuteTemplate(cCtResponseWritercTplNamescData)

iferr=nil

Trace(templateExecuteerrerr)

else

ifcTplNames==

cTplNames=cChildName++cCtRequestMethod++cTplExt

terr=templateParseFiles(pathJoin(ViewsPathcTplNames))

iferr=nil

Trace(templateParseFileserrerr)

err=tExecute(cCtResponseWritercData)

iferr=nil

Trace(templateExecuteerrerr)

returnnil

Designcontrollers

287

func(cController)Redirect(urlstringcodeint)

cCtRedirect(codeurl)

AbovethecontrollerbaseclassalreadyimplementsthefunctionsdefinedintheinterfaceThroughourroutingrulestherequestwillberoutedtotheappropriatecontrollerwhichwillinturnexecutethefollowingmethods

Init()initializationroutine

Prepare()pre-initializationroutineeachinheritingsubclassmayimplementthisfunction

method()dependingontherequestmethodperformdifferentfunctionsGETPOSTPUTHEADetcSubclassesshouldi

mplementthesefunctionsifnotimplementedthenthedefaultis403

Render()optionalmethodDeterminewhetherornottoexecuteaccordingtotheglobalvariableAutoRender

Finish()isexecutedaftertheactionbeencompletedEachinheritingsubclassmayimplementthisfunction

ApplicationguideAbovewevejustfinisheddiscussingBeegosimplementationofthebasecontrollerclassWecannowusethisinformationtodesignourrequesthandlinginheritingfromthebaseclassandimplementingthenecessarymethodsinourowncontroller

packagecontrollers

import(

githubcomastaxiebeego

)

typeMainControllerstruct

beegoController

func(thisMainController)Get()

thisData[Username]=astaxie

thisData[Email]=astaxiegmailcom

thisTplNames=indextpl

InthecodeaboveweveimplementedasubclassofControllercalledMainControllerwhichonlyimplementstheGet()methodIfausertriestoaccesstheresourceusinganyoftheotherHTTPmethods(POSTHEADetc)a403ForbiddenwillbereturnedHoweverifausersubmitsaGETrequesttotheresourceandwehavetheAutoRendervariablesettotruetheresourcescontrollerwillautomaticallycallitsRender()functionrenderingthecorrespondingtemplateandrespondingwiththefollowing

Theindextplcodecanbeseenbelowasyoucanseeparsingmodeldataintoatemplateisquitesimple

ltDOCTYPEhtmlgt

lthtmlgt

ltheadgt

lttitlegtbeegowelcometemplatelttitlegt

ltheadgt

ltbodygt

lth1gtHelloworldUsernameEmaillth1gt

ltbodygt

lthtmlgt

LinksDirectory

Designcontrollers

288

PrevioussectionCustomizingroutersNextsectionLogsandconfigurations

Designcontrollers

289

134Loggingandconfiguration

TheimportanceofloggingandconfigurationPreviouslyinthebookwesawthateventloggingplaysaveryimportantroleinapplicationdevelopmentWithadequateloggingwecanrecordcrucialinformationthatcanlaterbedissectedfordebuggingandoptimizationpurposesInthesectionwherewelookedattheseelogloggingutilitywesawthatithadsettingsforvariousloglevelgradationswhichcanbeessentialforprogramdevelopmentanddeploymentwecansetthelogginglevellowerinadevelopmentenvironmentwhilesettingithighinproductionsothatwecanmaskextraneousinformationwhenwearetryingtodebugourapplication

SettinguptheserverconfigurationmodulefordeployinganapplicationinvolvesanumberofdifferentserversettingsForexamplewetypicallyneedtoprovideinformationregardingdatabaseconfigurationlisteningportsetcviatheconfigurationfileSettingupacentralizedconfigurationfileallowsustheflexibilityofdeployingtheapplicationtodifferentmachinesandconnectingtoremotedatabasesifneeded

TheBeegologgingsystemTheBeegologgersdesignborrowsideasfromseelogandprovidessimilarfunctionalityintermsofsettinglogginglevelsBeegossystemishowevermorelightweightandmakesuseoftheGoslogLoggerinterfaceBydefaultlogsareoutputtoosStdoutbutuserscanimplementthisinterfacethroughbeegoSetLoggertocustomizethisAdetailedexampleofanimplementedinterfacecanbeseenbelow

Loglevelsforcontrollingtheloggingoutput

const(

LevelTrace=iota

LevelDebug

LevelInfo

LevelWarning

LevelError

LevelCritical

)

logLevelcontrolsthegloballoglevelusedbythelogger

varlevel=LevelTrace

LogLevelreturnsthegloballoglevelandcanbeusedin

acustomimplementationsoftheloggerinterface

funcLevel()int

returnlevel

SetLogLevelsetsthegloballoglevelusedbythesimple

logger

funcSetLevel(lint)

level=l

ThissectionimplementstheaboveloggradingsystemThedefaultlevelissettoTraceanduserscancustomizegradinglevelsusingSetLevel

Logsandconfigurations

290

loggerreferencestheusedapplicationlogger

varBeeLogger=logNew(osStdoutlogLdate|logLtime)

SetLoggersetsanewlogger

funcSetLogger(llogLogger)

BeeLogger=l

Tracelogsamessageattracelevel

funcTrace(vinterface)

iflevellt=LevelTrace

BeeLoggerPrintf([T]vnv)

Debuglogsamessageatdebuglevel

funcDebug(vinterface)

iflevellt=LevelDebug

BeeLoggerPrintf([D]vnv)

Infologsamessageatinfolevel

funcInfo(vinterface)

iflevellt=LevelInfo

BeeLoggerPrintf([I]vnv)

Warninglogsamessageatwarninglevel

funcWarn(vinterface)

iflevellt=LevelWarning

BeeLoggerPrintf([W]vnv)

Errorlogsamessageaterrorlevel

funcError(vinterface)

iflevellt=LevelError

BeeLoggerPrintf([E]vnv)

Criticallogsamessageatcriticallevel

funcCritical(vinterface)

iflevellt=LevelCritical

BeeLoggerPrintf([C]vnv)

ThecodesnippetaboveinitializesaBeeLoggerobjectbydefaultoutputtinglogstoosStdoutAsmentioneduserscanimplementbeegoSetLoggertocustomizetheloggersoutputBeeLoggerimplementssixfunctions

Trace(recordgeneralinformationforexample)EnteredparsefunctionvalidationblockValidationenteredsecondifDictionaryDictisemptyUsingdefaultvalue

Debug(debugginginformationforexample)WebpagerequestedhttpsomesitecomParams=ResponsegeneratedResponsesize10000SendingNewfilereceivedTypePNGSize20000

Info(printinggeneralinformationforexample)WebserverrestartedHourlystatisticsRequestedpages12345Errors123ServicepausedWaitingforresumecall

Logsandconfigurations

291

Warn(warningmessagesforexample)Cachecorruptedforfile=testfileReadingfromback-endDatabase19216807DBnotrespondingUsingbackup19216808DBNoresponsefromstatisticsserverStatisticsnotsent

Error(errormessagesforexample)InternalerrorCannotprocessrequest12345ErrorCannotperformlogincredentialsDBnotresponding

Critical(fatalerrorsforexample)CriticalpanicreceivedShuttingdownFatalerrorAppisshuttingdowntopreventdatacorruptionorloss

YoucanseethateachoftheselevelshasaspecificpurposeForinstanceifwesettheloggingleveltoWarn(level=LevelWarning)atthetimeofdeploymentallofthelowerlevellogs(TraceDebugInfo)willnotoutputanything

BeegoconfigurationdesignForprocessingconfigurationinformationBeegoimplementsakey=valuefileparserwhichreadsinformationformattedsimilarlytoiniconfigurationfilesTheparserreadstheconfigurationdataandsavesittoamapFinallyitcallsseveralfunctionsforretrievingthevaluesdatatype(intstringetc)Thedetailedimplementationcanbeseenbelow

Definesomeglobalconstantsfortheiniconfigurationfile

var(

bComment=[]byte

bEmpty=[]byte

bEqual=[]byte=

bDQuote=[]byte

)

Definestheformatoftheconfigurationfile

AConfigrepresentstheconfiguration

typeConfigstruct

filenamestring

commentmap[int][]stringid[]commentkeyid1isformaincomment

datamap[string]stringkeyvalue

offsetmap[string]int64keyoffsetforediting

syncRWMutex

DefinesafunctionforparsingthefileTheprocessbeginsbyopeningthefilethenreadingitlinebylineandparsingcommentsblanklinesandkey=valuedata

Logsandconfigurations

292

ParseFilecreatesanewConfigandparsesthefileconfigurationfromthe

namedfile

funcLoadConfig(namestring)(Configerror)

fileerr=osOpen(name)

iferr=nil

returnnilerr

cfg=ampConfig

fileName()

make(map[int][]string)

make(map[string]string)

make(map[string]int64)

syncRWMutex

cfgLock()

defercfgUnlock()

deferfileClose()

varcommentbytesBuffer

buf=bufioNewReader(file)

fornCommentoff=0int64(1)

line_err=bufReadLine()

iferr==ioEOF

break

ifbytesEqual(linebEmpty)

continue

off+=int64(len(line))

ifbytesHasPrefix(linebComment)

line=bytesTrimLeft(line)

line=bytesTrimLeftFunc(lineunicodeIsSpace)

commentWrite(line)

commentWriteByte(n)

continue

ifcommentLen()=0

cfgcomment[nComment]=[]stringcommentString()

commentReset()

nComment++

val=bytesSplitN(linebEqual2)

ifbytesHasPrefix(val[1]bDQuote)

val[1]=bytesTrim(val[1]``)

key=stringsTrimSpace(string(val[0]))

cfgcomment[nComment-1]=append(cfgcomment[nComment-1]key)

cfgdata[key]=stringsTrimSpace(string(val[1]))

cfgoffset[key]=off

returncfgnil

BelowareanumberoffunctionstheparserusesforreadingtheconfigurationfileThereturnvalueisdeterminedaseitheraboolintfloat64orstring

Logsandconfigurations

293

Boolreturnsthebooleanvalueforagivenkey

func(cConfig)Bool(keystring)(boolerror)

returnstrconvParseBool(cdata[key])

Intreturnstheintegervalueforagivenkey

func(cConfig)Int(keystring)(interror)

returnstrconvAtoi(cdata[key])

Floatreturnsthefloatvalueforagivenkey

func(cConfig)Float(keystring)(float64error)

returnstrconvParseFloat(cdata[key]64)

Stringreturnsthestringvalueforagivenkey

func(cConfig)String(keystring)string

returncdata[key]

ApplicationguideThefollowingfunctionisanexampleofanapplicationIusedtofetchjsondatafromaremoteurladdress

funcGetJson()

resperr=httpGet(beegoAppConfigString(url))

iferr=nil

beegoCritical(httpgetinfoerror)

return

deferrespBodyClose()

bodyerr=ioutilReadAll(respBody)

err=jsonUnmarshal(bodyampAllInfo)

iferr=nil

beegoCritical(errorerr)

BeegosCritical()loggingfunctioniscalledtoreportanyerrorswhichmayoccurintheGetJson()functionbeegoAppConfigString(url)isusedtoobtaininformationfromaconfigurationfile(typicallyappconf)whichmightlooksomethinglikethefollowing

appname=hs

url=httpwwwapicomapihtml

LinksDirectoryPrevioussectionDesigningcontrollersNextsectionAddingdeletingandupdatingblogs

Logsandconfigurations

294

135AddingdeletingandupdatingblogsWevealreadyintroducedtheentireconceptbehindtheBeegoframeworkthroughexamplesandpseudo-codeThissectionwilldescribehowtoimplementabloggingsystemusingBeegoincludingtheabilitytobrowseaddmodifyanddeleteblogposts

BlogdirectoryOurblogsdirectorystructurecanbeseenbelow

maingo

views

viewtpl

newtpl

layouttpl

indextpl

edittpl

modelsmodelgo

controllers

indexgo

viewgo

newgo

deletego

editgo

BlogroutingOurblogsmainroutingrulesareasfollows

ShowblogHome

beegoRegisterController(ampcontrollersIndexController)

Viewblogdetails

beegoRegisterController(viewid([0-9]+)ampcontrollersViewController)

CreateblogBowen

beegoRegisterController(newampcontrollersNewController)

DeleteBowen

beegoRegisterController(deleteid([0-9]+)ampcontrollersDeleteController)

EditBowen

beegoRegisterController(editid([0-9]+)ampcontrollersEditController)

DatabasestructureAtrivialdatabasetabletostorebasicbloginformation

CREATETABLEentries(

idINTAUTO_INCREMENT

titleTEXT

contentTEXT

createdDATETIME

primarykey(id)

)

ControllerIndexController

Adddeleteandupdateblogs

295

typeIndexControllerstruct

beegoController

func(thisIndexController)Get()

thisData[blogs]=modelsGetAll()

thisLayout=layouttpl

thisTplNames=indextpl

ViewController

typeViewControllerstruct

beegoController

func(thisViewController)Get()

inputs=thisInput()

id_=strconvAtoi(thisCtxParams[id])

thisData[Post]=modelsGetBlog(id)

thisLayout=layouttpl

thisTplNames=viewtpl

NewController

typeNewControllerstruct

beegoController

func(thisNewController)Get()

thisLayout=layouttpl

thisTplNames=newtpl

func(thisNewController)Post()

inputs=thisInput()

varblogmodelsBlog

blogTitle=inputsGet(title)

blogContent=inputsGet(content)

blogCreated=timeNow()

modelsSaveBlog(blog)

thisCtxRedirect(302)

EditController

Adddeleteandupdateblogs

296

typeEditControllerstruct

beegoController

func(thisEditController)Get()

inputs=thisInput()

id_=strconvAtoi(thisCtxParams[id])

thisData[Post]=modelsGetBlog(id)

thisLayout=layouttpl

thisTplNames=edittpl

func(thisEditController)Post()

inputs=thisInput()

varblogmodelsBlog

blogId_=strconvAtoi(inputsGet(id))

blogTitle=inputsGet(title)

blogContent=inputsGet(content)

blogCreated=timeNow()

modelsSaveBlog(blog)

thisCtxRedirect(302)

DeleteController

typeDeleteControllerstruct

beegoController

func(thisDeleteController)Get()

id_=strconvAtoi(thisCtxInputParams[id])

blog=modelsGetBlog(id)

thisData[Post]=blog

modelsDelBlog(blog)

thisCtxRedirect(302)

Modellayer

Adddeleteandupdateblogs

297

packagemodels

import(

databasesql

githubcomastaxiebeedb

_githubcomziutekmymysqlgodrv

time

)

typeBlogstruct

Idint`PK`

Titlestring

Contentstring

CreatedtimeTime

funcGetLink()beedbModel

dberr=sqlOpen(mymysqlblogastaxie123456)

iferr=nil

panic(err)

orm=beedbNew(db)

returnorm

funcGetAll()(blogs[]Blog)

db=GetLink()

dbFindAll(ampblogs)

return

funcGetBlog(idint)(blogBlog)

db=GetLink()

dbWhere(id=id)Find(ampblog)

return

funcSaveBlog(blogBlog)(bgBlog)

db=GetLink()

dbSave(ampblog)

returnbg

funcDelBlog(blogBlog)

db=GetLink()

dbDelete(ampblog)

return

Viewlayerlayouttpl

Adddeleteandupdateblogs

298

lthtmlgt

ltheadgt

lttitlegtMyBloglttitlegt

ltstylegt

menu

width200px

floatright

ltstylegt

ltheadgt

ltbodygt

ltulid=menugt

ltligtltahref=gtHomeltagtltligt

ltligtltahref=newgtNewPostltagtltligt

ltulgt

LayoutContent

ltbodygt

lthtmlgt

indextpl

lth1gtBlogpostslth1gt

ltulgt

rangeblogs

ltligt

ltahref=viewIdgtTitleltagt

fromCreated

ltahref=editIdgtEditltagt

ltahref=deleteIdgtDeleteltagt

ltligt

end

ltulgt

viewtpl

lth1gtPostTitlelth1gt

PostCreatedltbrgt

PostContent

newtpl

lth1gtNewBlogPostlth1gt

ltformaction=method=postgt

Titleltinputtype=textname=titlegtltbrgt

Contentlttextareaname=contentcolspan=3rowspan=10gtlttextareagt

ltinputtype=submitgt

ltformgt

edittpl

lth1gtEditPostTitlelth1gt

lth1gtNewBlogPostlth1gt

ltformaction=method=postgt

Titleltinputtype=textname=titlevalue=PostTitlegtltbrgt

Contentlttextareaname=contentcolspan=3rowspan=10gtPostContentlttextareagt

ltinputtype=hiddenname=idvalue=PostIdgt

ltinputtype=submitgt

ltformgt

Adddeleteandupdateblogs

299

LinksDirectoryPrevioussectionLogsandconfigurationsNextsectionSummary

Adddeleteandupdateblogs

300

136SummaryInthischapterwedescribedhowtoimplementthemajorcomponentsofaGowebframeworkWefirstdesignedaroutertomakeupforsomeofshortcomingsinGosbuilt-inhttppackagecreatingaroutercapableofdynamicroutingandRESTsupportWealsodesignedourownRESTfulControllerclassinaccordwiththeprinciplesofMVCborrowingideasfromframeworkssuchasTornadoNextwedesignedandimplementedatemplatelayoutandautomatedrenderingsystemmainlyusingGosbuilt-intemplatingengineWethenimplementedacustomloggerandtalkedaboutframeworkconfigurationtoallowforflexibleapplicationdeploymentThroughthisprocesswehaveimplementedabasicwebframeworkcalledBeegowhichatpresenthasbeenopen-sourcedonGithubLastlyweimplementedasimplebloggingapplicationontopofBeegoAfterhavinggonethroughalloftheseexamplesyouwillhopefullyhavelearnedhowtoquicklydevelopwebsitesinGo

LinksDirectoryPrevioussectionAdddeleteandupdateblogsNextchapterDevelopwebframework

Summary

301

14DevelopingawebframeworkChapter13describedhowtodevelopawebframeworkinGoWeintroducedtheMVCarchitecturearoutingandloggingsystemandwealsolookedatsimpleserverconfigurationThesearethebasicbuildingblocksofmostframeworksanditsagoodstartHoweverformoresophisticatedneedssomeauxiliarytoolsareneededtofacilitaterapidwebsitedevelopmentInthischapterwewillprovidesomequicktipsandtoolsforspeedingupdevelopmentThefirstsectionwillcoverthehow-toshowprocessingstaticfilesandwewillbeusingTwittersopensourceCSSandJavascriptframeworkcalledBootstrapforbeautifyingourwebsiteThesecondsectiondescribeshowtousethepreviouslydescribedsessionsforuserloginprocessingNextthethirdsectiondescribeshowtogenerateformsandhowtoprocesstheseformsforvaliddataWewillalsotalkabouthowtobindmodelsforCRUDoperationsInsection4welldescribehowtoperformsomeuserauthenticationincludingbasicHTTPauthenticationandHTTPdigestauthenticationFinallythelastsectionwilltalkaboutimplementingthepreviouslydescribedi18ntosupportmulti-lingualwebapplications

ByextendingBeegointhischapterwewillbeabletorapidlydevelopfullstackwebapplicationsOfcoursewellgothroughthefeaturesoftheseextensionsstep-by-stepapplyingthemtothebloggingsystemwedevelopedinChapter13ThroughthedevelopmentofacompleteandbeautifulbloggingsystemuserswillhopefullybeabletoseehowBeegocanhelptoboostdeveloperproductivity

LinksDirectoryPreviouschapterChapter13summaryNextsectionStaticfiles

Developwebframework

302

141StaticfilesWevealreadytalkedabouthowtodealwithstaticfilesinprevioussectionsNowletslookathowtosetupandusestaticfilesinsideofBeegoThenthroughintroducingTwittersopensourceHTMLandCSSframeworkBootstrapwellbeablequicklycreatebeautifullookingwebsiteswithouthavingtodotoomuchdesignwork

BeegostaticfilesandsettingsGosnethttppackageprovidesastaticfileserverwithfunctionssuchasServeFileandFileServerBeegosstaticfilehandlingisbasedonthislayeranditsspecificimplementationisasfollow

staticfileserver

forprefixstaticDir=rangeStaticDir

ifstringsHasPrefix(rURLPathprefix)

file=staticDir+rURLPath[len(prefix)]

httpServeFile(wrfile)

wstarted=true

return

StaticDirstorestheURLwhichcorrespondstoastaticfiledirectorysowhenhandlingrequestswesimplyneedtodeterminewhetherornottheURLbeginswithastaticfilepathIfsowecansimplyrespondusinghttpServeFile

Thefollowingisanexample

beegoStaticDir[asset]=static

ThenarequestwithaURLsuchashttpwwwbeegomeassetbootstrapcsswillresultinstaticbootstrapcssbeingservedtotheclient

BootstrapintegrationBootstrapisanopensourceToolkitforfront-enddevelopmentlaunchedbyTwitterFordevelopersBootstrapisoneofthebestfrontendkitsforrapidWebapplicationdevelopmentItisacollectionofHTMLCSSandjavascriptcomponentsusingthelatestHTML5standardsTheseincludearesponsivegridformsbuttonstablesandmanyotherusefulthings

ComponentsBootstrapcontainsawealthofWebcomponentsUsingthesecomponentsyoucanquicklybuildabeautifulfullyfunctionalwebsitewhichincludesthefollowingcomponentsPull-downmenusbuttongroupsbuttondrop-downmenusnavigationnavigationbarsbreadcrumbspaginationlayoutthumbnailswarningdialogsprogressbarsandothermediaobjectsJavaScriptpluginsBootstrapcomeswith13jQueryplug-insforBootstrapcomponentswhichgivesthemlifeTheseincludeModaldialogstabsscrollbarspop-upboxesandsoonBootstrapframeworkcustomizationAllBootstrapcssvariablescanbemodifiedaccordingtoyourneeds

Figure141abootstrapwebsite

NextletsseehowwecanuseBootstrapinsideourBeegoapplicationtoquicklycreateabeautifulwebsite

1 Firstletsdownloadthebootstrapdirectoryintoourprojectsstaticdirectoryasshowninthefollowingscreenshot

Staticfiles

303

Figure142Projectstaticfiledirectorystructure

2 BecauseBeegosetsadefaultvalueforStaticDirifyourstaticfilesdirectoryisstaticthenyouneednotgoanyfurther

StaticDir[static]=static

3 Ourtemplatesusethefollowingassetpaths

cssfile

ltlinkhref=staticcssbootstrapcssrel=stylesheetgt

jsfile

ltscriptsrc=staticjsbootstrap-transitionjsgtltscriptgt

Picturefiles

ltimgsrc=staticimglogopnggt

WiththeabovecodeweareintegratingBootstrapintoourBeegoapplicationThefigurebelowdemonstratestherenderedpage

Figure143websiteintegratedwithBootstrap

ThesetemplatesandformatsallcomeshippedwithBootstrapsowewontrepeatthecompletecodeherehoweveryoucantakealookattheprojectsofficialpagetolearnhowtowriteyourowntemplates

LinksDirectoryPrevioussectionDevelopingawebframeworkNextsectionSessions

Staticfiles

304

142SessionsInchapter6weintroducedsomebasicconceptspertainingtosessionsinGoandweimplementedasessionmanagerTheBeegoframeworkusesthissessionmanagertoimplementsomeconvenientsession-handlingfunctionality

IntegratingsessionsBeegohandlessessionsmainlyaccordingtothefollowingglobalvariables

relatedtosession

SessionOnboolwhetherornottoopenthesessionmoduleDefaultstofalse

SessionProviderstringthedesiredsessionbackendprocessingmoduleDefaultstoanin-memorysessionManager

SessionNamestringthenameoftheclientsavedcookies

SessionGCMaxLifetimeint64cookievalidity

GlobalSessionssessionManagerglobalsessioncontroller

OfcoursethevaluesofthesevariablesshownaboveneedtobeinitializedYoucanalsousethevaluesfromthefollowingconfigurationfilecodetosetthesevalues

ifarerr=AppConfigBool(sessionon)err=nil

SessionOn=false

else

SessionOn=ar

ifar=AppConfigString(sessionprovider)ar==

SessionProvider=memory

else

SessionProvider=ar

ifar=AppConfigString(sessionname)ar==

SessionName=beegosessionID

else

SessionName=ar

ifarerr=AppConfigInt(sessiongcmaxlifetime)err=nilampampar=0

int64val_=strconvParseInt(strconvItoa(ar)1064)

SessionGCMaxLifetime=int64val

else

SessionGCMaxLifetime=3600

AddthefollowingcodeinthebeegoRunfunction

ifSessionOn

GlobalSessions_=sessionNewManager(SessionProviderSessionNameSessionGCMaxLifetime)

goGlobalSessionsGC()

AslongasSessionOnissettotrueitwillopenthesessionbydefaultwithanindependentgoroutinesessionhandler

InordertofacilitateourcustomControllerquicklyusingsessiontheauthorbeegoControllerprovidesthefollowingmethods

ToassistusinquicklyusingsessionsinacustomControllerbeegoControllerprovidesthefollowingmethod

Session

305

func(cController)StartSession()(sesssessionSession)

sess=GlobalSessionsSessionStart(cCtxResponseWritercCtxRequest)

return

UsingsessionsFromthecodeabovewecanseethattheBeegoframeworksimplyinheritsitssessionfunctionalitySohowdoweuseitinourprojects

Firstofallweneedtoopenthesessionattheentrypointofourapplication

beegoSessionOn=true

Wecanthenusethecorrespondingsessionmethodinsideourcontrollerlikeso

func(thisMainController)Get()

varintcountint

sess=thisStartSession()

count=sessGet(count)

ifcount==nil

intcount=0

else

intcount=count(int)

intcount=intcount+1

sessSet(countintcount)

thisData[Username]=astaxie

thisData[Email]=astaxiegmailcom

thisData[Count]=intcount

thisTplNames=indextpl

ThecodeaboveshowshowtousesessionsinthecontrollerlogicTheprocesscanbedividedintotwosteps

1 Gettingsessionobject

GettheobjectsimilarinPHPsession_start()

sess=thisStartSession()

2 Usingthesessionforgeneraloperations

GetthesessionvaluessimilarinPHP$_SESSION[count]

sessGet(count)

Setthesessionvalue

sessSet(countintcount)

AsyoucanseeapplicationsbasedontheBeegoframeworkcaneasilyimplementsessionsTheprocessisverysimilartocallingsession_start()inPHPapplications

LinksDirectoryPrevioussectionStaticfilesNextsectionForms

Session

306

Session

307

143FormsInwebdevelopmentthefollowingworkflowwillprobablylookquitefamiliar

OpenawebpageshowingaformUsersfilloutandsubmittheformIfausersubmitssomeinvalidinformationorhasneglectedtofilloutarequiredfieldtheformwillbereturnedtotheuser(alongwiththefilledindata)withsomedescriptiveinformationabouttheproblemUsersre-filltheinvalidfieldsandcontinueattemptingtosubmittheformuntilitsaccepted

Atthereceivingendthescriptmust

ChecktheusersubmittedformdataVerifywhetherthedataisthecorrecttypeandoftheappropriatestandardForexampleifausernameissubmitteditmustverifythatitcontainsonlyvalidcharactersOtherexampleswouldbecheckingforminimumandmaximumlengthsusernameuniquenessandsoonFilteringdataandcleaningupunsafecharacterstoguaranteethatourapplicationonlyprocessesdatawhichissafeIfnecessarypre-formatthedata(ordatagapsneedtobeclearedthroughtheHTMLcodingandsoon)Preparethedataforinsertionintothedatabase

AlthoughtheprocedureisnotverycomplexitusuallyrequiresalotofboilerplateInadditionwebapplicationsoftenuseavarietyofdifferentcontrolstructurestodisplayerrormessagesonreturnedpagesImplementingformvalidationisasimplebutboringtask

FormsandvalidationFordevelopersthegeneraldevelopmentprocesscanbequitecomplexbutitsmostlyrepetitiveworkSupposeascenarioariseswhereyousuddenlyneedtoaddaformtoyourprojectcausingyoutorewriteallofthelocalcodetiedinwiththeformWeknowthatstructsareaverycommonlyuseddatastructureinGoandBeegousesthemtoitsadvantageforprocessingforminformation

FirstwedefineastructwithfieldscorrespondingtothefieldsinourformelementWecanusestructtagswhichmaptotheformelementasshownbelow

WhendevelopingWebapplicationsfirstdefineastructthatmatchesafieldtoacorrespondingformelementdefinedbyusingastructtagcorrespondingtotheelementinformationandauthenticationinformationasshownbelow

FordevelopersthegeneraldevelopmentprocessisverycomplexandmostlyconsistsofrepeatingthesameworkprocessAssumingascenarioforaprojectwherebyaneedarisestoadddatatoaformthenthelocalcodeoftheentireprocessneedstobemodifiedWeknowinGoastructisacommondatastructuresobeegousesaformstructtoprocessforminformation

Firstdefineastructwithfieldscorrespondingtoourformelementusingstructtagstodefinethecorrespondingformelementandauthenticationinformationlikeso

typeUserstruct

Usernamestring`formtextvalidrequired`

Nicknamestring`formtextvalidrequired`

Ageint`formtextvalidrequired|numeric`

Emailstring`formtextvalidrequired|valid_email`

Introducestring`formtextarea`

Afterdefiningourstructwecanaddthisactioninourcontroller

Form

308

func(thisAddController)Get()

thisData[form]=beegoForm(ampUser)

thisLayout=adminlayouthtml

thisTplNames=adminaddtpl

Theformisdisplayedinourtemplatelikeso

lth1gtNewBlogPostlth1gt

ltformaction=method=postgt

formrender()

ltformgt

AbovewevedefinedtheentirefirststepofdisplayingaformmappedtoastructThenextstepisforuserstofillintheirinformationandsubmittheformafterwhichtheserverwillreceivethedataandverifyitFinallytherecordwillbeinsertedintothedatabase

func(thisAddController)Post()

varuserUser

form=thisGetInput(ampuser)

ifformValidates()

return

modelsUserInsert(ampuser)

thisCtxRedirect(302adminindex)

FormtypeThefollowingtableliststhecorrespondingformelementinformation

lttablecellpadding=0cellspacing=1border=0style=width100class=tablebordergt

lttbodygt

lttrgt

ltthgtNameltthgt

ltthgtparameterltthgt

ltthgtDescriptionltthgt

lttrgt

lttrgt

lttdclass=tdgtltstronggttextltstronggt

lttdgt

lttdclass=tdgtNolttdgt

lttdclass=tdgttextboxinputboxlttdgt

lttrgt

lttrgt

lttdclass=tdgtltstronggtbuttonltstronggt

lttdgt

lttdclass=tdgtNolttdgt

lttdclass=tdgtbuttonlttdgt

lttrgt

lttrgt

lttdclass=tdgtltstronggtcheckboxltstronggt

lttdgt

lttdclass=tdgtNolttdgt

lttdclass=tdgtmulti-selectboxlttdgt

lttrgt

lttrgt

lttdclass=tdgtltstronggtdropdownltstronggt

lttdgt

lttdclass=tdgtNolttdgt

lttdclass=tdgtdrop-downselectionboxlttdgt

Form

309

lttrgt

lttrgt

lttdclass=tdgtltstronggtfileltstronggt

lttdgt

lttdclass=tdgtNolttdgt

lttdclass=tdgtfileuploadlttdgt

lttrgt

lttrgt

lttdclass=tdgtltstronggthiddenltstronggt

lttdgt

lttdclass=tdgtNolttdgt

lttdclass=tdgthiddenelementslttdgt

lttrgt

lttrgt

lttdclass=tdgtltstronggtpasswordltstronggt

lttdgt

lttdclass=tdgtNolttdgt

lttdclass=tdgtpasswordinputboxlttdgt

lttrgt

lttrgt

lttdclass=tdgtltstronggtradioltstronggt

lttdgt

lttdclass=tdgtNolttdgt

lttdclass=tdgtsingleboxlttdgt

lttrgt

lttrgt

lttdclass=tdgtltstronggttextarealtstronggt

lttdgt

lttdclass=tdgtNolttdgt

lttdclass=tdgttextinputboxlttdgt

lttrgt

lttbodygt

lttablegt

FormvalidationThefollowingtablelistssomeformvalidationrulesnativetoBeegothatcanbeused

lttablecellpadding=0cellspacing=1border=0style=width100class=tablebordergt

lttbodygt

lttrgt

ltthgtrulesltthgt

ltthgtparameterltthgt

ltthgtDescriptionltthgt

ltthgtExampleltthgt

lttrgt

lttrgt

lttdclass=tdgtltstronggtrequiredltstronggt

lttdgt

lttdclass=tdgtNolttdgt

lttdclass=tdgtIftheelementisemptyitreturnsFALSElttdgt

lttdclass=tdgtlttdgt

lttrgt

lttrgt

lttdclass=tdgtltstronggtmatchesltstronggt

lttdgt

lttdclass=tdgtYeslttdgt

lttdclass=tdgtiftheformelementsvaluewiththecorrespondingformfieldparametervaluesarenotequalth

enreturn

FALSElttdgt

lttdclass=tdgtmatches[form_item]lttdgt

lttrgt

Form

310

lttrgt

lttdclass=tdgtltstronggtis_uniqueltstronggt

lttdgt

lttdclass=tdgtYeslttdgt

lttdclass=tdgtiftheformelementsvaluewiththespecifiedfieldinatablehasduplicatedataitreturnsF

alse(Translators

NoteForexampleis_unique[UserEmail]thenthevalidationclasswilllookfortheUsertableinthe

Emailfieldthereisnoformelementswiththesamevaluesuchasdepositrepeatitreturnsfalseso

developersdonothavetowriteanotherCallbackverificationcode)lttdgt

lttdclass=tdgtis_unique[tablefield]lttdgt

lttrgt

lttrgt

lttdclass=tdgtltstronggtmin_lengthltstronggt

lttdgt

lttdclass=tdgtYeslttdgt

lttdclass=tdgtformelementvaluesifthecharacterlengthislessthanthenumberofdefinedparametersitre

turnsFALSElttdgt

lttdclass=tdgtmin_length[6]lttdgt

lttrgt

lttrgt

lttdclass=tdgtltstronggtmax_lengthltstronggt

lttdgt

lttdclass=tdgtYeslttdgt

lttdclass=tdgtiftheformelementsvalueisgreaterthanthelengthofthecharacterdefinednumericargument

itreturns

FALSElttdgt

lttdclass=tdgtmax_length[12]lttdgt

lttrgt

lttrgt

lttdclass=tdgtltstronggtexact_lengthltstronggt

lttdgt

lttdclass=tdgtYeslttdgt

lttdclass=tdgtiftheformelementvaluesandparametersdefinedcharacterlengthnumberdoesnotmatchitret

urnsFALSElttdgt

lttdclass=tdgtexact_length[8]lttdgt

lttrgt

lttrgt

lttdclass=tdgtltstronggtgreater_thanltstronggt

lttdgt

lttdclass=tdgtYeslttdgt

lttdclass=tdgtIftheformelementvaluesnon-numerictypesorlessthanthevaluedefinedparametersitret

urnsFALSElttdgt

lttdclass=tdgtgreater_than[8]lttdgt

lttrgt

lttrgt

lttdclass=tdgtltstronggtless_thanltstronggt

lttdgt

lttdclass=tdgtYeslttdgt

lttdclass=tdgtIftheformelementvaluesnon-numerictypesorgreaterthanthevaluedefinedparametersit

returnsFALSElttdgt

lttdclass=tdgtless_than[8]lttdgt

Form

311

lttrgt

lttrgt

lttdclass=tdgtltstronggtalphaltstronggt

lttdgt

lttdclass=tdgtNolttdgt

lttdclass=tdgtIftheformelementvaluecontainscharactersotherthanlettersbesidesitreturnsFALSElttdgt

lttdclass=tdgtlttdgt

lttrgt

lttrgt

lttdclass=tdgtltstronggtalpha_numericltstronggt

lttdgt

lttdclass=tdgtNolttdgt

lttdclass=tdgtIftheformelementvaluescontainedinadditiontolettersandothercharactersotherthannumb

ersitreturns

FALSElttdgt

lttdclass=tdgtlttdgt

lttrgt

lttrgt

lttdclass=tdgtltstronggtalpha_dashltstronggt

lttdgt

lttdclass=tdgtNolttdgt

lttdclass=tdgtIftheformelementvaluecontainsinadditiontotheletternumberunderlinecharactersothe

rthandash

returnsFALSElttdgt

lttdclass=tdgtlttdgt

lttrgt

lttrgt

lttdclass=tdgtltstronggtnumericltstronggt

lttdgt

lttdclass=tdgtNolttdgt

lttdclass=tdgtIftheformelementvaluecontainscharactersotherthannumbersinadditionitreturnsFALSElt

tdgt

lttdclass=tdgtlttdgt

lttrgt

lttrgt

lttdclass=tdgtltstronggtintegerltstronggt

lttdgt

lttdclass=tdgtNolttdgt

lttdclass=tdgtexceptiftheformelementcontainscharactersotherthananintegeritreturnsFALSElttdgt

lttdclass=tdgtlttdgt

lttrgt

lttrgt

lttdclass=tdgtltstronggtdecimalltstronggt

lttdgt

lttdclass=tdgtYeslttdgt

lttdclass=tdgtIftheformelementtype(non-decimal)isnotcompleteitreturnsFALSElttdgt

lttdclass=tdgtlttdgt

lttrgt

lttrgt

lttdclass=tdgtltstronggtis_naturalltstronggt

lttdgt

lttdclass=tdgtNolttdgt

lttdclass=tdgtvalueiftheformelementcontainsanumberofotherunnaturalvalues(othervaluesexcludingz

ero)it

returnsFALSENaturalnumberslikethis0123andsoonlttdgt

lttdclass=tdgtlttdgt

lttrgt

lttrgt

lttdclass=tdgtltstronggtis_natural_no_zeroltstronggt

Form

312

lttdgt

lttdclass=tdgtNolttdgt

lttdclass=tdgtvalueiftheformelementcontainsanumberofotherunnaturalvalues(othervaluesincludingz

ero)it

returnsFALSENonzeronaturalnumbers123andsoonlttdgt

lttdclass=tdgtlttdgt

lttrgt

lttrgt

lttdclass=tdgtltstronggtvalid_emailltstronggt

lttdgt

lttdclass=tdgtNolttdgt

lttdclass=tdgtIftheformelementvaluecontainsinvalidemailaddressitreturnsFALSElttdgt

lttdclass=tdgtlttdgt

lttrgt

lttrgt

lttdclass=tdgtltstronggtvalid_emailsltstronggt

lttdgt

lttdclass=tdgtNolttdgt

lttdclass=tdgtformelementvaluesifanyonevaluecontainsinvalidemailaddress(addressesseparatedbycomm

asinEnglish

)itreturnsFALSElttdgt

lttdclass=tdgtlttdgt

lttrgt

lttrgt

lttdclass=tdgtltstronggtvalid_ipltstronggt

lttdgt

lttdclass=tdgtNolttdgt

lttdclass=tdgtiftheformelementsvalueisnotavalidIPaddressitreturnsFALSElttdgt

lttdclass=tdgtlttdgt

lttrgt

lttrgt

lttdclass=tdgtltstronggtvalid_base64ltstronggt

lttdgt

lttdclass=tdgtNolttdgt

lttdclass=tdgtiftheformelementsvaluecontainsthebase64-encodedcharactersinadditiontootherthanthe

characters

returnsFALSElttdgt

lttdclass=tdgtlttdgt

lttrgt

lttbodygt

lttablegt

LinksDirectoryPrevioussectionSessionsNextsectionUservalidation

Form

313

144UservalidationIntheprocessofdevelopingwebapplicationsuserauthenticationisaproblemwhichdevelopersfrequentlyencounterUserloginregistrationandlogoutamongotheroperationsaswellasgeneralauthenticationcanbedividedintothreeparts

HTTPBasicandHTTPDigestAuthenticationThirdPartyAuthenticationIntegrationQQmicro-bloggingwatercressOPENIDGoogleGitHubFacebookandtwitteretcCustomuserloginregistrationlogoutaregenerallybasedonsessionsandcookieauthentication

BeegodoesnotnativelyprovidesupportforanyofthesethreethingshoweveryoucaneasilymakeuseofexistingthirdpartyopensourcelibrariestoimplementthemThefirsttwoauthenticationsolutionsareonBeegosroadmaptoeventuallybeintegrated

HTTPbasicanddigestauthenticationBothHTTPbasicanddigestauthenticationarerelativelysimpletechniquescommonlyusedbywebapplicationsTherearealreadymanyopensourcethird-partylibrarieswhichsupportthesetwoauthenticationmethodssuchas

githubcomabbotgo-http-auth

ThefollowingcodedemonstrateshowtousethislibrarytoimplementauthenticationinaBeegoapplication

packagecontrollers

import(

githubcomabbotgo-http-auth

githubcomastaxiebeego

)

funcSecret(userrealmstring)string

ifuser==john

passwordishello

return$1$dlPL2MqE$oQmn16q49SqdmhenQuNgs1

return

typeMainControllerstruct

beegoController

func(thisMainController)Prepare()

a=authNewBasicAuthenticator(examplecomSecret)

ifusername=aCheckAuth(thisCtxRequest)username==

aRequireAuth(thisCtxResponseWriterthisCtxRequest)

func(thisMainController)Get()

thisData[Username]=astaxie

thisData[Email]=astaxiegmailcom

thisTplNames=indextpl

TheabovecodetakesadvantageofBeegosprepare()functiontoperformauthenticationbeforeallowingthenormalflowofexecutiontoproceedasyoucanseeitsverysimpletoimplementHTTPauthenticationDigestauthenticationcanbeimplementedinmuchthesameway

Uservalidation

314

OAuthandOAuth2authenticationOAuthandOAuth2arecurrentlytwoofthemostpopularauthenticationmethodsFortunatelytherearethird-partylibrarieswhichimplementthistypeofauthenticationsuchasthegoauthpackageavailableongithub

githubcombradrydzewskigoauth

ThecodebelowdemonstrateshowtousethislibrarytoimplementOAuthauthenticationinBeegousingourGithubcredentials

1 Letsaddsomeroutes

beegoRegisterController(authloginampcontrollersGithubController)

beegoRegisterController(mainpageampcontrollersPageController)

2 ThenwedealwiththeGithubControllerlandingpage

packagecontrollers

import(

githubcomastaxiebeego

githubcombradrydzewskigoauth

)

const(

githubClientKey=a0864ea791ce7e7bd0df

githubSecretKey=a0ec09a647a688a64a28f6190b5a0d2705df56ca

)

typeGithubControllerstruct

beegoController

func(thisGithubController)Get()

settheauthparameters

authConfigCookieSecret=[]byte(7H9xiimk2QdTdYI7rDddfJeV)

authConfigLoginSuccessRedirect=mainpage

authConfigCookieSecure=false

githubHandler=authGithub(githubClientKeygithubSecretKey)

githubHandlerServeHTTP(thisCtxResponseWriterthisCtxRequest)

3 Handlingafterasuccessfullandingpage

Uservalidation

315

packagecontrollers

import(

githubcomastaxiebeego

githubcombradrydzewskigoauth

nethttp

neturl

)

typePageControllerstruct

beegoController

func(thisPageController)Get()

settheauthparameters

authConfigCookieSecret=[]byte(7H9xiimk2QdTdYI7rDddfJeV)

authConfigLoginSuccessRedirect=mainpage

authConfigCookieSecure=false

usererr=authGetUserCookie(thisCtxRequest)

ifnoactiveusersessionthenauthorizeuser

iferr=nil||userId()==

httpRedirect(thisCtxResponseWriterthisCtxRequestauthConfigLoginRedirecthttpStatusSeeOther

)

return

elseaddtheusertotheURLandcontinue

thisCtxRequestURLUser=urlUser(userId())

thisData[pic]=userPicture()

thisData[id]=userId()

thisData[name]=userName()

thisTplNames=hometpl

Thewholeprocessisasfollows

firstopenyourbrowserandentertheaddress

Figure144showsthehomepagewithaloginbutton

Whenclickingonthelinkthefollowingscreenappears

Figure145displayedafterclickingtheloginbuttontoauthenticatewithyourGitHubcredentials

AfterclickingAuthorizeappthefollowingscreenappears

Figure146authorizedGithubinformationgetsdisplayedaftertheloginpage

CustomauthenticationCustomauthenticationisgenerallycombinedwithsessionauthenticationthefollowingcodeisaBeegobasedopensourceblogwhichdemonstratesthis

Loginprocess

func(thisLoginController)Post()

thisTplNames=logintpl

thisCtxRequestParseForm()

username=thisCtxRequestFormGet(username)

Uservalidation

316

password=thisCtxRequestFormGet(password)

md5Password=md5New()

ioWriteString(md5Passwordpassword)

buffer=bytesNewBuffer(nil)

fmtFprintf(bufferxmd5PasswordSum(nil))

newPass=bufferString()

now=timeNow()Format(2006-01-02150405)

userInfo=modelsGetUserInfo(username)

ifuserInfoPassword==newPass

varusersmodelsUser

usersLast_logintime=now

modelsUpdateUserInfo(users)

Setthesessionsuccessfullogin

sess=globalSessionsSessionStart(thisCtxResponseWriterthisCtxRequest)

sessSet(uiduserInfoId)

sessSet(unameuserInfoUsername)

thisCtxRedirect(302)

Registrationprocess

func(thisRegController)Post()

thisTplNames=regtpl

thisCtxRequestParseForm()

username=thisCtxRequestFormGet(username)

password=thisCtxRequestFormGet(password)

usererr=checkUsername(username)

fmtPrintln(usererr)

ifusererr==false

thisData[UsernameErr]=UsernameerrorPleasetoagain

return

passerr=checkPassword(password)

ifpasserr==false

thisData[PasswordErr]=PassworderrorPleasetoagain

return

md5Password=md5New()

ioWriteString(md5Passwordpassword)

buffer=bytesNewBuffer(nil)

fmtFprintf(bufferxmd5PasswordSum(nil))

newPass=bufferString()

now=timeNow()Format(2006-01-02150405)

userInfo=modelsGetUserInfo(username)

ifuserInfoUsername==

varusersmodelsUser

usersUsername=username

usersPassword=newPass

usersCreated=now

usersLast_logintime=now

modelsAddUser(users)

Setthesessionsuccessfullogin

sess=globalSessionsSessionStart(thisCtxResponseWriterthisCtxRequest)

sessSet(uiduserInfoId)

sessSet(unameuserInfoUsername)

thisCtxRedirect(302)

else

thisData[UsernameErr]=Useralreadyexists

Uservalidation

317

funccheckPassword(passwordstring)(bbool)

ifok_=regexpMatchString(^[a-zA-Z0-9]416$password)ok

returnfalse

returntrue

funccheckUsername(usernamestring)(bbool)

ifok_=regexpMatchString(^[a-zA-Z0-9]416$username)ok

returnfalse

returntrue

Onceyouhaveimplementeduserloginandregistrationothermodulescanbeaddedtodeterminewhethertheuserhasbeenloggedinornot

func(thisAddBlogController)Prepare()

sess=globalSessionsSessionStart(thisCtxResponseWriterthisCtxRequest)

sess_uid=sessGet(userid)

sess_username=sessGet(username)

ifsess_uid==nil

thisCtxRedirect(302adminlogin)

return

thisData[Username]=sess_username

LinksDirectoryPrevioussectionFormNextsectionMulti-languagesupport

Uservalidation

318

145Multi-languagesupportInthechapterwhereweintroducedinternationalizationandlocalizationwedevelopedthego-i18nlibraryInthissectionwewillseehowthislibraryisintegratedintotheBeegoframeworkandhowitenablesourBeegoapplicationstosupportbothinternationalizationandlocalization

I18nintegrationBeegofirstsetssomeglobalvariables

Translationi18nIL

Langstringsetthelanguagepackzhen

LangPathstringsetthelanguagepacklocation

Amulti-languageinitializationfunctionisdefined

funcInitLang()

beegoTranslation=i18nNewLocale()

beegoTranslationLoadPath(beegoLangPath)

beegoTranslationSetLocale(beegoLang)

Inordertofacilitatemulti-languagecallsinthetemplatepackagedirectlywedesignedthreefunctionsforhandlingmulti-languageresponses

Multi-languagesupport

319

beegoTplFuncMap[Trans]=i18nI18nT

beegoTplFuncMap[TransDate]=i18nI18nTimeDate

beegoTplFuncMap[TransMoney]=i18nI18nMoney

funcI18nT(argsinterface)string

ok=false

varsstring

iflen(args)==1

sok=args[0](string)

ifok

s=fmtSprint(args)

returnbeegoTranslationTranslate(s)

funcI18nTimeDate(argsinterface)string

ok=false

varsstring

iflen(args)==1

sok=args[0](string)

ifok

s=fmtSprint(args)

returnbeegoTranslationTime(s)

funcI18nMoney(argsinterface)string

ok=false

varsstring

iflen(args)==1

sok=args[0](string)

ifok

s=fmtSprint(args)

returnbeegoTranslationMoney(s)

Multi-languagedevelopment1 Settingthelanguageandlocationofthelanguagepacktheninitializei18nobjects

beegoLang=zh

beegoLangPath=viewslang

beegoInitLang()

2 Designingamulti-languagepackage

Abovewetalkedabouthowtoinitializeamulti-languagepackageNowletslookathowtodesignoneMulti-languagepackagesaretypicallyJSONfilesasyouvealreadyseeninChapter10WemustprovidetranslationfilesforlanguageswewishtosupportonourLangPathsuchasthefollowing

Multi-languagesupport

320

zhjson

zh

submit提交

create创建

enjson

en

submitSubmit

createCreate

3 Usinglanguagepackages

Wecancallthecontrollertogetthetranslatedresponseinthedesiredlanguagelikeso

func(thisMainController)Get()

thisData[create]=beegoTranslationTranslate(create)

thisTplNames=indextpl

Wecanalsodirectlyinterpolatetranslatedresponsesinourtemplates

DirectTexttranslation

create|Trans

Timetotranslate

time|TransDate

Currencytranslation

money|TransMoney

LinksDirectoryPrevioussectionUservalidationNextsectionpprof

Multi-languagesupport

321

146pprofAgreatfeatureofGosstandardlibraryisitscodeperformancemonitoringtoolsThesepackagesexistintwoplaces

nethttppprof

runtimepprof

InfactnethttppprofsimplyexposesruntimeprofilingdatafromtheruntimepprofpackageonanHTTPport

pprofsupportinBeegoTheBeegoframeworkcurrentlysupportspprofhoweveritisnotturnedonbydefaultIfyouneedtotesttheperformanceofyourapplication(forinstancebyviewingtheexecutiongoroutine)suchinformationfromGosdefaultpackagenethttppprofalreadyhasthisfeatureBecausebeegohasrepackagedtheServHTTPfunctionyoucannotopenthedefaultfeatureincludedinpprofThisresultedinbeegosupportingpprofinternally

FirstinourbeegoRunfunctionwechoosewhetherornottoautomaticallyloadtheperformancepackaccordingtoourconfigurationvariable(inthiscasePprofOn)

ifPprofOn

BeeAppRegisterController(`debugpprof`ampProfController)

BeeAppRegisterController(`debugpprofpp([w]+)`ampProfController)

DesigningProfController

packagebeego

import(

nethttppprof

)

typeProfControllerstruct

Controller

func(thisProfController)Get()

switchthisCtxParams[pp]

default

pprofIndex(thisCtxResponseWriterthisCtxRequest)

case

pprofIndex(thisCtxResponseWriterthisCtxRequest)

casecmdline

pprofCmdline(thisCtxResponseWriterthisCtxRequest)

caseprofile

pprofProfile(thisCtxResponseWriterthisCtxRequest)

casesymbol

pprofSymbol(thisCtxResponseWriterthisCtxRequest)

thisCtxResponseWriterWriteHeader(200)

GettingstartedFromtheabovewecanseethatenablingpprofisassimpleassettingthePprofOnconfigurationvariabletotrue

pprof

322

beegoPprofOn=true

YoucanthenopenthefollowingURLinyourbrowsertoseethefollowinginterface

Figure147currentsystemgoroutineheapthreadinformation

Byclickingonagoroutinewecanseealotofdetailedinformation

Figure148showsthecurrentgoroutinedetails

Ofcoursewecanalsogetmoredetailsfromthecommandline

gotoolpprofhttplocalhost8080debugpprofprofile

Thistimetheprogramwillbeginprofilingtheapplicationforaperiodof30secondsduringwhichtimeitwillrepeatedlyrefreshthepageinthebrowserinanattempttogatherCPUusageandperformancedata

(pprof)top10

Total3samples

13333331333MHeap_AllocLocked

13336671333osexec(Cmd)closeDescriptors

133310001333runtimesigprocmask

00010001333MCentral_Grow

00010002667mainCompile

00010002667maincompile

00010002667mainrun

00010001333makeslice1

00010002667nethttp(ServeMux)ServeHTTP

00010002667nethttp(conn)serve

(pprof)web

Figure149showstheexecutionflowofinformation

LinksDirectoryPrevioussectionMulti-languagesupportNextsectionSummary

pprof

323

147SummaryThischapterillustratessomewaysinwhichtheBeegoframeworkcanbeextendedWefirstlookedatstaticfilesupportlearninghowBeegohandlesservingstaticfilesinternallyWesawhowthisfunctionalityallowedustoeasilyintegratestaticassets(suchasBootstrapsCSSfiles)forrapidandgreatlookingwebsitedevelopmentNextwesawhowtointegratesessionManagertopainlesslyfacilitateusersessionsinBeegoWethendescribedformmanagementandvalidationleveragingGosstructstoreducecoderepetitionandforsimplifyingfieldvalidationAfterthatwediscusseduserauthenticationwhichinvolvedthreemainstrategiesHTTPauthentication(basicanddigest)thirdpartyauthenticationandcustomauthenticationWelearnedaboutsomeexistingthirdpartyauthenticationpackagesthathavealreadyimplementedthesestrategieswhichareconvenientlyaccommodatedbyBeegoThenextsectionre-introducedlanguagesupportinBeegowesawhowtointegratethego-i18npackageandlearnedhowtoeasilyloadmultiplelanguagepacksintoourapplicationsasneededLastlywediscussedhowtoworkwithGospprofpackagesinBeegoThepprofpackageisusedforperformanceprofilinginGoandBeegorepackagesitsoitcanservethesamepurposeinBeegoapplicationswithoutmuchadditionalworkThroughthesesixsectionsweveextendedBeegowithmanyfeaturesmakingitintoaversatileframeworksuitablefortherequirementsofmanywebapplicationsUsershavethefreedomofextendingtheframeworktosuittheirindividualneedsthisbriefintroductiontoBeegosimplyoffersasmalltasteofwhatcanbedone

LinksDirectoryPrevioussectionpprofNextchapterAppendixAReferences

Summary

324

AppendixAReferencesThisbookisasummaryofmyGoexperiencesomecontentarefromotherGopherseitherblogsorsitesThankstothem

1 golangblog2 RussCoxsblog3 gobook4 golangtutorials5 轩脉刃de刀光剑影

6 GoProgrammingLanguage7 NetworkprogrammingwithGo8 setup-the-rails-application-for-internationalization9 TheCross-SiteScripting(XSS)FAQ

References

325

1Goenvironmentconfiguration11Installation12$GOPATHandworkspace13Gocommands14Godevelopmenttools15Summary

2Gobasicknowledge21HelloGo22Gofoundation23Controlstatementsandfunctions24struct25Object-oriented26interface27Concurrency28Summary

3Webfoundation31Webworkingprinciples32Buildasimplewebserver33HowGoworkswithweb34Getintohttppackage35Summary

4Userform41Processforminputs42Verificationofinputs43Crosssitescripting44Duplicatesubmissions45Fileupload46Summary

5Database51databasesqlinterface52MySQL53SQLite54PostgreSQL55DevelopORMbasedonbeedb56NoSQLdatabase57Summary

6Datastorageandsession61Sessionandcookies62HowtousesessioninGo63Sessionstorage64Preventhijackofsession65Summary

7Textfiles71XML72JSON73Regexp74Templates75Files76Strings77Summary

8Webservices81Sockets82WebSocket

preface

326

83REST84RPC85Summary

9Securityandencryption91CSRFattacks92Filterinputs93XSSattacks94SQLinjection95Passwordstorage96Encryptanddecryptdata97Summary

10Internationalizationandlocalization101Timezone102Localizedresources103Internationalsites104Summary

11Errorhandlingdebuggingandtesting111Errorhandling112DebuggingbyusingGDB113Writetestcases114Summary

12Deploymentandmaintenance121Logs122Errorsandcrashes123Deployment124Backupandrecovery125Summary

13Buildawebframework131Projectprogram132Customizedrouters133Designcontrollers134Logsandconfigurations135Adddeleteandupdateblogs136Summary

14Developwebframework141Staticfiles142Session143Form144Uservalidation145Multi-languagesupport146pprof147Summary

AppendixAReferences

preface

327

  • Introduction
  • Go Environment Configuration
    • Installation
    • $GOPATH and workspace
    • Go commands
    • Go development tools
    • Summary
      • Go basic knowledge
        • Hello Go
        • Go foundation
        • Control statements and functions
        • struct
        • Object-oriented
        • interface
        • Concurrency
        • Summary
          • Web foundation
            • Web working principles
            • Build a simple web server
            • How Go works with web
            • Get into http package
            • Summary
              • HTTP Form
                • Process form inputs
                • Validation of inputs
                • Cross site scripting
                • Duplicate submissions
                • File upload
                • Summary
                  • Database
                    • databasesql interface
                    • How to use MySQL
                    • How to use SQLite
                    • How to use PostgreSQL
                    • How to use beedb ORM
                    • NOSQL
                    • Summary
                      • Data storage and session
                        • Session and cookies
                        • How to use session in Go
                        • Session storage
                        • Prevent hijack of session
                        • Summary
                          • Text files
                            • XML
                            • JSON
                            • Regexp
                            • Templates
                            • Files
                            • Strings
                            • Summary
                              • Web services
                                • Sockets
                                • WebSocket
                                • REST
                                • RPC
                                • Summary
                                  • Security and encryption
                                    • CSRF attacks
                                    • Filter inputs
                                    • XSS attacks
                                    • SQL injection
                                    • Password storage
                                    • Encrypt and decrypt data
                                    • Summary
                                      • Internationalization and localization
                                        • Time zone
                                        • Localized resources
                                        • International sites
                                        • Summary
                                          • Error handling debugging and testing
                                            • Error handling
                                            • Debugging by using GDB
                                            • Write test cases
                                            • Summary
                                              • Deployment and maintenance
                                                • Logs
                                                • Errors and crashes
                                                • Deployment
                                                • Backup and recovery
                                                • Summary
                                                  • Build a web framework
                                                    • Project program
                                                    • Customized routers
                                                    • Design controllers
                                                    • Logs and configurations
                                                    • Add delete and update blogs
                                                    • Summary
                                                      • Develop web framework
                                                        • Static files
                                                        • Session
                                                        • Form
                                                        • User validation
                                                        • Multi-language support
                                                        • pprof
                                                        • Summary
                                                          • References
                                                          • preface
Page 2: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write

172

173

174

175

18

181

182

183

184

185

186

187

19

191

192

193

194

195

110

1101

1102

1103

1104

1105

1106

1107

111

1111

1112

1113

1114

112

1121

1122

1123

1124

113

1131

1132

1133

1134

1135

HowtousesessioninGo

Sessionstorage

Preventhijackofsession

Summary

Textfiles

XML

JSON

Regexp

Templates

Files

Strings

Summary

Webservices

Sockets

WebSocket

REST

RPC

Summary

Securityandencryption

CSRFattacks

Filterinputs

XSSattacks

SQLinjection

Passwordstorage

Encryptanddecryptdata

Summary

Internationalizationandlocalization

Timezone

Localizedresources

Internationalsites

Summary

Errorhandlingdebuggingandtesting

Errorhandling

DebuggingbyusingGDB

Writetestcases

Summary

Deploymentandmaintenance

Logs

Errorsandcrashes

Deployment

Backupandrecovery

Summary

3

114

1141

1142

1143

1144

1145

1146

115

1151

1152

1153

1154

1155

1156

1157

116

117

Buildawebframework

Projectprogram

Customizedrouters

Designcontrollers

Logsandconfigurations

Adddeleteandupdateblogs

Summary

Developwebframework

Staticfiles

Session

Form

Uservalidation

Multi-languagesupport

pprof

Summary

References

preface

4

BuildWebApplicationwithGolangPurpose

BecauseIminterestedinwebapplicationdevelopmentIusedmyfreetimetowritethisbookasanopensourceversionItdoesntmeanthatIhaveaverygoodabilitytobuildwebapplicationsIwouldliketosharewhatIvedonewithGoinbuildingwebapplications

ForthoseofyouwhoareworkingwithPHPPythonRubyyouwilllearnhowtobuildawebapplicationwithGoForthoseofyouwhoareworkingwithCC++youwillknowhowthewebworks

IbelievethepurposeofstudyingissharingwithothersThehappiestthinginmylifeissharingeverythingIveknownwithmorepeople

Donate

AliPay

alipay

EnglishDonatedonate

CommunityQQ群386056972

BBShttpgocnio

Acknowledgments四月份平民AprilCitizen(reviewcode)洪瑞琦HongRuiqi(reviewcode)边疆BianJiang(writetheconfigurationsaboutVimandEmacsforGodevelopment)欧林猫OlingCat(reviewcode)吴文磊WenleiWu(providesomepictures)北极星Polaris(reviewwholebook)雨痕RainTrail(reviewchapter2and3)

LicenseThisbookislicensedundertheCCBY-SA30LicensethecodeislicensedunderaBSD3-ClauseLicenseunlessotherwisespecified

GetStarted

Index

Introduction

5

Introduction

6

1GoEnvironmentConfigurationWelcometotheworldofGoletsstartexploring

Goisafast-compiledgarbage-collectedconcurrentsystemsprogramminglanguageIthasthefollowingadvantages

CompilesalargeprojectwithinafewsecondsProvidesasoftwaredevelopmentmodelthatiseasytoreasonaboutavoidingmostoftheproblemsassociatedwithC-styleheaderfilesIsastaticlanguagethatdoesnothavelevelsinitstypesystemsousersdonotneedtospendmuchtimedealingwithrelationsbetweentypesItismorelikealightweightobject-orientedlanguagePerformsgarbagecollectionItprovidesbasicsupportforconcurrencyandcommunicationDesignedformulti-corecomputers

GoisacompiledlanguageItcombinesthedevelopmentefficiencyofinterpretedordynamiclanguageswiththesecurityofstaticlanguagesItisgoingtobethelanguageofchoiceformodernmulti-corecomputerswithnetworkingForthesepurposestherearesomeproblemsthatneedtoinherentlyberesolvedatthelevelofthelanguageofchoicesuchasarichlyexpressivelightweighttypesystemanativeconcurrencymodelandstrictlyregulatedgarbagecollectionForquitesometimenopackagesortoolshaveemergedthathaveaimedtosolvealloftheseproblemsinapragmaticfashionthuswasbornthemotivationfortheGolanguage

InthischapterIwillshowyouhowtoinstallandconfigureyourownGodevelopmentenvironment

LinksDirectoryNextsectionInstallation

GoEnvironmentConfiguration

7

11Installation

ThreewaystoinstallGoTherearemanywaystoconfiguretheGodevelopmentenvironmentonyourcomputerandyoucanchoosewhicheveroneyoulikeThethreemostcommonwaysareasfollows

OfficialinstallationpackagesTheGoteamprovidesconvenientinstallationpackagesinWindowsLinuxMacandotheroperatingsystemsThisisprobablytheeasiestwaytogetstartedYoucangettheinstallersfromtheGolangDownloadPage

InstallityourselffromsourcecodePopularwithdeveloperswhoarefamiliarwithUnix-likesystems

Usingthird-partytoolsTherearemanythird-partytoolsandpackagemanagersforinstallingGolikeapt-getinUbuntuandhomebrewforMac

IncaseyouwanttoinstallmorethanoneversionofGoonacomputeryoushouldtakealookatatoolcalledGVMItisthebesttoolIveseensofarforaccomplishingthistaskotherwiseyoudhavetodealwithityourself

InstallfromsourcecodeTocompileGo15andupwardsyouonlyneedthepreviousversionofGoasGohasachievedbootstrappingYouonlyneedGotocompileGo

TocompileGo14downwardsyouwillneedaCcompilerassomepartsofGoarestillwritteninPlan9CandATampTassembler

OnaMacifyouhaveinstalledXcodeyoualreadyhavethecompiler

OnUnix-likesystemsyouneedtoinstallgccorasimilarcompilerForexampleusingthepackagemanagerapt-get(includedwithUbuntu)onecaninstalltherequiredcompilersasfollows

sudoapt-getinstallgcclibc6-dev

OnWindowsyouneedtoinstallMinGWinordertoinstallgccDontforgettoconfigureyourenvironmentvariablesaftertheinstallationhascompleted(EverythingthatlookslikethismeansitscommentedbyatranslatorIfyouareusing64-bitWindowsyoushouldinstallthe64-bitversionofMinGW)

AtthispointexecutethefollowingcommandstoclonetheGosourcecodeandcompileit(ItwillclonethesourcecodetoyourcurrentdirectorySwitchyourworkpathbeforeyoucontinueThismaytakesometime)

gitclonehttpsgogooglesourcecomgo

cdgosrc

allbash

AsuccessfulinstallationwillendwiththemessageALLTESTSPASSED

OnWindowsyoucanachievethesamebyrunningallbat

IfyouareusingWindowstheinstallationpackagewillsetyourenvironmentvariablesautomaticallyInUnix-likesystemsyouneedtosetthesevariablesmanuallyasfollows(IfyourGoversionisgreaterthan10youdonthavetoset$GOBINanditwillautomaticallyberelatedtoyour$GOROOTbinwhichwewilltalkaboutinthenextsection)

Installation

8

exportGOROOT=$HOMEgo

exportGOBIN=$GOROOTbin

exportPATH=$PATH$GOROOTbin

Ifyouseethefollowinginformationonyourscreenyoureallset

Figure11Informationafterinstallingfromsourcecode

OnceyouseetheusageinformationofGoitmeansyouhavesuccessfullyinstalledGoonyourcomputerIfitsaysnosuchcommandcheckthatyour$PATHenvironmentvariablecontainstheinstallationpathofGo

UsingthestandardinstallationpackagesGohasone-clickinstallationpackagesforeverysupportedoperatingsystemThesepackageswillinstallGoinusrlocalgo(cGoinWindows)bydefaultOfcoursethiscanbemodifiedbutyoualsoneedtochangealltheenvironmentvariablesmanuallyasIveshownabove

Howtocheckifyouroperatingsystemis32-bitor64-bit

Ournextstepdependsonyouroperatingsystemtypesowehavetocheckitbeforewedownloadthestandardinstallationpackages

IfyouareusingWindowspressWin+RandthenrunthecommandtoolTypethesysteminfocommandanditwillshowyousomeusefulsysteminformationFindthelinethatsayssystemtype-ifyouseex64-basedPCthatmeansyouroperatingsystemis64-bit32-bitotherwise

Istronglyrecommenddownloadingthe64-bitpackageifyouareaMacuserasGonolongersupportspure32-bitprocessorsonMacOSX

Linuxuserscantypeuname-aintheterminaltoseesysteminformationA64-bitoperatingsystemwillshowthefollowing

ltsomedescriptiongtx86_64x86_64x86_64GNULinux

somemachinessuchasUbuntu1004willshowasfollowing

x86_64GNULinux

32-bitoperatingsystemsinsteadshow

ltsomedescriptiongti686i686i386GNULinux

Mac

Gotothedownloadpagechoosego142darwin-386pkg(Thelaterversionhasno32-bitdownload)for32-bitsystemsandgo183darwin-amd64pkgfor64-bitsystemsGoingallthewaytotheendbyclickingnext~gobinwillbeaddedtoyoursystems$PATHafteryoufinishtheinstallationNowopentheterminalandtypegoYoushouldseethesameoutputshowninfigure11

Linux

Gotothedownloadpagechoosego183linux-386targzfor32-bitsystemsandgo183linux-amd64targzfor64-bitsystemsSupposeyouwanttoinstallGointhe$GO_INSTALL_DIRpathUncompressthetargztoyourchosenpathusingthecommandtarzxvfgo183linux-amd64targz-C$GO_INSTALL_DIRThensetyour$PATHwiththefollowingexportPATH=$PATH$GO_INSTALL_DIRgobinNowjustopentheterminalandtypegoYoushouldnowseethesameoutputdisplayedinfigure11

Installation

9

Windows

Gotothedownloadpagechoosego183windows-386msifor32-bitsystemsandgo183windows-amd64msifor64-bitsystemsGoingallthewaytotheendbyclickingnextcgobinwillbeaddedtopathNowjustopenacommandlinewindowandtypegoYoushouldnowseethesameoutputdisplayedinfigure11

Usethird-partytools

GVM

GVMisaGomulti-versioncontroltooldevelopedbyathird-partylikervmforrubyItsquiteeasytouseInstallgvmbytypingthefollowingcommandsinyourterminal

bashltlt(curl-s-S-Lhttpsrawgithubcommoovwebgvmmasterbinscriptsgvm-installer)

ThenweinstallGousingthefollowingcommands

gvminstallgo183

gvmusego183

Aftertheprocesshasfinishedyoureallset

apt-get

UbuntuisthemostpopulardesktopreleaseversionofLinuxItusesapt-gettomanagepackagesWecaninstallGousingthefollowingcommands

sudoadd-apt-repositoryppagophersgo

sudoapt-getupdate

sudoapt-getinstallgolang-go

wget

wgethttpsstoragegoogleapiscomgolanggo183linux-amd64targz

sudotar-xzfgo183linux-amd64targz-Cusrlocal

Goenvironment

exportGOROOT=usrlocalgo

exportGOBIN=$GOROOTbin

exportPATH=$PATH$GOBIN

exportGOPATH=$HOMEgopath

Startingfromgo18TheGOPATHenvironmentvariablenowhasadefaultvalueifitisunsetItdefaultsto$HOMEgoonUnixandUSERPROFILEgoonWindows

HomebrewHomebrewisasoftwaremanagementtoolcommonlyusedinMactomanagepackagesJusttypethefollowingcommandstoinstallGo

1 InstallHomebrew

usrbinruby-e$(curl-fsSLhttpsrawgithubusercontentcomHomebrewinstallmasterinstall)

Installation

10

1 InstallGo

brewupdateampampbrewupgrade

brewinstallgo

LinksDirectoryPrevioussectionGoenvironmentconfigurationNextsection$GOPATHandworkspace

Installation

11

12$GOPATHandworkspace

$GOPATHGotakesauniqueapproachtomanagethecodefileswiththeintroductionofa$GOPATHdirectorywhichcontainsallthegocodeinthemachineNotethatthisisdifferentfromthe$GOROOTenvironmentvariablewhichstateswheregoisinstalledonthemachineWehavetodefinethe$GOPATHvariablebeforeusingthelanguageinnixsystemsthereisafilecalledprofileweneedtoappendthebelowexportstatementtothefileTheconceptbehindgopathisanovelonewherewecanlinktoanygocodeatanyinstantoftimewithoutambiguity

Startingfromgo18theGOPATHenvironmentvariablenowhasadefaultvalueifitisunsetItdefaultsto$HOMEgoonUnixandUSERPROFILEgoonWindows

InUnix-likesystemsthevariableshouldbeusedlikethis

exportGOPATH=$HOMEmygo

InWindowsyouneedtocreateanewenvironmentvariablecalledGOPATHthensetitsvaluetocmygo(Thisvaluedependsonwhereyourworkspaceislocated)

ItsOKtohavemorethanonepath(workspace)in$GOPATHbutrememberthatyouhavetouse(inWindows)tobreakthemupAtthispointgogetwillsavethecontenttoyourfirstpathin$GOPATHItishighlyrecommendedtonothavemultiplesversionstheworstcaseistocreateafolderbythenameofyourprojectrightinside$GOPATHitbreakseverythingthatthecreatorswerewishingtochangeinprogrammingwiththecreationofgolanguagebecausewhenyoucreateafolderinside$GOPATHyouwillreferenceyourpackagesasdirectlyasandthisbreaksalltheapplicationswhichwillimportyourpackagebecausethegogetwontfindyourpackagePleasefollowconventionsthereisareasonconventionsarecreated

In$GOPATHyoumusthavethreefoldersasfollows

srcforsourcefileswhosesuffixisgocgspkgforcompiledfileswhosesuffixisabinforexecutablefiles

InthisbookIusemygoasmyonlypathin$GOPATH

PackagedirectoryCreatepackagesourcefilesandfolderslike$GOPATHsrcmymathsqrtgo(mymathisthepackagename)(Authorusesmymathashispackagenameandthesamenameforthefolderthatcontainsthepackagesourcefiles)

EverytimeyoucreateapackageyoushouldcreateanewfolderinthesrcdirectorywiththenotableexceptionofmainforwhichmainfoldercreationisoptionalFoldernamesareusuallythesameasthepackagethatyouaregoingtouseYoucanhavemulti-leveldirectoriesifyouwanttoForexampleifyoucreatethedirectory$GOPATHsrcgithubcomastaxiebeedbthenthepackagepathwouldbegithubcomastaxiebeedbThepackagenamewillbethelastdirectoryinyourpathwhichisbeedbinthiscase

Executefollowingcommands(Nowauthorgoesbacktotalkexamples)

cd$GOPATHsrc

mkdirmymath

Createanewfilecalledsqrtgotypethefollowingcontenttoyourfile

$GOPATHandworkspace

12

Sourcecodeof$GOPATHsrcmymathsqrtgo

packagemymath

funcSqrt(xfloat64)float64

z=00

fori=0ilt1000i++

z-=(zz-x)(2x)

returnz

NowmypackagedirectoryhasbeencreatedanditscodehasbeenwrittenIrecommendthatyouusethesamenameforyourpackagesastheircorrespondingdirectoriesandthatthedirectoriescontainallofthepackagesourcefiles

CompilepackagesWevealreadycreatedourpackageabovebuthowdowecompileitforpracticalpurposesTherearetwowaystodothis

1 Switchyourworkpathtothedirectoryofyourpackagethenexecutethegoinstallcommand2 Executetheabovecommandexceptwithafilenamelikegoinstallmymath

Aftercompilingwecanopenthefollowingfolder

cd$GOPATHpkg$GOOS_$GOARCH

youcanseethefilewasgenerated

mymatha

ThefilewhosesuffixisaisthebinaryfileofourpackageHowdoweuseit

Obviouslyweneedtocreateanewapplicationtouseit

Createanewapplicationpackagecalledmathapp

cd$GOPATHsrc

mkdirmathapp

cdmathapp

vimmaingo

Writethefollowingcontenttomaingo

$GOPATHsrcmathappmaingosourcecode

packagemain

import(

mymath

fmt

)

funcmain()

fmtPrintf(HelloworldSqrt(2)=vnmymathSqrt(2))

Tocompilethisapplicationyouneedtoswitchtotheapplicationdirectorywhichinthiscaseis$GOPATHsrcmathappthenexecutethegoinstallcommandNowyoushouldseeanexecutablefilecalledmathappwasgeneratedinthedirectory$GOPATHbinTorunthisprogramusethemathappcommandYoushouldseethefollowingcontentinyourterminal

HelloworldSqrt(2)=1414213562373095

$GOPATHandworkspace

13

InstallremotepackagesGohasatoolforinstallingremotepackageswhichisacommandcalledgogetItsupportsmostopensourcecommunitiesincludingGithubGoogleCodeBitBucketandLaunchpad

gogetgithubcomastaxiebeedb

Youcanusegoget-uhelliptoupdateyourremotepackagesanditwillautomaticallyinstallallthedependentpackagesaswell

ThistoolwillusedifferentversioncontroltoolsfordifferentopensourceplatformsForexamplegitforGithubandhgforGoogleCodeThereforeyouhavetoinstalltheseversioncontroltoolsbeforeyouusegoget

Afterexecutingtheabovecommandsthedirectorystructureshouldlooklikefollowing

$GOPATH

src

|-githubcom

|-astaxie

|-beedb

pkg

|--$GOOS_$GOARCH

|-githubcom

|-astaxie

|-beedba

Actuallygogetclonessourcecodetothe$GOPATHsrcofthelocalfilesystemthenexecutesgoinstall

Youcanuseremotepackagesinthesamewaythatweuselocalpackages

importgithubcomastaxiebeedb

DirectorycompletestructureIfyouvefollowedalloftheabovestepsyourdirectorystructureshouldnowlooklikethefollowing

bin

mathapp

pkg

$GOOS_$GOARCHsuchasdarwin_amd64linux_amd64

mymatha

githubcom

astaxie

beedba

src

mathapp

maingo

mymath

sqrtgo

githubcom

astaxie

beedb

beedbgo

utilgo

Nowyouareabletoseethedirectorystructureclearlybincontainsexecutablefilespkgcontainscompiledfilesandsrccontainspackagesourcefiles

(TheformatofenvironmentvariablesinWindowsisGOPATHhoweverthisbookmainlyfollowstheUnix-stylesoWindowsusersneedtoreplacetheseyourself)

$GOPATHandworkspace

14

LinksDirectoryPrevioussectionInstallationNextsectionGocommands

$GOPATHandworkspace

15

13Gocommands

GocommandsTheGolanguagecomeswithacompletesetofcommandoperationtoolsYoucanexecutethegocommandontheterminaltoseethem

Figure13Gocommanddisplaysdetailedinformation

TheseareallusefulforusLetsseehowtousesomeofthem

gobuildThiscommandisforcompilingtestsItwillcompilepackagesanddependenciesifitsnecessary

Ifthepackageisnotthemainpackagesuchasmymathinsection12nothingwillbegeneratedafteryouexecutegobuildIfyouneedthepackagefileain$GOPATHpkgusegoinstallinsteadIfthepackageisthemainpackageitwillgenerateanexecutablefileinthesamefolderIfyouwantthefiletobegeneratedin$GOPATHbinusegoinstallorgobuild-o$PATH_HEREaexeIftherearemanyfilesinthefolderbutyoujustwanttocompileoneofthemyoushouldappendthefilenameaftergobuildForexamplegobuildagogobuildwillcompileallthefilesinthefolderYoucanalsoassignthenameofthefilethatwillbegeneratedForinstanceinthemathappproject(insection12)usinggobuild-oastaxieexewillgenerateastaxieexeinsteadofmathappexeThedefaultnameisyourfoldername(non-mainpackage)orthefirstsourcefilename(mainpackage)

(AccordingtoTheGoProgrammingLanguageSpecificationpackagenamesshouldbethenameafterthewordpackageinthefirstlineofyoursourcefilesItdoesnthavetobethesameasthefoldernameandtheexecutablefilenamewillbeyourfoldernamebydefault)

gobuildignoresfileswhosenamesstartwith_orIfyouwanttohavedifferentsourcefilesforeveryoperatingsystemyoucannamefileswiththesystemnameasasuffixSupposetherearesomesourcefilesforloadingarraysTheycouldbenamedasfollows

array_linuxgo|array_darwingo|array_windowsgo|array_freebsdgo

gobuildchoosestheonethatsassociatedwithyouroperatingsystemForexampleitonlycompilesarray_linuxgoinLinuxsystemsandignoresalltheothers

gocleanThiscommandisforcleaningfilesthataregeneratedbycompilersincludingthefollowingfiles

_objolddirectoryofobjectleftbyMakefiles

_testolddirectoryoftestleftbyMakefiles

_testmaingoolddirectoryofgotestleftbyMakefiles

testoutolddirectoryoftestleftbyMakefiles

buildoutolddirectoryoftestleftbyMakefiles

[568ao]objectfilesleftbyMakefiles

DIR(exe)generatedbygobuild

DIRtest(exe)generatedbygotest-c

MAINFILE(exe)generatedbygobuildMAINFILEgo

Gocommands

16

IusuallyusethiscommandtocleanupmyfilesbeforeIuploadmyprojecttoGithubTheseareusefulforlocaltestsbutuselessforversioncontrol

gofmtandgofmtThepeoplewhoareworkingwithCC++shouldknowthatpeoplearealwaysarguingaboutwhichcodestyleisbetterKampR-styleorANSI-styleHoweverinGothereisonlyonecodestylewhichisenforcedForexampleleftbracesmustonlybeinsertedattheendoflinesandtheycannotbeontheirownlinesotherwiseyouwillgetcompileerrorsFortunatelyyoudonthavetoremembertheserulesgofmtdoesthisjobforyouJustexecutethecommandgofmtltFilenamegtgointerminalIdontusethiscommandverymuchbecauseIDEsusuallyexecutethiscommandautomaticallywhenyousavesourcefilesIwilltalkmoreaboutIDEsinthenextsection

gofmtisjustanaliaswhichrunsthecommandgofmt-l-wonthepackagesnamedbytheimportpaths

Weusuallyusegofmt-winsteadofgofmtThelatterwillnotrewriteyoursourcefilesafterformattingcodegofmt-wsrcformatsthewholeproject

gogetThiscommandisforgettingremotepackagesSofaritsupportsBitBucketGithubGoogleCodeandLaunchpadThereareactuallytwothingsthathappenafterweexecutethiscommandThefirstthingisthatGodownloadsthesourcecodethenexecutesgoinstallBeforeyouusethiscommandmakesureyouhaveinstalledalloftherelatedtools

BitBucket(MercurialGit)

Github(git)

GoogleCode(GitMercurialSubversion)

Launchpad(Bazaar)

InordertousethiscommandyouhavetoinstallthesetoolscorrectlyDontforgettoupdatethe$PATHvariableBythewayitalsosupportscustomizeddomainnamesUsegohelpimportpathformoredetailsaboutthis

goinstallThiscommandcompilesallpackagesandgeneratesfilesthenmovesthemto$GOPATHpkgor$GOPATHbin

gotestThiscommandloadsallfileswhosenameinclude_testgoandgeneratestestfilesthenprintsinformationthatlookslikethefollowing

okarchivetar0011s

FAILarchivezip0022s

okcompressgzip0033s

IttestsallyourtestfilesbydefaultUsecommandgohelptestflagformoredetails

godocManypeoplesaythatwedontneedanythird-partydocumentationforprogramminginGo(actuallyIvemadeaCHMalready)Gohasapowerfultooltomanagedocumentationnatively

Gocommands

17

SohowdowelookuppackageinformationindocumentationForinstanceifyouwanttogetmoredetailsaboutthebuiltinpackageusethegodocbuiltincommandSimilarlyusethegodocnethttpcommandtolookupthehttppackagedocumentationIfyouwanttoseemoredetailsaboutspecificfunctionsusethegodocfmtPrintfandgodoc-srcfmtPrintfcommandstoviewthesourcecode

Executethegodoc-http=8080commandthenopen1270018080inyourbrowserYoushouldseealocalizedgolangorgItcannotonlyshowthestandardpackagesinformationbutalsopackagesinyour$GOPATHpkgItsgreatforpeoplewhoaresufferingfromtheGreatFirewallofChina

OthercommandsGoprovidesmorecommandsthanthosewevejusttalkedabout

gofixupgradecodefromanoldversionbeforego1toanewversionaftergo1

goversiongetinformationaboutyourversionofGo

goenvviewenvironmentvariablesaboutGo

golistlistallinstalledpackages

goruncompiletemporaryfilesandruntheapplication

TherearealsomoredetailsaboutthecommandsthatIvetalkedaboutYoucanusegohelpltcommandgttolookthemup

LinksDirectoryPrevioussection$GOPATHandworkspaceNextsectionGodevelopmenttools

Gocommands

18

GodevelopmenttoolsInthissectionImgoingtoshowyouafewIDEsthatcanhelpyoubecomeamoreefficientprogrammerwithcapabilitiessuchasintelligentcodecompletionandauto-formattingTheyareallcross-platformsothestepsIwillbeshowingyoushouldnotbeverydifferentevenifyouarenotusingthesameoperatingsystem

LiteIDELiteIDEisanopensourcelightweightIDEfordevelopingGoprojectsonlydevelopedbyvisualfc

Figure14MainpanelofLiteIDE

LiteIDEfeatures

Cross-platformWindowsLinuxMacOS

Cross-compileManagemultiplecompileenvironmentsSupportscross-compilationofGo

ProjectmanagementstandardDocumentationviewbasedon$GOPATHCompilationsystembasedon$GOPATHAPIdocumentationindexbasedon$GOPATH

GosourcecodeeditorCodeoutliningFullsupportofgocodeGodocumentationviewandAPIindexViewcodeexpressionusingF1FunctiondeclarationjumpusingF2GdbsupportAuto-formatwithgofmt

OthersMulti-languagePluginsystemTexteditorthemesSyntaxsupportbasedonKateintelligentcompletionbasedonfull-textCustomizedshortcutsMarkdownsupport

Real-timepreviewCustomizedCSSExportHTMLandPDFConvertandmergetoHTMLandPDF

LiteIDEinstallationInstallLiteIDE

Downloadpage

Godevelopmenttools

19

Sourcecode

YouneedtoinstallGofirstthendownloadtheversionappropriateforyouroperatingsystemDecompressthepackagetodirectlyuseit

Installgocode

Youhavetoinstallgocodeinordertouseintelligentcompletion

goget-ugithubcomnsfgocode

Compilationenvironment

SwitchconfigurationinLiteIDEtosuityouroperatingsystemInWindowsandusingthe64-bitversionofGoyoushouldchoosewin64astheconfigurationenvironmentinthetoolbarThenchooseOptionsfindLiteEnvintheleftlistandopenfilewin64envintherightlist

GOROOT=cgo

GOBIN=

GOARCH=amd64

GOOS=windows

CGO_ENABLED=1

PATH=GOBINGOROOTbinPATH

ReplaceGOROOT=cgotoyourGoinstallationpathsaveitIfyouhaveMinGW64addcMinGW64bintoyourpathenvironmentvariableforcgosupport

InLinuxandusingthe64-bitversionofGoyoushouldchooselinux64astheconfigurationenvironmentinthetoolbarThenchooseOptionsfindLiteEnvintheleftlistandopenthelinux64envfileintherightlist

GOROOT=$HOMEgo

GOBIN=

GOARCH=amd64

GOOS=linux

CGO_ENABLED=1

PATH=$GOBIN$GOROOTbin$PATH

ReplaceGOROOT=$HOMEgotoyourGoinstallationpathsaveit

$GOPATH$GOPATHisthepaththatcontainsalistofprojectsOpenthecommandtool(orpressCtrl+`inLiteIDE)thentypegohelpgopathformoredetailsItsveryeasytoviewandchange$GOPATHinLiteIDEFollowView-SetupGOPATHtoviewandchangethesevalues

SublimeTextHereImgoingtointroduceyoutheSublimeText3(Sublimeforshort)+GoSublime+gocodeLetmeexplainwhy

Intelligentcompletion

Figure15Sublimeintelligentcompletion

Auto-formatsourcefilesProjectmanagement

Godevelopmenttools

20

Figure16Sublimeprojectmanagement

Syntaxhighlight

FreetrialforeverwithnofunctionallimitationsYoumaybepromptedonceinawhiletoremindyoutopurchasealicensebutyoucansimplyignoreitifyouwishOfcourseifyoudofindthatitenhancesyourproductivityandyoureallyenjoyusingitpleasepurchaseacopyofitandsupportitscontinueddevelopment

FirstdownloadtheversionofSublimesuitableforyouroperatingsystem

1 PressCtrl+`openthecommandtoolandinputthefollowingcommands

ApplicabletoSublimeText3

importurllibrequestospf=PackageControlsublime-packageipp=sublimeinstalled_packages_path()urllibrequesti

nstall_opener(urllibrequestbuild_opener(urllibrequestProxyHandler()))open(ospathjoin(ipppf)wb)write(urlli

brequesturlopen(httpsublimewbondnet+pfreplace(20))read())

ApplicabletoSublimeText2

importurllib2ospf=PackageControlsublime-packageipp=sublimeinstalled_packages_path()osmakedirs(ipp)ifnotos

pathexists(ipp)elseNoneurllib2install_opener(urllib2build_opener(urllib2ProxyHandler()))open(ospathjoin(ipp

pf)wb)write(urllib2urlopen(httpsublimewbondnet+pfreplace(20))read())print(PleaserestartSubl

imeTexttofinishinstallation)

RestartSublimeTextwhentheinstallationhasfinishedYoushouldthenfinda`PackageControl`optioninthePref

erencesmenu

[](images14sublime3pngraw=true)

Figure17SublimePackageControl

1 ToinstallGoSublimeSidebarEnhancementsandGoBuildpressCtrl+Shift+ptoopenPackageControlthentypepcip(shortforPackageControlInstallPackage)

Figure18SublimeInstallPackages

NowtypeinGoSublimepressOKtoinstallthepackageandrepeatthesamestepsforinstallingSidebarEnhancementsandGoBuildOnceagainrestarttheeditorwhenitcompletestheinstallation

2 ToverifythattheinstallationissuccessfulopenSublimethenopenthemaingofiletoseeifithasthepropersyntaxhighlightingTypeimporttoseeifcodecompletionpromptsappearAftertypingimportfmttypefmtanywhereaftertheimportdeclarationtoseewhetherornotintelligentcodecompletionforfunctionswassuccessfullyenabled

Ifeverythingisfineyoureallset

Ifnotcheckyour$PATHagainOpenaterminaltypegocodeIfitdoesnotrunyour$PATHwasnotconfiguredcorrectly

VimVimisapopulartexteditorforprogrammerswhichevolvedfromitsslimmerpredecessorViIthasfunctionsforintelligentcompletioncompilationandjumpingtoerrors

vim-goisvimaboveanopen-sourcegolanguageusingthemostextensivedevelopmentenvironmentplug-ins

Thepluginaddressgithubcomfatihvim-go

Godevelopmenttools

21

VimpluginmanagementarethemainstreamPathogenandVundleButtheaspectsthereofaredifferentPathogenistosolveeachplug-inaftertheinstallationoffilesscatteredtomultipledirectoriesandpoormanagementoftheexistenceVundleistosolvetheautomaticsearchanddownloadplug-insexistThesetwoplug-inscanbeusedsimultaneously

1InstallVundle

mkdir~vimbundle

gitclonehttpsgithubcomgmarikVundlevimgit~vimbundleVundlevim

EditvimrcVundletherelevantconfigurationwillbeplacedinthebeginning(RefertotheVundledocumentationfordetails)

setnocompatiblebeiMprovedrequired

filetypeoffrequired

settheruntimepathtoincludeVundleandinitialize

setrtp+=~vimbundleVundlevim

callvundlebegin()

letVundlemanageVundlerequired

PlugingmarikVundlevim

AllofyourPluginsmustbeaddedbeforethefollowingline

callvundleend()required

filetypepluginindentonrequired

2InstallVim-go

Edit~vimrcAddalinebetweenvundlebeginandvundleend

Pluginfatihvim-go

ExecutedwithinVimPluginInstall

3InstallYCM(YourCompleteMe)toAutoCompleteAddalineto~vimrc

PluginValloricYouCompleteMe

ExecutedwithinVimPluginInstall

Figure18VimintelligentcompletionforGo

1 SyntaxhighlightingforGo

cp-r$GOROOTmiscvim~vim

2 Enablingsyntaxhighlighting

filetypepluginindenton

syntaxon

3 Installgocode

goget-ugithubcomnsfgocode

gocodewillbeinstalledin$GOBINasdefault

Godevelopmenttools

22

4 Configuregocode

~cd$GOPATHsrcgithubcomnsfgocodevim

~updatesh

~gocodesetpropose-builtinstrue

propose-builtinstrue

~gocodesetlib-pathhomebordergocodepkglinux_amd64

lib-pathhomebordergocodepkglinux_amd64

~gocodeset

propose-builtinstrue

lib-pathhomebordergocodepkglinux_amd64

Explanationofgocodeconfiguration

propose-builtinsspecifieswhetherornottoopenintelligentcompletionfalsebydefaultlib-pathgocodeonlysearchesforpackagesin$GOPATHpkg$GOOS_$GOARCHand$GOROOTpkg$GOOS_$GOARCHThissettingcanbeusedtoaddadditionalpaths

5 CongratulationsTryemaingotoexperiencetheworldofGo

EmacsEmacsistheso-calledWeaponofGodSheisnotonlyaneditorbutalsoapowerfulIDE

Figure110EmacsmainpanelofGoeditor

1 Syntaxhighlighting

cp$GOROOTmiscemacs~emacsd

2 Installgocode

goget-ugithubcomnsfgocode

gocodewillbeinstalledin$GOBINasdefault

3 Configuregocode

~cd$GOPATHsrcgithubcomnsfgocodevim

~updatebash

~gocodesetpropose-builtinstrue

propose-builtinstrue

~gocodesetlib-pathhomebordergocodepkglinux_amd64

lib-pathhomebordergocodepkglinux_amd64

~gocodeset

propose-builtinstrue

lib-pathhomebordergocodepkglinux_amd64

4 InstallAutoCompletionDownloadanduncompress

~makeinstallDIR=$HOMEemacsdauto-complete

Configure~emacsfile

Godevelopmenttools

23

auto-complete

(requireauto-complete-config)

(add-to-listac-dictionary-directories~emacsdauto-completeac-dict)

(ac-config-default)

(local-set-key(kbdM-)semantic-complete-analyze-inline)

(local-set-keysemantic-complete-self-insert)

(local-set-keygtsemantic-complete-self-insert)

Followthislinkformoredetails

5 Configureemacs

golangmode

(requirego-mode-load)

(requirego-autocomplete)

speedbar

(speedbar1)

(speedbar-add-supported-extensiongo)

(add-hook

go-mode-hook

(lambda()

gocode

(auto-complete-mode1)

(setqac-sources(ac-source-go))

ImenuampSpeedbar

(setqimenu-generic-expression

((type^type([^tnrf])1)

(func^func()1)))

(imenu-add-to-menubarIndex)

Outlinemode

(make-local-variableoutline-regexp)

(setqoutline-regexp|[^rnf][^rnf]|pack|func|impo|cons|var|type|tt)

(outline-minor-mode1)

(local-set-keyM-aoutline-previous-visible-heading)

(local-set-keyM-eoutline-next-visible-heading)

Menubar

(requireeasymenu)

(defconstgo-hooked-menu

(Gotools

[Gorunbuffergot]

[Goreformatbuffergo-fmt-buffert]

[Gocheckbuffergo-fix-buffert]))

(easy-menu-define

go-added-menu

(current-local-map)

Gotools

go-hooked-menu)

Other

(setqshow-trailing-whitespacet)

))

helperfunction

(defungo()

runcurrentbuffer

(interactive)

(compile(concatgorun(buffer-file-name))))

helperfunction

(defungo-fmt-buffer()

rungofmtoncurrentbuffer

(interactive)

(ifbuffer-read-only

(progn

(ding)

(messageBufferisreadonly))

(let((p(line-number-at-pos))

(filename(buffer-file-name))

(old-max-mini-window-heightmax-mini-window-height))

(show-all)

(if(get-bufferGoReformatErrors)

Godevelopmenttools

24

(progn

(delete-windows-onGoReformatErrors)

(kill-bufferGoReformatErrors)))

(setqmax-mini-window-height1)

(if(=0(shell-command-on-region(point-min)(point-max)gofmtGoReformatOutputnilGoRefor

matErrorst))

(progn

(erase-buffer)

(insert-buffer-substringGoReformatOutput)

(goto-char(point-min))

(forward-line(1-p)))

(with-current-bufferGoReformatErrors

(progn

(goto-char(point-min))

(while(re-search-forwardltstandardinputgtnilt)

(replace-matchfilename))

(goto-char(point-min))

(compilation-mode))))

(setqmax-mini-window-heightold-max-mini-window-height)

(delete-windows-onGoReformatOutput)

(kill-bufferGoReformatOutput))))

helperfunction

(defungo-fix-buffer()

rungofixoncurrentbuffer

(interactive)

(show-all)

(shell-command-on-region(point-min)(point-max)gotoolfix-diff))

6 CongratulationsyouredoneSpeedbarisclosedbydefault-removethecommentsymbolsintheline(speedbar1)toenablethisfeatureoryoucanuseitthroughM-xspeedbar

EclipseEclipseisalsoagreatdevelopmenttoolIllshowyouhowtouseittowriteGoprograms

Figure11EclipsemainpanelforeditingGo

1 DownloadandinstallEclipse2 DownloadgoclipsehttpcodegooglecompgoclipsewikiInstallationInstructions3 Downloadgocode

gocodeinGithub

httpsgithubcomnsfgocode

YouneedtoinstallgitinWindowsusuallyweusemsysgit

Installgocodeinthecommandtool

goget-ugithubcomnsfgocode

Youcaninstallfromsourcecodeifyoulike

4 DownloadandinstallMinGW5 Configureplugins

Windows-gtPreferences-gtGo

(1)ConfigureGocompiler

Godevelopmenttools

25

Figure112GoSettinginEclipse

(2)Configuregocode(optional)setgocodepathtowherethegocodeexeis

Figure113gocodeSetting

(3)Configuregdb(optional)setgdbpathtowherethegdbexeis

Figure114gdbSetting

6 Checktheinstallation

CreateanewGoprojectandhellogofileasfollowing

Figure115Createanewprojectandfile

Testinstallationasfollows(youneedtotypecommandinconsoleinEclipse)

Figure116TestGoprograminEclipse

IntelliJIDEAPeoplewhohaveworkedwithJavashouldbefamiliarwiththisIDEItsupportsGosyntaxhighlightingandintelligentcodecompletionimplementedbyaplugin

1 DownloadIDEAthereisnodifferencebetweentheUltimateandCommunityeditions

2 InstalltheGopluginChooseFile-Setting-PluginsthenclickBrowserrepo

3 Searchgolangdoubleclickdownloadandinstallandwaitforthedownloadtocomplete

ClickApplythenrestart

4 NowyoucancreateaGoproject

InputthepositionofyourGosdkinthenextstep-basicallyitsyour$GOROOT

(SeeablogpostforsetupanduseIntelliJIDEAwithGostepbystep)

VisualStudioVSCodeThisisanawesometexteditorreleasedasopensourcecrossplatformmyMicrosoftwhichtakesthedevelopmentexperiencetoawholenewlevelhttpscodevisualstudiocomIthaseverythingamoderntexteditorisexpectedtohaveanddespitebeingbasedonthesamebackendthatatomioisbaseditisveryfast

ItworkswithWindowsMacLinuxIthasgopackagebuiltitprovidescodelinting

Godevelopmenttools

26

AtomAtomisanawesometexteditorreleasedasopensourcecrossplatformbuiltonElectronandbasedoneverythingweloveaboutourfavoriteeditorsWedesignedittobedeeplycustomizablebutstillapproachableusingthedefaultconfiguration

Downloadhttpsatomio

GoglandGoglandisthecodenameforanewcommercialIDEbyJetBrainsaimedatprovidinganergonomicenvironmentforGodevelopment

Theofficialversionisnotyetreleased

Downloadhttpswwwjetbrainscomgo

LinksDirectoryPrevioussectionGocommandsNextsectionSummary

Godevelopmenttools

27

15SummaryInthischapterwetalkedabouthowtoinstallGousingthreedifferentmethodsincludingfromsourcecodethestandardpackageandviathird-partytoolsThenweshowedyouhowtoconfiguretheGodevelopmentenvironmentmainlycoveringhowtosetupyour$GOPATHAfterthatweintroducedsomestepsforcompilinganddeployingGoprogramsWethencoveredGocommandsincludingthecompileinstallformatandtestcommandsFinallytherearemanypowerfultoolstodevelopGoprogramssuchasLiteIDESublimeTextVSCodeAtomGoglangVimEmacsEclipseIntelliJIDEAetcYoucanchooseanyoneyoulikeexploringtheworldofGo

LinksDirectoryPrevioussectionGodevelopmenttoolsNextchapterGobasicknowledge

Summary

28

2GobasicknowledgeGoisacompiledsystemprogramminglanguageanditbelongstotheC-familyHoweveritscompilationspeedismuchfasterthanotherC-familylanguagesIthasonly25keywordsevenlessthanthe26lettersoftheEnglishalphabetLetstakealookatthesekeywordsbeforewegetstarted

breakdefaultfuncinterfaceselect

casedefergomapstruct

chanelsegotopackageswitch

constfallthroughifrangetype

continueforimportreturnvar

InthischapterImgoingtoteachyousomebasicGoknowledgeYouwillfindouthowconcisetheGoprogramminglanguageisandthebeautifuldesignofthelanguageProgrammingcanbeveryfuninGoAfterwecompletethischapteryoullbefamiliarwiththeabovekeywords

LinksDirectoryPreviouschapterChapter1SummaryNextsectionHelloGo

Gobasicknowledge

29

WhatmakesGodifferentfromotherlanguagesTheGoprogramminglanguagewascreatedwithonegoalinmindtobeabletobuildscalableweb-applicationsforlargescaleaudiencesinalargeteamSothatisthereasontheymadethelanguageasstandardizedaspossiblehencethegofmttoolandthestrictusageguidelinestothelanguagewasforthesakeofnothavingtwofactionsinthedeveloperbaseinotherlanguagestherearereligiouswarsonwheretokeeptheopeningbrace

publicstaticvoidmain()

or

publicstaticvoidmain()

orforpythonshouldweuse4spacesor6spacesoratabortwotabsandotheruserpreferencesIfyouknowpythonthenyoumightbeawareofPEP8whichisasetofguidelinesabouthowtowriteelegantcode

WhilethismightseemtobeashallowproblemwhenthecodebasegrowsandmoreandmorepeopleworkonthesamecodebaseitisbecomesincreasinglydifficulttomaintainthecodesbeautyWeliveinaworldwhererobotscandriveacarsoweshouldntjustwritecodeweshouldwriteelegantcode

ForotherlanguagestherearemanyvariableswhenitcomestowritingcodeEverylanguageisgoodforitsusecasebutGoisalittlespecialbecauseitwasdesignedatacompanywhichistheverysynonymoftheInternet(anddistributedcomputing)TypicallyinordertooptimizeprogramsdeveloperschoosetowriteJavaoverPythonandC++overJavabutalmostallavailablelanguageswidelyinusewerewrittendecadesagowhen1GBstoragewasmuchpricierNowstorageandcomputingisrelativelycheapandcomputersaregettingmultiplescoresbuttheoldlanguagesarenotharnessingconcurrencyinawaythatgodoesItsnotbecausethoselanguagesarebadutilizingconcurrencywasntarelevantusecasewhiletheolderlanguagesevolved

TomitigatealltheproblemsthatGooglefacedwithcurrenttoolstheywroteasystemslanguagecalledGowhichyouareabouttolearnTherearemanyadvantagestousinggolangandtherearedisadvantagestooforeverycoinhasbothsidesOneofthesignificantimprovementsinincodeformattingGooglehasdesignedthelanguagetoavoiddebatesoncodeformattingGocodewrittenbyanyoneintheworld(assumingtheyknowandusegofmt)willlookexactlythesameThiswontseemtomatteruntilyouworkinateamAlsowhenthecompanyusesautomatedcoderevieworsomeotherfancytechniquetheformattedcodemaybreakinotherlanguageswhichdonthavestrictandstandardformattingrulesbutnotingo

Gowasdesignedwithconcurrencyinmindpleasenotethatparallelism=concurrencythereisanamazingpostbyRobPikeonthegolangblogyouwillfinditthereitiswortharead

AnotherveryimportantchangethatistheconceptofGOPATHGonearethedayswhenyouhadtocreateafoldercalledcodeandthencreateworkspacesforeclipseandwhatnotNowyouhavetokeeponefoldertreeforgocodewhichwillbeupdatedbythepackagemanagerautomaticallyItisalsorecommendedtocreatefolderswitheitheracustomdomainorthegithubdomainforexampleIcreatedataskmanagerusinggolangsoIcreatedasetoffolders~gosrcgithubcomthewhitetulipTasks

NoteInnixsystems~standsforhomedirectorywhichisthewindowsequivalentofCUsersusernameNowthe~goistheuniverseforthegocodeinyourmachineThisisasignificantimprovementoverotherlanguageswecanstorethecodeefficientlywithouthasslesWhileitmightseemstrangeatfirstthisapproachmakealotofsensethantheridiculouspackagenamesiepackagenamesgeneratedforotherlanguagesusingreversedomains

NoteAlongwithsrctherearetwofolderspkgwhichisforpackagesandbinwhichisforbinary

HelloGo

30

ThisGOPATHadvantageisntjustrestrictedtostoringcodeinparticularfolderWhenyouhavecreatedfivepackagesforyourprojectyoudonthavetoimportthemlikeimportdbInsteadyoucanuseimportgithubcomthewhitetulipTasksdbsothatwhenexecutinggogetonmyrepothegotoolwillfindthepackagefromgithubcompathifitwasntdownloadedinitiallyThisstandardizesalotofscrewedupthingsintheprogrammingdiscipline(lt--Toremoveandreplacewithactualexplanationofwhythisisbetter)

Whiletheremaybesomefoundedcomplaintsthatgocreatorshaveignoredalllanguageresearchdonesincethepast30yrsyoucannotcreateaproductoralanguagewhicheveryonewillfallinlovewithTherearealwayssomeortheotherusecasesorconstraintswhichthecreatorsshouldconsiderConsideringalltheadvantagesatleastforwebdevelopmentIdonotthinkanylanguagegetsclosetotheadvantageswhichgohasevenifyouignoreallthatIsaidaboveGoisacompiledlanguagewhichmeansinproductionyouwonthavetosetupaJVMoravirtualenvandwillinsteadhaveasinglestaticbinaryLikeanicingonacakeallthemodernlibrariesareinthestandardlibrarysuchasthehttpliballowingyoutocreatewebappsingolangwithoutusingathirdpartywebframework

21HelloGoBeforewestartbuildinganapplicationinGoweneedtolearnhowtowriteasimpleprogramYoucantexpecttobuildabuildingwithoutfirstknowinghowtobuilditsfoundationThereforewearegoingtolearnthebasicsyntaxtorunsomesimpleprogramsinthissection

ProgramAccordingtointernationalpracticebeforeyoulearnhowtoprograminsomelanguagesyouwillwanttoknowhowtowriteaprogramtoprintHelloworld

AreyoureadyLetsGo

packagemain

importfmt

funcmain()

fmtPrintf(Helloworldor你好世界orΚαλημέρακόσμεorこんにちは世界n)

Itprintsfollowinginformation

Helloworldor你好世界orΚαλημέρακόσμεorこんにちは世界

ExplanationOnethingthatyoushouldknowinthefirstisthatGoprogramsarecomposedbypackage

packageltpkgNamegt(Inthiscaseispackagemain)tellsusthissourcefilebelongstomainpackageandthekeywordmaintellsusthispackagewillbecompiledtoaprograminsteadofpackagefileswhoseextensionsarea

Everyexecutableprogramhasoneandonlyonemainpackageandyouneedanentryfunctioncalledmainwithoutanyargumentsorreturnvaluesinthemainpackage

InordertoprintHelloworldhellipwecalledafunctioncalledPrintfThisfunctioniscomingfromfmtpackagesoweimportthispackageinthethirdlineofsourcecodewhichisimportfmt

ThewaytothinkaboutpackagesinGoissimilartoPythonandtherearesomeadvantagesModularity(breakupyourprogramintomanymodules)andreusability(everymodulecanbereusedinmanyprograms)Wejusttalkedaboutconceptsregardingpackagesandwewillmakeourownpackageslater

HelloGo

31

OnthefifthlineweusethekeywordfunctodefinethemainfunctionThebodyofthefunctionisinsideofjustlikeCC++andJava

AsyoucanseetherearenoargumentsWewilllearnhowtowritefunctionswithargumentsinjustasecondandyoucanalsohavefunctionsthathavenoreturnvalueorhaveseveralreturnvalues

OnthesixthlinewecalledthefunctionPrintfwhichisfromthepackagefmtThiswascalledbythesyntaxltpkgNamegtltfuncNamegtwhichisverylikePython-style

Aswementionedinchapter1thepackagesnameandthenameofthefolderthatcontainsthatpackagecanbedifferentHeretheltpkgNamegtcomesfromthenameinpackageltpkgNamegtnotthefoldersname

Youmaynoticethattheexampleabovecontainsmanynon-ASCIIcharactersThepurposeofshowingthisistotellyouthatGosupportsUTF-8bydefaultYoucanuseanyUTF-8characterinyourprograms

EachgofileisinsomepackageandthatpackageshouldbeadistinctfolderintheGOPATHbutmainisaspecialpackagewhichdoesntrequireamainfolderThisisoneaspectwhichtheyleftoutforstandardizationButshouldyouchoosetomakeamainfolderthenyouhavetoensurethatyourunthebinaryproperlyAlsoonegocodecanthavemorethanonemaingofile

~gosrcgithubcomthewhitetulipTasksmain$gobuild~gosrcgithubcomthewhitetulipTasks$mainmain

thethinghereisthatwhenyourcodeisusingsomestaticfilesorsomethingelsethenyououghttorunthebinaryfromtherootoftheapplicationasweseeinthesecondlineaboveIamrunningthemainbinaryoutsidethemainpackagesometimesyoumightwonderwhyyourapplicationisntworkingthenthismightbeoneofthepossibleproblemspleasekeepthisinmind

Onethingyouwillnoticehereisthatgodoesntseetousesemicolonstoendastatementwellitdoesjustthereisaminorcatchtheprogrammerisntexpectedtoputsemicolonsthecompileraddssemicolonstothegocodewhenitcompileswhichisthereasonthatthis(thankfully)isasyntaxerror

funcmain()

becausethecompileraddsasemicolonattheendofmain()whichisasyntaxerrorandasstatedaboveithelpsavoidreligiouswarsiwishtheycombinevimandemacsandcreateauniversaleditorwhichllhelpsavesomemorewarsButfornowwelllearnGo

ConclusionGousespackage(likemodulesinPython)toorganizeprogramsThefunctionmainmain()(thisfunctionmustbeinthemainpackage)istheentrypointofanyprogramGostandardizeslanguageandmostoftheprogrammingmethodologysavingtimeofdeveloperswhichtheydhavewastedinreligiouswarsTherecanbeonlyonemainpackageandonlyonemainfunctioninsideagomainpackageGosupportsUTF-8charactersbecauseoneofthecreatorsofGoisacreatorofUTF-8soGohassupportedmultiplelanguagesfromthetimeitwasborn

LinksDirectoryPrevioussectionGobasicknowledgeNextsectionGofoundation

HelloGo

32

HelloGo

33

22GofoundationInthissectionwearegoingtoteachyouhowtodefineconstantsvariableswithelementarytypesandsomeskillsinGoprogramming

DefinevariablesTherearemanyformsofsyntaxthatcanbeusedtodefinevariablesinGo

ThekeywordvaristhebasicformtodefinevariablesnoticethatGoputsthevariabletypeafterthevariablename

defineavariablewithnameldquovariableNamerdquoandtypetype

varvariableNametype

Definemultiplevariables

definethreevariableswhichtypesaretype

varvname1vname2vname3type

Defineavariablewithinitialvalue

defineavariablewithnameldquovariableNamerdquotypetypeandvaluevalue

varvariableNametype=value

Definemultiplevariableswithinitialvalues

Definethreevariableswithtypetypeandinitializetheirvalues

vname1isv1vname2isv2vname3isv3

varvname1vname2vname3type=v1v2v3

DoyouthinkthatitstootedioustodefinevariablesusethewayaboveDontworrybecausetheGoteamhasalsofoundthistobeaproblemThereforeifyouwanttodefinevariableswithinitialvalueswecanjustomitthevariabletypesothecodewilllooklikethisinstead

Definethreevariableswithouttypetypeandinitializetheirvalues

vname1isv1vname2isv2vname3isv3

varvname1vname2vname3=v1v2v3

WellIknowthisisstillnotsimpleenoughforyouLetsseehowwefixit

Definethreevariableswithouttypetypeandwithoutkeywordvarandinitializetheirvalues

vname1isv1vname2isv2vname3isv3

vname1vname2vname3=v1v2v3

NowitlooksmuchbetterUse=toreplacevarandtypethisiscalledashortassignmentIthasonelimitationthisformcanonlybeusedinsideofafunctionsYouwillgetcompileerrorsifyoutrytouseitoutsideoffunctionbodiesThereforeweusuallyusevartodefineglobalvariables

Gofoundation

34

_(blank)isaspecialvariablenameAnyvaluethatisgiventoitwillbeignoredForexamplewegive35tobanddiscard34(ThisexamplejustshowyouhowitworksItlooksuselessherebecauseweoftenusethissymbolwhenwegetfunctionreturnvalues)

_b=3435

IfyoudontusevariablesthatyouvedefinedinyourprogramthecompilerwillgiveyoucompilationerrorsTrytocompilethefollowingcodeandseewhathappens

packagemain

funcmain()

variint

ConstantsSo-calledconstantsarethevaluesthataredeterminedduringcompiletimeandyoucannotchangethemduringruntimeInGoyoucanusenumberbooleanorstringastypesofconstants

Defineconstantsasfollows

constconstantName=value

youcanassigntypeofconstantsifitsnecessary

constPifloat32=31415926

Moreexamples

constPi=31415926

consti=10000

constMaxThread=10

constprefix=astaxie_

Elementarytypes

Boolean

InGoweusebooltodefineavariableasbooleantypethevaluecanonlybetrueorfalseandfalsewillbethedefaultvalue(Youcannotconvertvariablestypebetweennumberandboolean)

samplecode

varisActiveboolglobalvariable

varenableddisabled=truefalseomittypeofvariables

functest()

varavailableboollocalvariable

valid=falsebriefstatementofvariable

available=trueassignvaluetovariable

Numericaltypes

IntegertypesincludebothsignedandunsignedintegertypesGohasintanduintatthesametimetheyhavesamelengthbutspecificlengthdependsonyouroperatingsystemTheyuse32-bitin32-bitoperatingsystemsand64-bitin64-bitoperatingsystemsGoalsohastypesthathavespecificlengthincludingruneint8int16int32int64byteuint8uint16uint32uint64Notethatruneisaliasofint32andbyteisaliasofuint8

Gofoundation

35

Oneimportantthingyoushouldknowthatyoucannotassignvaluesbetweenthesetypesthisoperationwillcausecompileerrors

varaint8

varbint32

c=a+b

Althoughint32hasalongerlengththanint8andhasthesametypeasintyoucannotassignvaluesbetweenthem(cwillbeassertedastypeinthere)

Floattypeshavethefloat32andfloat64typesandnotypecalledfloatThelatteroneisthedefaulttypeifusingbriefstatement

ThatsallNoGosupportscomplexnumbersaswellcomplex128(witha64-bitrealand64-bitimaginarypart)isthedefaulttypeifyouneedasmallertypethereisonecalledcomplex64(witha32-bitrealand32-bitimaginarypart)ItsformisRE+IMiwhereREisrealpartandIMisimaginarypartthelastiistheimaginarynumberThereisaexampleofcomplexnumber

varccomplex64=5+5i

output(5+5i)

fmtPrintf(Valueisvc)

String

WejusttalkedabouthowGousestheUTF-8charactersetStringsarerepresentedbydoublequotesorbackticks `

samplecode

varfrenchHellostringbasicformtodefinestring

varemptyStringstring=defineastringwithemptystring

functest()

noyesmaybe=noyesmaybebriefstatement

japaneseHello=Ohaiou

frenchHello=Bonjourbasicformofassignvalues

ItsimpossibletochangestringvaluesbyindexYouwillgeterrorswhenyoucompilethefollowingcode

varsstring=hello

s[0]=c

WhatifIreallywanttochangejustonecharacterinastringTrythefollowingcode

s=hello

c=[]byte(s)convertstringto[]bytetype

c[0]=c

s2=string(c)convertbacktostringtype

fmtPrintf(sns2)

Youusethe+operatortocombinetwostrings

s=hello

m=world

a=s+m

fmtPrintf(sna)

andalso

Gofoundation

36

s=hello

s=c+s[1]youcannotchangestringvaluesbyindexbutyoucangetvaluesinstead

fmtPrintf(sns)

WhatifIwanttohaveamultiple-linestring

m=`hello

world`

willnotescapeanycharactersinastring

ErrortypesGohasoneerrortypeforpurposeofdealingwitherrormessagesThereisalsoapackagecallederrorstohandleerrors

err=errorsNew(emitmachodwarfelfheadercorrupted)

iferr=nil

fmtPrint(err)

Underlyingdatastructure

ThefollowingpicturecomesfromanarticleaboutGodatastructureinRussCoxsBlogAsyoucanseeGoutilizesblocksofmemorytostoredata

Figure21Gounderlyingdatastructure

Someskills

Definebygroup

Ifyouwanttodefinemultipleconstantsvariablesorimportpackagesyoucanusethegroupform

Basicform

importfmt

importos

consti=100

constpi=31415

constprefix=Go_

variint

varpifloat32

varprefixstring

Groupform

Gofoundation

37

import(

fmt

os

)

const(

i=100

pi=31415

prefix=Go_

)

var(

iint

pifloat32

prefixstring

)

Unlessyouassignthevalueofconstantisiotathefirstvalueofconstantinthegroupconst()willbe0IffollowingconstantsdontassignvaluesexplicitlytheirvalueswillbethesameasthelastoneIfthevalueoflastconstantisiotathevaluesoffollowingconstantswhicharenotassignedareiotaalso

iotaenumerate

Gohasonekeywordcallediotathiskeywordistomakeenumitbeginswith0increasedby1

const(

x=iotax==0

y=iotay==1

z=iotaz==2

wIfthereisnoexpressionaftertheconstantsnameitusesthelastexpression

soitssayingw=iotaimplicitlyThereforew==3andyandzbothcanomit=iotaaswell

)

constv=iotaonceiotameetskeyword`const`itresetsto`0`sov=0

const(

efg=iotaiotaiotae=0f=0g=0valuesofiotaaresameinoneline

)

Somerules

ThereasonthatGoisconcisebecauseithassomedefaultbehaviors

AnyvariablethatbeginswithacapitallettermeansitwillbeexportedprivateotherwiseThesameruleappliesforfunctionsandconstantsnopublicorprivatekeywordexistsinGo

arrayslicemap

array

arrayisanarrayobviouslywedefineoneasfollows

vararr[n]type

in[n]typenisthelengthofthearraytypeisthetypeofitselementsLikeotherlanguagesweuse[]togetorsetelementvalueswithinarrays

Gofoundation

38

vararr[10]intanarrayoftype[10]int

arr[0]=42arrayis0-based

arr[1]=13assignvaluetoelement

fmtPrintf(Thefirstelementisdnarr[0])

getelementvalueitreturns42

fmtPrintf(Thelastelementisdnarr[9])

itreturnsdefaultvalueof10thelementinthisarraywhichis0inthiscase

Becauselengthisapartofthearraytype[3]intand[4]intaredifferenttypessowecannotchangethelengthofarraysWhenyouusearraysasargumentsfunctionsgettheircopiesinsteadofreferencesIfyouwanttousereferencesyoumaywanttousesliceWelltalkaboutlater

Itspossibletouse=whenyoudefinearrays

a=[3]int123defineanintarraywith3elements

b=[10]int123

defineaintarraywith10elementsofwhichthefirstthreeareassigned

Therestofthemusethedefaultvalue0

c=[]int456use`hellip`toreplacethelengthparameterandGowillcalculateitforyou

YoumaywanttousearraysasarrayselementsLetsseehowtodothis

defineatwo-dimensionalarraywith2elementsandeachelementhas4elements

doubleArray=[2][4]int[4]int1234[4]int5678

Thedeclarationcanbewrittenmoreconciselyasfollows

easyArray=[2][4]int12345678

Arrayunderlyingdatastructure

Figure22Multidimensionalarraymappingrelationship

sliceInmanysituationsthearraytypeisnotagoodchoice-forinstancewhenwedontknowhowlongthearraywillbewhenwedefineitThusweneedadynamicarrayThisiscalledsliceinGo

sliceisnotreallyadynamicarrayItsareferencetypeslicepointstoanunderlyingarraywhosedeclarationissimilartoarraybutdoesntneedlength

justlikedefininganarraybutthistimeweexcludethelength

varfslice[]int

Thenwedefineasliceandinitializeitsdata

slice=[]byteabcd

slicecanredefineexistingslicesorarrayssliceusesarray[ij]toslicewhereiisthestartindexandjisendindexbutnoticethatarray[j]willnotbeslicedsincethelengthofthesliceisj-i

Gofoundation

39

defineanarraywith10elementswhosetypesarebytes

varar=[10]byteabcdefghij

definetwosliceswithtype[]byte

varab[]byte

apointstoelementsfrom3rdto5thinarrayar

a=ar[25]

nowahaselementsar[2]ar[3]andar[4]

bisanothersliceofarrayar

b=ar[35]

nowbhaselementsar[3]andar[4]

NoticethedifferencesbetweensliceandarraywhenyoudefinethemWeuse[hellip]toletGocalculatelengthbutuse[]todefinesliceonly

Theirunderlyingdatastructure

Figure23Correspondencebetweensliceandarray

slicehassomeconvenientoperations

sliceis0-basedar[n]equalstoar[0n]Thesecondindexwillbethelengthofsliceifomittedar[n]equalstoar[nlen(ar)]Youcanusear[]toslicewholearrayreasonsareexplainedinfirsttwostatements

Moreexamplespertainingtoslice

defineanarray

vararray=[10]byteabcdefghij

definetwoslices

varaSlicebSlice[]byte

someconvenientoperations

aSlice=array[3]equalstoaSlice=array[03]aSlicehaselementsabc

aSlice=array[5]equalstoaSlice=array[510]aSlicehaselementsfghij

aSlice=array[]equalstoaSlice=array[010]aSlicehasallelements

slicefromslice

aSlice=array[37]aSlicehaselementsdefglen=4cap=7

bSlice=aSlice[13]bSlicecontainsaSlice[1]aSlice[2]soithaselementsef

bSlice=aSlice[3]bSlicecontainsaSlice[0]aSlice[1]aSlice[2]soithasdef

bSlice=aSlice[05]slicecouldbeexpandedinrangeofcapnowbSlicecontainsdefgh

bSlice=aSlice[]bSlicehassameelementsasaSlicedoeswhicharedefg

sliceisareferencetypesoanychangeswillaffectothervariablespointingtothesamesliceorarrayForinstanceinthecaseofaSliceandbSliceaboveifyouchangethevalueofanelementinaSlicebSlicewillbechangedaswell

sliceislikeastructbydefinitionanditcontains3parts

ApointerthatpointstowhereslicestartsThelengthofsliceCapacitythelengthfromstartindextoendindexofslice

Array_a=[10]byteabcdefghij

Slice_a=Array_a[25]

Theunderlyingdatastructureofthecodeaboveasfollows

Gofoundation

40

Figure24Arrayinformationofslice

Therearesomebuilt-infunctionsforslice

lengetsthelengthofslicecapgetsthemaximumlengthofsliceappendappendsoneormoreelementstosliceandreturnsslicecopycopieselementsfromoneslicetotheotherandreturnsthenumberofelementsthatwerecopied

AttentionappendwillchangethearraythatslicepointstoandaffectotherslicesthatpointtothesamearrayAlsoifthereisnotenoughlengthfortheslice((cap-len)==0)appendreturnsanewarrayforthissliceWhenthishappensotherslicespointingtotheoldarraywillnotbeaffected

map

mapbehaveslikeadictionaryinPythonUsetheformmap[keyType]valueTypetodefineit

LetsseesomecodeThesetandgetvaluesinmaparesimilartoslicehowevertheindexinslicecanonlybeoftypeintwhilemapcanusemuchmorethanthatforexampleintstringorwhateveryouwantAlsotheyareallabletouse==and=tocomparevalues

usestringasthekeytypeintasthevaluetypeand`make`initializeit

varnumbersmap[string]int

anotherwaytodefinemap

numbers=make(map[string]int)

numbers[one]=1assignvaluebykey

numbers[ten]=10

numbers[three]=3

fmtPrintln(Thethirdnumberisnumbers[three])getvalues

ItprintsThethirdnumberis3

Somenoteswhenyouusemap

mapisdisorderlyEverytimeyouprintmapyouwillgetdifferentresultsItsimpossibletogetvaluesbyindex-youhavetousekeymapdoesnthaveafixedlengthItsareferencetypejustlikeslicelenworksformapalsoItreturnshowmanykeysthatmaphasItsquiteeasytochangethevaluethroughmapSimplyusenumbers[one]=11tochangethevalueofkeyoneto11

Youcanuseformkeyvaltoinitializemapsvaluesandmaphasbuilt-inmethodstocheckifthekeyexists

Usedeletetodeleteanelementinmap

Initializeamap

rating=map[string]float32C5Go45Python45C++2

maphastworeturnvaluesForthesecondreturnvalueifthekeydoesnt

existokreturnsfalseItreturnstrueotherwise

csharpRatingok=rating[C]

ifok

fmtPrintln(CisinthemapanditsratingiscsharpRating)

else

fmtPrintln(WehavenoratingassociatedwithCinthemap)

delete(ratingC)deleteelementwithkeyc

AsIsaidabovemapisareferencetypeIftwomapspointtosameunderlyingdataanychangewillaffectbothofthem

Gofoundation

41

m=make(map[string]string)

m[Hello]=Bonjour

m1=m

m1[Hello]=Salutnowthevalueofm[hello]isSalut

makenewmakedoesmemoryallocationforbuilt-inmodelssuchasmapsliceandchannelwhilenewisfortypesmemoryallocation

new(T)allocateszero-valuetotypeTsmemoryreturnsitsmemoryaddresswhichisthevalueoftypeTByGosdefinitionitreturnsapointerwhichpointstotypeTszero-value

newreturnspointers

Thebuilt-infunctionmake(Targs)hasdifferentpurposesthannew(T)makecanbeusedforslicemapandchannelandreturnsatypeTwithaninitialvalueThereasonfordoingthisisbecausetheunderlyingdataofthesethreetypesmustbeinitializedbeforetheypointtothemForexampleaslicecontainsapointerthatpointstotheunderlyingarraylengthandcapacityBeforethesedataareinitializedsliceisnilsoforslicemapandchannelmakeinitializestheirunderlyingdataandassignssomesuitablevalues

makereturnsnon-zerovalues

Thefollowingpictureshowshownewandmakearedifferent

Figure25Underlyingmemoryallocationofmakeandnew

Zero-valuedoesnotmeanemptyvalueItsthevaluethatvariablesdefaulttoinmostcasesHereisalistofsomezero-values

int0

int80

int320

int640

uint0x0

rune0theactualtypeofruneisint32

byte0x0theactualtypeofbyteisuint8

float320lengthis4byte

float640lengthis8byte

boolfalse

string

LinksDirectoryPrevioussectionHelloGoNextsectionControlstatementsandfunctions

Gofoundation

42

23ControlstatementsandfunctionsInthissectionwearegoingtotalkaboutcontrolstatementsandfunctionoperationsinGo

ControlstatementThegreatestinventioninprogrammingisflowcontrolBecauseofthemyouareabletousesimplecontrolstatementsthatcanbeusedtorepresentcomplexlogicTherearethreecategoriesofflowcontrolconditionalcyclecontrolandunconditionaljump

if

ifwillmostlikelybethemostcommonkeywordinyourprogramsIfitmeetstheconditionsthenitdoessomethinganditdoessomethingelseifnot

ifdoesntneedparenthesesinGo

ifxgt10

fmtPrintln(xisgreaterthan10)

else

fmtPrintln(xislessthanorequalto10)

ThemostusefulthingconcerningifinGoisthatitcanhaveoneinitializationstatementbeforetheconditionalstatementThescopeofthevariablesdefinedinthisinitializationstatementareonlyavailableinsidetheblockofthedefiningif

initializexthencheckifxgreaterthan

ifx=computedValue()xgt10

fmtPrintln(xisgreaterthan10)

else

fmtPrintln(xislessthan10)

thefollowingcodewillnotcompile

fmtPrintln(x)

Useif-elseformultipleconditions

ifinteger==3

fmtPrintln(Theintegerisequalto3)

elseifintegerlt3

fmtPrintln(Theintegerislessthan3)

else

fmtPrintln(Theintegerisgreaterthan3)

gotoGohasagotokeywordbutbecarefulwhenyouuseitgotoreroutesthecontrolflowtoapreviouslydefinedlabelwithinthebodyofsamecodeblock

Controlstatementsandfunctions

43

funcmyFunc()

i=0

Herelabelendswith

fmtPrintln(i)

i++

gotoHerejumptolabelHere

Thelabelnameiscasesensitive

for

foristhemostpowerfulcontrollogicinGoItcanreaddatainloopsanditerativeoperationsjustlikewhile

forexpression1expression2expression3

expression1expression2andexpression3areallexpressionswhereexpression1andexpression3arevariabledefinitionsorreturnvaluesfromfunctionsandexpression2isaconditionalstatementexpression1willbeexecutedoncebeforeloopingandexpression3willbeexecutedaftereachloop

Examplesaremoreusefulthanwords

packagemain

importfmt

funcmain()

sum=0

forindex=0indexlt10index++

sum+=index

fmtPrintln(sumisequaltosum)

Printsumisequalto45

SometimesweneedmultipleassignmentsbutGodoesnthavetheoperatorsoweuseparallelassignmentlikeij=i+1j-1

Wecanomitexpression1andexpression3iftheyarenotnecessary

sum=1

forsumlt1000

sum+=sum

OmitaswellFeelfamiliarYesitsidenticaltowhile

sum=1

forsumlt1000

sum+=sum

TherearetwoimportantoperationsinloopswhicharebreakandcontinuebreakjumpsoutoftheloopandcontinueskipsthecurrentloopandstartsthenextoneIfyouhavenestedloopsusebreakalongwithlabels

Controlstatementsandfunctions

44

forindex=10indexgt0index--

ifindex==5

breakorcontinue

fmtPrintln(index)

breakprints109876

continueprints1098764321

forcanreaddatafromarrayslicemapandstringwhenitisusedtogetherwithrange

forkv=rangemap

fmtPrintln(mapskeyk)

fmtPrintln(mapsvalv)

BecauseGosupportsmulti-valuereturnsandgivescompileerrorswhenyoudontusevaluesthatweredefinedyoumaywanttouse_todiscardcertainreturnvalues

for_v=rangemap

fmtPrintln(mapsvalv)

Withgoyoucanaswellcreateaninfiniteloopwhichisequivalenttowhiletrueinotherlanguges

for

yourlogic

switchSometimesyoumayfindthatyouareusingtoomanyif-elsestatementstoimplementsomelogicwhichmaymakeitdifficulttoreadandmaintaininthefutureThisistheperfecttimetousetheswitchstatementtosolvethisproblem

switchsExpr

caseexpr1

someinstructions

caseexpr2

someotherinstructions

caseexpr3

someotherinstructions

default

othercode

ThetypeofsExprexpr1expr2andexpr3mustbethesameswitchisveryflexibleConditionsdonthavetobeconstantsanditexecutesfromtoptobottomuntilitmatchesconditionsIfthereisnostatementafterthekeywordswitchthenitmatchestrue

i=10

switchi

case1

fmtPrintln(iisequalto1)

case234

fmtPrintln(iisequalto23or4)

case10

fmtPrintln(iisequalto10)

default

fmtPrintln(AllIknowisthatiisaninteger)

Controlstatementsandfunctions

45

InthefifthlineweputmanyvaluesinonecaseandwedontneedtoaddthebreakkeywordattheendofcasesbodyItwilljumpoutoftheswitchbodyonceitmatchedanycaseIfyouwanttocontinuetomatchingmorecasesyouneedtousethefallthroughstatement

integer=6

switchinteger

case4

fmtPrintln(integerlt=4)

fallthrough

case5

fmtPrintln(integerlt=5)

fallthrough

case6

fmtPrintln(integerlt=6)

fallthrough

case7

fmtPrintln(integerlt=7)

fallthrough

case8

fmtPrintln(integerlt=8)

fallthrough

default

fmtPrintln(defaultcase)

Thisprogramprintsthefollowinginformation

integerlt=6

integerlt=7

integerlt=8

defaultcase

FunctionsUsethefunckeywordtodefineafunction

funcfuncName(input1type1input2type2)(output1type1output2type2)

functionbody

multi-valuereturn

returnvalue1value2

Wecanextrapolatethefollowinginformationfromtheexampleabove

UsekeywordfunctodefineafunctionfuncNameFunctionshavezerooneormorethanoneargumentsTheargumenttypecomesaftertheargumentnameandargumentsareseparatedbyFunctionscanreturnmultiplevaluesTherearetworeturnvaluesnamedoutput1andoutput2youcanomittheirnamesandusetheirtypeonlyIfthereisonlyonereturnvalueandyouomittedthenameyoudontneedbracketsforthereturnvaluesIfthefunctiondoesnthavereturnvaluesyoucanomitthereturnparametersaltogetherIfthefunctionhasreturnvaluesyouhavetousethereturnstatementsomewhereinthebodyofthefunction

Letsseeonepracticalexample(calculatemaximumvalue)

Controlstatementsandfunctions

46

packagemain

importfmt

returngreatervaluebetweenaandb

funcmax(abint)int

ifagtb

returna

returnb

funcmain()

x=3

y=4

z=5

max_xy=max(xy)callfunctionmax(xy)

max_xz=max(xz)callfunctionmax(xz)

fmtPrintf(max(dd)=dnxymax_xy)

fmtPrintf(max(dd)=dnxzmax_xz)

fmtPrintf(max(dd)=dnyzmax(yz))callfunctionhere

IntheaboveexampletherearetwoargumentsinthefunctionmaxtheirtypesarebothintsothefirsttypecanbeomittedForinstanceabintinsteadofaintbintThesamerulesapplyforadditionalargumentsNoticeherethatmaxonlyhasonereturnvaluesoweonlyneedtowritethetypeofitsreturnvalue-thisistheshortformofwritingit

Multi-valuereturn

OnethingthatGoisbetteratthanCisthatitsupportsmulti-valuereturns

Wellusethefollowingexamplehere

packagemain

importfmt

returnresultsofA+BandAB

funcSumAndProduct(ABint)(intint)

returnA+BAB

funcmain()

x=3

y=4

xPLUSyxTIMESy=SumAndProduct(xy)

fmtPrintf(d+d=dnxyxPLUSy)

fmtPrintf(dd=dnxyxTIMESy)

Theaboveexamplereturnstwovalueswithoutnames-youhavetheoptionofnamingthemalsoIfwenamedthereturnvalueswewouldjustneedtousereturntoreturnthevaluessincetheyareinitializedinthefunctionautomaticallyNoticethatifyourfunctionsaregoingtobeusedoutsideofthepackagewhichmeansyourfunctionnamesstartwithacapitalletteryoudbetterwritecompletestatementsforreturnitmakesyourcodemorereadable

funcSumAndProduct(ABint)(addintmultipliedint)

add=A+B

multiplied=AB

return

Controlstatementsandfunctions

47

Variadicfunctions

GosupportsfunctionswithavariablenumberofargumentsThesefunctionsarecalledvariadicwhichmeansthefunctionallowsanuncertainnumbersofarguments

funcmyfunc(argint)

arghellipinttellsGothatthisisafunctionthathasvariableargumentsNoticethattheseargumentsaretypeintInthebodyoffunctiontheargbecomesasliceofint

for_n=rangearg

fmtPrintf(Andthenumberisdnn)

Passbyvalueandpointers

Whenwepassanargumenttothefunctionthatwascalledthatfunctionactuallygetsthecopyofourvariablessoanychangewillnotaffecttotheoriginalvariable

Letsseeoneexampleinordertoprovewhatimsaying

packagemain

importfmt

simplefunctiontoadd1toa

funcadd1(aint)int

a=a+1wechangevalueofa

returnareturnnewvalueofa

funcmain()

x=3

fmtPrintln(x=x)shouldprintx=3

x1=add1(x)calladd1(x)

fmtPrintln(x+1=x1)shouldprintx+1=4

fmtPrintln(x=x)shouldprintx=3

CanyouseethatEventhoughwecalledadd1withxtheoriginvalueofxdoesntchange

Thereasonisverysimplewhenwecalledadd1wegaveacopyofxtoitnotthexitself

NowyoumayaskhowIcanpasstherealxtothefunction

WeneedusepointershereWeknowvariablesarestoredinmemoryandtheyhavesomememoryaddressesSoifwewanttochangethevalueofavariablewemustchangeitsmemoryaddressThereforethefunctionadd1hastoknowthememoryaddressofxinordertochangeitsvalueHerewepassampxtothefunctionandchangetheargumentstypetothepointertypeintBeawarethatwepassacopyofthepointernotcopyofvalue

Controlstatementsandfunctions

48

packagemain

importfmt

simplefunctiontoadd1toa

funcadd1(aint)int

a=a+1wechangedvalueofa

returnareturnnewvalueofa

funcmain()

x=3

fmtPrintln(x=x)shouldprintx=3

x1=add1(ampx)calladd1(ampx)passmemoryaddressofx

fmtPrintln(x+1=x1)shouldprintx+1=4

fmtPrintln(x=x)shouldprintx=4

NowwecanchangethevalueofxinthefunctionsWhydoweusepointersWhataretheadvantages

AllowsustousemorefunctionstooperateononevariableLowcostbypassingmemoryaddresses(8bytes)copyisnotanefficientwaybothintermsoftimeandspacetopassvariableschannelsliceandmaparereferencetypessotheyusepointerswhenpassingtofunctionsbydefault(AttentionIfyouneedtochangethelengthofsliceyouhavetopasspointersexplicitly)

deferGohasawelldesignedkeywordcalleddeferYoucanhavemanydeferstatementsinonefunctiontheywillexecuteinreverseorderwhentheprogramexecutestotheendoffunctionsInthecasewheretheprogramopenssomeresourcefilesthesefileswouldhavetobeclosedbeforethefunctioncanreturnwitherrorsLetsseesomeexamples

funcReadWrite()bool

fileOpen(file)

Dosomework

iffailureX

fileClose()

returnfalse

iffailureY

fileClose()

returnfalse

fileClose()

returntrue

WesawsomecodebeingrepeatedseveraltimesdefersolvesthisproblemverywellItdoesntonlyhelpyoutowritecleancodebutalsomakesyourcodemorereadable

Controlstatementsandfunctions

49

funcReadWrite()bool

fileOpen(file)

deferfileClose()

iffailureX

returnfalse

iffailureY

returnfalse

returntrue

IftherearemorethanonedeferstheywillexecutebyreverseorderThefollowingexamplewillprint43210

fori=0ilt5i++

deferfmtPrintf(di)

Functionsasvaluesandtypes

FunctionsarealsovariablesinGowecanusetypetodefinethemFunctionsthathavethesamesignaturecanbeseenasthesametype

typetypeNamefunc(input1inputType1input2inputType2[])(result1resultType1[])

WhatstheadvantageofthisfeatureTheansweristhatitallowsustopassfunctionsasvalues

packagemain

importfmt

typetestIntfunc(int)booldefineafunctiontypeofvariable

funcisOdd(integerint)bool

returninteger2=0

funcisEven(integerint)bool

returninteger2==0

passthefunction`f`asanargumenttoanotherfunction

funcfilter(slice[]intftestInt)[]int

varresult[]int

for_value=rangeslice

iff(value)

result=append(resultvalue)

returnresult

varslice=[]int123457

funcmain()

odd=filter(sliceisOdd)

even=filter(sliceisEven)

fmtPrintln(slice=slice)

fmtPrintln(Oddelementsofsliceareodd)

fmtPrintln(Evenelementsofsliceareeven)

Controlstatementsandfunctions

50

ItsveryusefulwhenweuseinterfacesAsyoucanseetestIntisavariablethathasafunctionastypeandthereturnedvaluesandargumentsoffilterarethesameasthoseoftestIntThereforewecanhavecomplexlogicinourprogramswhilemaintainingflexibilityinourcode

PanicandRecover

Godoesnthavetry-catchstructurelikeJavadoesInsteadofthrowingexceptionsGousespanicandrecovertodealwitherrorsHoweveryoushouldntusepanicverymuchalthoughitspowerful

Panicisabuilt-infunctiontobreakthenormalflowofprogramsandgetintopanicstatusWhenafunctionFcallspanicFwillnotcontinueexecutingbutitsdeferfunctionswillcontinuetoexecuteThenFgoesbacktothebreakpointwhichcausedthepanicstatusTheprogramwillnotterminateuntilallofthesefunctionsreturnwithpanictothefirstlevelofthatgoroutinepaniccanbeproducedbycallingpanicintheprogramandsomeerrorsalsocausepaniclikearrayaccessoutofboundserrors

Recoverisabuilt-infunctiontorecovergoroutinesfrompanicstatusCallingrecoverindeferfunctionsisusefulbecausenormalfunctionswillnotbeexecutedwhentheprogramisinthepanicstatusItcatchespanicvaluesiftheprogramisinthepanicstatusanditgetsniliftheprogramisnotinpanicstatus

Thefollowingexampleshowshowtousepanic

varuser=osGetenv(USER)

funcinit()

ifuser==

panic(novaluefor$USER)

Thefollowingexampleshowshowtocheckpanic

functhrowsPanic(ffunc())(bbool)

deferfunc()

ifx=recover()x=nil

b=true

()

f()iffcausespanicitwillrecover

return

mainfunctionandinitfunction

GohastworetentionswhicharecalledmainandinitwhereinitcanbeusedinallpackagesandmaincanonlybeusedinthemainpackageThesetwofunctionsarenotabletohaveargumentsorreturnvaluesEventhoughwecanwritemanyinitfunctionsinonepackageIstronglyrecommendwritingonlyoneinitfunctionforeachpackage

Goprogramswillcallinit()andmain()automaticallysoyoudontneedtocallthembyyourselfForeverypackagetheinitfunctionisoptionalbutpackagemainhasoneandonlyonemainfunction

ProgramsinitializeandbeginexecutionfromthemainpackageIfthemainpackageimportsotherpackagestheywillbeimportedinthecompiletimeIfonepackageisimportedmanytimesitwillbeonlycompiledonceAfterimportingpackagesprogramswillinitializetheconstantsandvariableswithintheimportedpackagesthenexecutetheinitfunctionifitexistsandsoonAfteralltheotherpackagesareinitializedprogramswillinitializeconstantsandvariablesinthemainpackagethenexecutetheinitfunctioninsidethepackageifitexistsThefollowingfigureshowstheprocess

Figure26FlowofprogramsinitializationinGo

Controlstatementsandfunctions

51

import

WeuseimportveryofteninGoprogramsasfollows

import(

fmt

)

Thenweusefunctionsinthatpackageasfollows

fmtPrintln(helloworld)

fmtisfromGostandardlibraryitislocatedwithin$GOROOTpkgGosupportsthird-partypackagesintwoways

1 RelativepathimportmodelloadpackageinthesamedirectoryIdontrecommendthisway2 Absolutepathimportshorturlmodelloadpackageinpath$GOPATHpkgshorturlmodel

Therearesomespecialoperatorswhenweimportpackagesandbeginnersarealwaysconfusedbytheseoperators

1 DotoperatorSometimeweseepeopleusefollowingwaytoimportpackages

import(

fmt

)

ThedotoperatormeansyoucanomitthepackagenamewhenyoucallfunctionsinsideofthatpackageNowfmtPrintf(Helloworld)becomestoPrintf(Helloworld)

2 AliasoperationItchangesthenameofthepackagethatweimportedwhenwecallfunctionsthatbelongtothatpackage

import(

ffmt

)

NowfmtPrintf(Helloworld)becomestofPrintf(Helloworld)3 _operatorThisistheoperatorthatisdifficulttounderstandwithoutsomeoneexplainingittoyou

import(

databasesql

_githubcomziutekmymysqlgodrv

)

The_operatoractuallymeanswejustwanttoimportthatpackageandexecuteitsinitfunctionandwearenotsureifwewanttousethefunctionsbelongingtothatpackage

LinksDirectoryPrevioussectionGofoundationNextsectionstruct

Controlstatementsandfunctions

52

24struct

structWecandefinenewtypesofcontainersofotherpropertiesorfieldsinGojustlikeinotherprogramminglanguagesForexamplewecancreateatypecalledpersontorepresentapersonwithfieldsnameandageWecallthiskindoftypeastruct

typepersonstruct

namestring

ageint

Lookhoweasyitistodefineastruct

Therearetwofields

nameisastringusedtostoreapersonsnameageisaintusedtostoreapersonsage

Letsseehowtouseit

typepersonstruct

namestring

ageint

varPpersonpispersontype

Pname=AstaxieassignAstaxietothefieldnameofp

Page=25assign25tofieldageofp

fmtPrintf(ThepersonsnameissnPname)accessfieldnameofp

Therearethreemorewaystoinitializeastruct

Assigninitialvaluesbyorder

P=personTom25

Usetheformatfieldvaluetoinitializethestructwithoutorder

P=personage24nameBob

Defineananonymousstructtheninitializeit

P=structnamestringageintAmy18

Letsseeacompleteexample

struct

53

packagemain

importfmt

defineanewtype

typepersonstruct

namestring

ageint

structispassedbyvalue

comparetheageoftwopeoplethenreturntheolderpersonanddifferencesofage

funcOlder(p1p2person)(personint)

ifp1agegtp2age

returnp1p1age-p2age

returnp2p2age-p1age

funcmain()

vartomperson

tomnametomage=Tom18

bob=personage25nameBob

paul=personPaul43

tb_Oldertb_diff=Older(tombob)

tp_Oldertp_diff=Older(tompaul)

bp_Olderbp_diff=Older(bobpaul)

fmtPrintf(Ofsandssisolderbydyearsntomnamebobnametb_Oldernametb_diff)

fmtPrintf(Ofsandssisolderbydyearsntomnamepaulnametp_Oldernametp_diff)

fmtPrintf(Ofsandssisolderbydyearsnbobnamepaulnamebp_Oldernamebp_diff)

embeddedfieldsinstructIvejustintroducedtoyouhowtodefineastructwithfieldnamesandtypeInfactGosupportsfieldswithoutnamesbutwithtypesWecalltheseembeddedfields

Whentheembeddedfieldisastructallthefieldsinthatstructwillimplicitlybethefieldsinthestructinwhichithasbeenembedded

Letsseeoneexample

struct

54

packagemain

importfmt

typeHumanstruct

namestring

ageint

weightint

typeStudentstruct

HumanembeddedfielditmeansStudentstructincludesallfieldsthatHumanhas

specialtystring

funcmain()

instantiateandinitializeastudent

mark=StudentHumanMark25120ComputerScience

accessfields

fmtPrintln(Hisnameismarkname)

fmtPrintln(Hisageismarkage)

fmtPrintln(Hisweightismarkweight)

fmtPrintln(Hisspecialtyismarkspecialty)

modifymarksspecialty

markspecialty=AI

fmtPrintln(Markchangedhisspecialty)

fmtPrintln(Hisspecialtyismarkspecialty)

fmtPrintln(MarkbecomeoldHeisnotanathleteanymore)

markage=46

markweight+=60

fmtPrintln(Hisageismarkage)

fmtPrintln(Hisweightismarkweight)

Figure27EmbeddinginStudentandHuman

WeseethatwecanaccesstheageandnamefieldsinStudentjustlikewecaninHumanThisishowembeddedfieldsworkItsverycoolisntitHoldontheressomethingcoolerYoucanevenuseStudenttoaccessHumaninthisembeddedfield

markHuman=HumanMarcus55220

markHumanage-=1

AllthetypesinGocanbeusedasembeddedfields

struct

55

packagemain

importfmt

typeSkills[]string

typeHumanstruct

namestring

ageint

weightint

typeStudentstruct

Humanstructasembeddedfield

Skillsstringsliceasembeddedfield

intbuilt-intypeasembeddedfield

specialtystring

funcmain()

initializeStudentJane

jane=StudentHumanHumanJane35100specialtyBiology

accessfields

fmtPrintln(Hernameisjanename)

fmtPrintln(Herageisjaneage)

fmtPrintln(Herweightisjaneweight)

fmtPrintln(Herspecialtyisjanespecialty)

modifyvalueofskillfield

janeSkills=[]stringanatomy

fmtPrintln(HerskillsarejaneSkills)

fmtPrintln(Sheacquiredtwonewones)

janeSkills=append(janeSkillsphysicsgolang)

fmtPrintln(HerskillsnowarejaneSkills)

modifyembeddedfield

janeint=3

fmtPrintln(Herpreferrednumberisjaneint)

Intheaboveexamplewecanseethatalltypescanbeembeddedfieldsandwecanusefunctionstooperateonthem

ThereisonemoreproblemhoweverIfHumanhasafieldcalledphoneandStudenthasafieldwithsamenamewhatshouldwedo

GouseaverysimplewaytosolveitTheouterfieldsgetupperaccesslevelswhichmeanswhenyouaccessstudentphonewewillgetthefieldcalledphoneinstudentnottheoneintheHumanstructThisfeaturecanbesimplyseenasfieldoverloading

struct

56

packagemain

importfmt

typeHumanstruct

namestring

ageint

phonestringHumanhasphonefield

typeEmployeestruct

Human

specialtystring

phonestringphoneinemployee

funcmain()

Bob=EmployeeHumanBob34777-444-XXXXDesigner333-222

fmtPrintln(BobsworkphoneisBobphone)

fmtPrintln(BobspersonalphoneisBobHumanphone)

LinksDirectoryPrevioussectionControlstatementsandfunctionsNextsectionObject-oriented

struct

57

Object-orientedWetalkedaboutfunctionsandstructsinthelasttwosectionsbutdidyoueverconsiderusingfunctionsasfieldsofastructInthissectionIwillintroduceyoutoanotherformoffunctionthathasareceiverwhichiscalledamethod

methodSupposeyoudefinearectanglestructandyouwanttocalculateitsareaWedtypicallyusethefollowingcodetoachievethisgoal

packagemain

importfmt

typeRectanglestruct

widthheightfloat64

funcarea(rRectangle)float64

returnrwidthrheight

funcmain()

r1=Rectangle122

r2=Rectangle94

fmtPrintln(Areaofr1isarea(r1))

fmtPrintln(Areaofr2isarea(r2))

TheaboveexamplecancalculatearectanglesareaWeusethefunctioncalledareabutitsnotamethodoftherectanglestruct(likeclassmethodsinclassicobject-orientedlanguages)Thefunctionandstructaretwoindependentthingsasyoumaynotice

ItsnotaproblemsofarHoweverifyoualsohavetocalculatetheareaofacirclesquarepentagonoranyotherkindofshapeyouaregoingtoneedtoaddadditionalfunctionswithverysimilarnames

Figure28Relationshipbetweenfunctionandstruct

ObviouslythatsnotcoolAlsotheareashouldreallybethepropertyofacircleorrectangle

ThisiswhereamethodcomestoplayThemethodisafunctionaffiliatedwithatypeIthassimilarsyntaxasfunctionexceptafterthefunckeywordhasaparametercalledthereceiverwhichisthemainbodyofthatmethod

UsingthesameexampleRectangleArea()belongsdirectlytorectangleinsteadofasaperipheralfunctionMorespecificallylengthwidthandArea()allbelongtorectangle

AsRobPikesaid

Amethodisafunctionwithanimplicitfirstargumentcalledareceiver

Syntaxofmethod

func(rReceiverType)funcName(parameters)(results)

Letschangeourexampleusingmethodinstead

Object-oriented

58

packagemain

import(

fmt

math

)

typeCirclestruct

radiusfloat64

typeRectanglestruct

widthheightfloat64

method

func(cCircle)Area()float64

returncradiuscradiusmathPi

method

func(rRectangle)Area()float64

returnrwidthrheight

funcmain()

c1=Circle10

c2=Circle25

r1=Rectangle94

r2=Rectangle122

fmtPrintln(Areaofc1isc1Area())

fmtPrintln(Areaofc2isc2Area())

fmtPrintln(Areaofr1isr1Area())

fmtPrintln(Areaofr2isr2Area())

Notesforusingmethods

IfthenameofmethodsarethesamebuttheydontsharethesamereceiverstheyarenotthesameMethodsareabletoaccessfieldswithinreceiversUsetocallamethodinthestructthesamewayfieldsarecalled

Figure29Methodsaredifferentindifferentstructs

IntheexampleabovetheArea()methodsbelongtobothRectangleandCirclerespectivelysothereceiversareRectangleandCircle

OnethingthatsworthnotingisthatthemethodwithadottedlinemeansthereceiverispassedbyvaluenotbyreferenceThedifferencebetweenthemisthatamethodcanchangeitsreceiversvalueswhenthereceiverispassedbyreferenceanditgetsacopyofthereceiverwhenthereceiverispassedbyvalue

CanthereceiveronlybeastructOfcoursenotAnytypecanbethereceiverofamethodYoumaybeconfusedaboutcustomizedtypesStructisaspecialkindofcustomizedtype-therearemorecustomizedtypes

Usethefollowingformattodefineacustomizedtype

typetypeNametypeLiteral

Examplesofcustomizedtypes

Object-oriented

59

typeageint

typemoneyfloat32

typemonthsmap[string]int

m=months

January31

February28

December31

IhopethatyouknowhowtousecustomizedtypesnowSimilartotypedefinCweuseagestosubstituteintintheaboveexample

Letsgetbacktotalkingaboutmethod

Youcanuseasmanymethodsincustomtypesasyouwant

packagemain

importfmt

const(

WHITE=iota

BLACK

BLUE

RED

YELLOW

)

typeBoxstruct

widthheightdepthfloat64

colorColor

typeColorbyte

typeBoxList[]Boxasliceofboxes

method

func(bBox)Volume()float64

returnbwidthbheightbdepth

methodwithapointerreceiver

func(bBox)SetColor(cColor)

bcolor=c

method

func(blBoxList)BiggestsColor()Color

v=000

k=Color(WHITE)

for_b=rangebl

ifbVolume()gtv

v=bVolume()

k=bcolor

returnk

method

func(blBoxList)PaintItBlack()

fori_=rangebl

bl[i]SetColor(BLACK)

method

func(cColor)String()string

Object-oriented

60

strings=[]stringWHITEBLACKBLUEREDYELLOW

returnstrings[c]

funcmain()

boxes=BoxList

Box444RED

Box10101YELLOW

Box1120BLACK

Box10101BLUE

Box10301WHITE

Box202020YELLOW

fmtPrintf(Wehavedboxesinoursetnlen(boxes))

fmtPrintln(Thevolumeofthefirstoneisboxes[0]Volume()cmsup3)

fmtPrintln(Thecolorofthelastoneisboxes[len(boxes)-1]colorString())

fmtPrintln(ThebiggestoneisboxesBiggestsColor()String())

Letspaintthemallblack

boxesPaintItBlack()

fmtPrintln(Thecolorofthesecondoneisboxes[1]colorString())

fmtPrintln(ObviouslynowthebiggestoneisboxesBiggestsColor()String())

Wedefinesomeconstantsandcustomizedtypes

UseColorasaliasofbyteDefineastructBoxwhichhasfieldsheightwidthlengthandcolorDefineastructBoxListwhichhasBoxasitsfield

Thenwedefinedsomemethodsforourcustomizedtypes

Volume()usesBoxasitsreceiverandreturnsthevolumeofBoxSetColor(cColor)changesBoxscolorBiggestsColor()returnsthecolorwhichhasthebiggestvolumePaintItBlack()setscolorforallBoxinBoxListtoblackString()useColorasitsreceiverreturnsthestringformatofcolorname

IsitmuchclearerwhenweusewordstodescribeourrequirementsWeoftenwriteourrequirementsbeforewestartcoding

Usepointerasreceiver

LetstakealookatSetColormethodItsreceiverisapointerofBoxYesyoucanuseBoxasareceiverWhydoweuseapointerhereBecausewewanttochangeBoxscolorinthismethodThusifwedontuseapointeritwillonlychangethevalueinsideacopyofBox

Ifweseethatareceiveristhefirstargumentofamethoditsnothardtounderstandhowitworks

Youmightbeaskingwhywearentusing(b)Color=cinsteadofbColor=cintheSetColor()methodEitheroneisOKherebecauseGoknowshowtointerprettheassignmentDoyouthinkGoismorefascinatingnow

Youmayalsobeaskingwhetherweshoulduse(ampbl[i])SetColor(BLACK)inPaintItBlackbecausewepassapointertoSetColorAgaineitheroneisOKbecauseGoknowshowtointerpretit

Inheritanceofmethod

WelearnedaboutinheritanceoffieldsinthelastsectionSimilarlywealsohavemethodinheritanceinGoIfananonymousfieldhasmethodsthenthestructthatcontainsthefieldwillhaveallthemethodsfromitaswell

Object-oriented

61

packagemain

importfmt

typeHumanstruct

namestring

ageint

phonestring

typeStudentstruct

Humananonymousfield

schoolstring

typeEmployeestruct

Human

companystring

defineamethodinHuman

func(hHuman)SayHi()

fmtPrintf(HiIamsyoucancallmeonsnhnamehphone)

funcmain()

sam=EmployeeHumanSam45111-888-XXXXGolangInc

mark=StudentHumanMark25222-222-YYYYMIT

samSayHi()

markSayHi()

MethodOverridingIfwewantEmployeetohaveitsownmethodSayHiwecandefineamethodthathasthesamenameinEmployeeanditwillhideSayHiinHumanwhenwecallit

Object-oriented

62

packagemain

importfmt

typeHumanstruct

namestring

ageint

phonestring

typeStudentstruct

Human

schoolstring

typeEmployeestruct

Human

companystring

func(hHuman)SayHi()

fmtPrintf(HiIamsyoucancallmeonsnhnamehphone)

func(eEmployee)SayHi()

fmtPrintf(HiIamsIworkatsCallmeonsnename

ecompanyephone)Yesyoucansplitinto2lineshere

funcmain()

sam=EmployeeHumanSam45111-888-XXXXGolangInc

mark=StudentHumanMark25222-222-YYYYMIT

samSayHi()

markSayHi()

YouareabletowriteanObject-orientedprogramnowandmethodsuseruleofcapitallettertodecidewhetherpublicorprivateaswell

LinksDirectoryPrevioussectionstructNextsectioninterface

Object-oriented

63

26Interface

InterfaceOneofthesubtlestdesignfeaturesinGoareinterfacesAfterreadingthissectionyouwilllikelybeimpressedbytheirimplementation

Whatisaninterface

Inshortaninterfaceisasetofmethodsthatweusetodefineasetofactions

LiketheexamplesinprevioussectionsbothStudentandEmployeecanSayHi()buttheydontdothesamething

LetsdosomemoreworkWelladdonemoremethodSing()tothemalongwiththeBorrowMoney()methodtoStudentandtheSpendSalary()methodtoEmployee

NowStudenthasthreemethodscalledSayHi()Sing()andBorrowMoney()andEmployeehasSayHi()Sing()andSpendSalary()

ThiscombinationofmethodsiscalledaninterfaceandisimplementedbybothStudentandEmployeeSoStudentandEmployeeimplementtheinterfaceSayHi()andSing()AtthesametimeEmployeedoesntimplementtheinterfaceBorrowMoney()andStudentdoesntimplementtheinterfaceSpendSalary()ThisisbecauseEmployeedoesnthavethemethodBorrowMoney()andStudentdoesnthavethemethodSpendSalary()

TypeofInterfaceAninterfacedefinesasetofmethodssoifatypeimplementsallthemethodswesaythatitimplementstheinterface

interface

64

typeHumanstruct

namestring

ageint

phonestring

typeStudentstruct

Human

schoolstring

loanfloat32

typeEmployeestruct

Human

companystring

moneyfloat32

defineinterfaces

typeMeninterface

SayHi()

Sing(lyricsstring)

Guzzle(beerSteinstring)

typeYoungChapinterface

SayHi()

Sing(songstring)

BorrowMoney(amountfloat32)

typeElderlyGentinterface

SayHi()

Sing(songstring)

SpendSalary(amountfloat32)

func(hHuman)SayHi()

fmtPrintf(HiIamsyoucancallmeonsnhnamehphone)

func(hHuman)Sing(lyricsstring)

fmtPrintln(Lalalalalalalalalalalyrics)

func(hHuman)Guzzle(beerSteinstring)

fmtPrintln(GuzzleGuzzleGuzzlebeerStein)

EmployeeoverloadsSayHi

func(eEmployee)SayHi()

fmtPrintf(HiIamsIworkatsCallmeonsnename

ecompanyephone)Yesyoucansplitinto2lineshere

func(sStudent)BorrowMoney(amountfloat32)

sloan+=amount(againandagainand)

func(eEmployee)SpendSalary(amountfloat32)

emoney-=amountMorevodkapleaseGetmethroughtheday

Weknowthataninterfacecanbeimplementedbyanytypeandonetypecanimplementmanyinterfacessimultaneously

Notethatanytypeimplementstheemptyinterfaceinterfacebecauseitdoesnthaveanymethodsandalltypeshavezeromethodsbydefault

Valueofinterface

interface

65

SowhatkindofvaluescanbeputintheinterfaceIfwedefineavariableasatypeinterfaceanytypethatimplementstheinterfacecanassignedtothisvariable

LiketheaboveexampleifwedefineavariablemasinterfaceMenthenanyoneofStudentHumanorEmployeecanbeassignedtomSowecouldhaveasliceofMenandanytypethatimplementsinterfaceMencanassigntothissliceBeawarehoweverthatthesliceofinterfacedoesnthavethesamebehaviorasasliceofothertypes

packagemain

importfmt

typeHumanstruct

namestring

ageint

phonestring

typeStudentstruct

Human

schoolstring

loanfloat32

typeEmployeestruct

Human

companystring

moneyfloat32

InterfaceMenimplementedbyHumanStudentandEmployee

typeMeninterface

SayHi()

Sing(lyricsstring)

method

func(hHuman)SayHi()

fmtPrintf(HiIamsyoucancallmeonsnhnamehphone)

method

func(hHuman)Sing(lyricsstring)

fmtPrintln(Lalalalalyrics)

method

func(eEmployee)SayHi()

fmtPrintf(HiIamsIworkatsCallmeonsnename

ecompanyephone)Yesyoucansplitinto2lineshere

funcmain()

mike=StudentHumanMike25222-222-XXXMIT000

paul=StudentHumanPaul26111-222-XXXHarvard100

sam=EmployeeHumanSam36444-222-XXXGolangInc1000

tom=EmployeeHumanSam36444-222-XXXThingsLtd5000

defineinterfacei

variMen

icanstoreStudent

i=mike

fmtPrintln(ThisisMikeaStudent)

iSayHi()

iSing(Novemberrain)

icanstoreEmployee

i=tom

fmtPrintln(ThisisTomanEmployee)

iSayHi()

interface

66

iSing(Borntobewild)

sliceofMen

fmtPrintln(LetsuseasliceofMenandseewhathappens)

x=make([]Men3)

thesethreeelementsaredifferenttypesbuttheyallimplementedinterfaceMen

x[0]x[1]x[2]=paulsammike

for_value=rangex

valueSayHi()

Aninterfaceisasetofabstractmethodsandcanbeimplementedbynon-interfacetypesItcannotthereforeimplementitself

Emptyinterface

AnemptyinterfaceisaninterfacethatdoesntcontainanymethodssoalltypesimplementanemptyinterfaceThisfactisveryusefulwhenwewanttostorealltypesatsomepointandissimilartovoidinC

defineaasemptyinterface

varvoidinterface

vars

i=5

s=Helloworld

acanstorevalueofanytype

void=i

void=s

Ifafunctionusesanemptyinterfaceasitsargumenttypeitcanacceptanytypeifafunctionusesemptyinterfaceasitsreturnvaluetypeitcanreturnanytype

Methodargumentsofaninterface

AnyvariablecanbeusedinaninterfaceSohowcanweusethisfeaturetopassanytypeofvariabletoafunction

ForexampleweusefmtPrintlnalotbuthaveyouevernoticedthatitcanacceptanytypeofargumentLookingattheopensourcecodeoffmtweseethefollowingdefinition

typeStringerinterface

String()string

ThismeansanytypethatimplementsinterfaceStringercanbepassedtofmtPrintlnasanargumentLetsproveit

interface

67

packagemain

import(

fmt

strconv

)

typeHumanstruct

namestring

ageint

phonestring

HumanimplementsfmtStringer

func(hHuman)String()string

returnName+hname+Age+strconvItoa(hage)+yearsContact+hphone

funcmain()

Bob=HumanBob39000-7777-XXX

fmtPrintln(ThisHumanisBob)

LookingbacktotheexampleofBoxyouwillfindthatColorimplementsinterfaceStringeraswellsoweareabletocustomizetheprintformatIfwedontimplementthisinterfacefmtPrintlnprintsthetypewithitsdefaultformat

fmtPrintln(ThebiggestoneisboxesBiggestsColor()String())

fmtPrintln(ThebiggestoneisboxesBiggestsColor())

AttentionIfthetypeimplementedtheinterfaceerrorfmtwillcallError()soyoudonthavetoimplementStringeratthispoint

TypeofvariableinaninterfaceIfavariableisthetypethatimplementsaninterfaceweknowthatanyothertypethatimplementsthesameinterfacecanbeassignedtothisvariableThequestionishowcanweknowthespecifictypestoredintheinterfaceTherearetwowayswhichIwillshowyou

AssertionofComma-okpattern

Gohasthesyntaxvalueok=element(T)ThischeckstoseeifthevariableisthetypethatweexpectwherevalueisthevalueofthevariableokisavariableofbooleantypeelementistheinterfacevariableandtheTisthetypeofassertion

Iftheelementisthetypethatweexpectokwillbetruefalseotherwise

Letsuseanexampletoseemoreclearly

interface

68

packagemain

import(

fmt

strconv

)

typeElementinterface

typeList[]Element

typePersonstruct

namestring

ageint

func(pPerson)String()string

return(name+pname+-age+strconvItoa(page)+years)

funcmain()

list=make(List3)

list[0]=1anint

list[1]=Helloastring

list[2]=PersonDennis70

forindexelement=rangelist

ifvalueok=element(int)ok

fmtPrintf(list[d]isanintanditsvalueisdnindexvalue)

elseifvalueok=element(string)ok

fmtPrintf(list[d]isastringanditsvalueissnindexvalue)

elseifvalueok=element(Person)ok

fmtPrintf(list[d]isaPersonanditsvalueissnindexvalue)

else

fmtPrintf(list[d]isofadifferenttypenindex)

Itsquiteeasytousethispatternbutifwehavemanytypestotestwedbetteruseswitch

switchtest

Letsuseswitchtorewritetheaboveexample

interface

69

packagemain

import(

fmt

strconv

)

typeElementinterface

typeList[]Element

typePersonstruct

namestring

ageint

func(pPerson)String()string

return(name+pname+-age+strconvItoa(page)+years)

funcmain()

list=make(List3)

list[0]=1anint

list[1]=Helloastring

list[2]=PersonDennis70

forindexelement=rangelist

switchvalue=element(type)

caseint

fmtPrintf(list[d]isanintanditsvalueisdnindexvalue)

casestring

fmtPrintf(list[d]isastringanditsvalueissnindexvalue)

casePerson

fmtPrintf(list[d]isaPersonanditsvalueissnindexvalue)

default

fmtPrintln(list[d]isofadifferenttypeindex)

Onethingyoushouldrememberisthatelement(type)cannotbeusedoutsideoftheswitchbodywhichmeansinthatcaseyouhavetousethecomma-okpattern

Embeddedinterfaces

ThemostbeautifulthingisthatGohasalotofbuilt-inlogicsyntaxsuchasanonymousfieldsinstructNotsuprisinglywecanuseinterfacesasanonymousfieldsaswellbutwecallthemEmbeddedinterfacesHerewefollowthesamerulesasanonymousfieldsMorespecificallyifaninterfacehasanotherinterfaceembeddedwithinititwillbehaveasifithasallthemethodsthattheembeddedinterfacehas

Wecanseethatthesourcefileincontainerheaphasthefollowingdefinition

typeInterfaceinterface

sortInterfaceembeddedsortInterface

Push(xinterface)aPushmethodtopushelementsintotheheap

Pop()interfaceaPopmethodthatpopselementsfromtheheap

WeseethatsortInterfaceisanembeddedinterfacesotheaboveInterfacehasthethreemethodscontainedwithinthesortInterfaceimplicitly

interface

70

typeInterfaceinterface

Lenisthenumberofelementsinthecollection

Len()int

Lessreturnswhethertheelementwithindexishouldsort

beforetheelementwithindexj

Less(ijint)bool

Swapswapstheelementswithindexesiandj

Swap(ijint)

AnotherexampleistheioReadWriterinpackageio

ioReadWriter

typeReadWriterinterface

Reader

Writer

Reflection

ReflectioninGoisusedfordetermininginformationatruntimeWeusethereflectpackageandTheLawsofReflectionpostexplainshowreflectworksinGo

TherearethreestepsinvolvedwhenusingreflectFirstweneedtoconvertaninterfacetoreflecttypes(reflectTypeorreflectValuethisdependsonthesituation)

t=reflectTypeOf(i)getmeta-dataintypeiandusettogetallelements

v=reflectValueOf(i)getactualvalueintypeiandusevtochangeitsvalue

Afterthatwecanconvertthereflectedtypestogetthevaluesthatweneed

varxfloat64=34

t=reflectTypeOf(x)

v=reflectValueOf(x)

fmtPrintln(typet)

fmtPrintln(valuev)

fmtPrintln(kindisfloat64vKind()==reflectFloat64)

FinallyifwewanttochangethevaluesofthereflectedtypesweneedtomakeitmodifiableAsdiscussedearlierthereisadifferencebetweenpassbyvalueandpassbyreferenceThefollowingcodewillnotcompile

varxfloat64=34

v=reflectValueOf(x)

vSetFloat(71)

Insteadwemustusethefollowingcodetochangethevaluesfromreflecttypes

varxfloat64=34

p=reflectValueOf(ampx)

v=pElem()

vSetFloat(71)

Wehavejustdiscussedthebasicsofreflectionhoweveryoumustpracticemoreinordertounderstandmore

Links

interface

71

DirectoryPrevioussectionObject-orientedNextsectionConcurrency

interface

72

ConcurrencyItissaidthatGoistheCofthe21stcenturyIthinktherearetworeasonsforitFirstGoisasimplelanguageSecondconcurrencyisahottopicintodaysworldandGosupportsthisfeatureatthelanguagelevel

goroutinegoroutinesandconcurrencyarebuiltintothecoredesignofGoTheyresimilartothreadsbutworkdifferentlyGoalsogivesyoufullsupporttosharingmemoryinyourgoroutinesOnegoroutineusuallyuses4~5KBofstackmemoryThereforeitsnothardtorunthousandsofgoroutinesonasinglecomputerAgoroutineismorelightweightmoreefficientandmoreconvenientthansystemthreads

goroutinesrunonthethreadmanageratruntimeinGoWeusethegokeywordtocreateanewgoroutinewhichisafunctionattheunderlyinglevel(main()isagoroutine)

gohello(abc)

Letsseeanexample

packagemain

import(

fmt

runtime

)

funcsay(sstring)

fori=0ilt5i++

runtimeGosched()

fmtPrintln(s)

funcmain()

gosay(world)createanewgoroutine

say(hello)currentgoroutine

Output

hello

world

hello

world

hello

world

hello

world

hello

WeseethatitsveryeasytouseconcurrencyinGobyusingthekeywordgoIntheaboveexamplethesetwogoroutinessharesomememorybutwewouldbetterofffollowingthedesignrecipeDontuseshareddatatocommunicateusecommunicationtosharedata

runtimeGosched()meanslettheCPUexecuteothergoroutinesandcomebackatsomepoint

InGo15theruntimenowsetsthedefaultnumberofthreadstorunsimultaneouslydefinedbyGOMAXPROCStothenumberofcoresavailableontheCPU

Concurrency

73

BeforeGo15ThescheduleronlyusesonethreadtorunallgoroutineswhichmeansitonlyimplementsconcurrencyIfyouwanttousemoreCPUcoresinordertotakeadvantageofparallelprocessingyouhavetocallruntimeGOMAXPROCS(n)tosetthenumberofcoresyouwanttouseIfnlt1itchangesnothing

channelsgoroutinesruninthesamememoryaddressspacesoyouhavetomaintainsynchronizationwhenyouwanttoaccesssharedmemoryHowdoyoucommunicatebetweendifferentgoroutinesGousesaverygoodcommunicationmechanismcalledchannelAchannelisliketwo-waypipelineinUnixshellsusechanneltosendorreceivedataTheonlydatatypethatcanbeusedinchannelsisthetypechannelandthekeywordchanBeawarethatyouhavetousemaketocreateanewchannel

ci=make(chanint)

cs=make(chanstring)

cf=make(chaninterface)

channelusestheoperatorlt-tosendorreceivedata

chlt-vsendvtochannelch

v=lt-chreceivedatafromchandassigntov

Letsseemoreexamples

packagemain

importfmt

funcsum(a[]intcchanint)

total=0

for_v=rangea

total+=v

clt-totalsendtotaltoc

funcmain()

a=[]int728-940

c=make(chanint)

gosum(a[len(a)2]c)

gosum(a[len(a)2]c)

xy=lt-clt-creceivefromc

fmtPrintln(xyx+y)

SendingandreceivingdatainchannelsblocksbydefaultsoitsmucheasiertousesynchronousgoroutinesWhatImeanbyblockisthatagoroutinewillnotcontinuewhenreceivingdatafromanemptychannelie(value=lt-ch)untilothergoroutinessenddatatothischannelOntheotherhandthegoroutinewillnotcontinueuntilthedataitsendstoachannelie(chlt-5)isreceived

BufferedchannelsIintroducednon-bufferedchannelsaboveGoalsohasbufferedchannelsthatcanstoremorethanasingleelementForexamplech=make(chanbool4)herewecreateachannelthatcanstore4booleanelementsSointhischannelweareabletosend4elementsintoitwithoutblockingbutthegoroutinewillbeblockedwhenyoutrytosendafifthelementandnogoroutinereceivesit

Concurrency

74

ch=make(chantypen)

n==0non-buffer(block)

ngt0buffer(non-blockuntilnelementsinthechannel)

Youcantrythefollowingcodeonyourcomputerandchangesomevalues

packagemain

importfmt

funcmain()

c=make(chanint2)change2to1willhaveruntimeerrorbut3isfine

clt-1

clt-2

fmtPrintln(lt-c)

fmtPrintln(lt-c)

RangeandCloseWecanuserangetooperateonbufferchannelsasinsliceandmap

packagemain

import(

fmt

)

funcfibonacci(nintcchanint)

xy=11

fori=0iltni++

clt-x

xy=yx+y

close(c)

funcmain()

c=make(chanint10)

gofibonacci(cap(c)c)

fori=rangec

fmtPrintln(i)

fori=rangecwillnotstopreadingdatafromchanneluntilthechannelisclosedWeusethekeywordclosetoclosethechannelinaboveexampleItsimpossibletosendorreceivedataonaclosedchannelyoucanusevok=lt-chtotestifachannelisclosedIfokreturnsfalseitmeansthethereisnodatainthatchannelanditwasclosed

Remembertoalwaysclosechannelsinproducersandnotinconsumersoritsveryeasytogetintopanicstatus

AnotherthingyouneedtorememberisthatchannelsarenotlikefilesYoudonthavetoclosethemfrequentlyunlessyouaresurethechanneliscompletelyuselessoryouwanttoexitrangeloops

SelectIntheaboveexamplesweonlyuseonechannelbuthowcanwedealwithmorethanonechannelGohasakeywordcalledselecttolistentomanychannels

Concurrency

75

selectisblockingbydefaultanditcontinuestoexecuteonlywhenoneofchannelshasdatatosendorreceiveIfseveralchannelsarereadytouseatthesametimeselectchooseswhichtoexecuterandomly

packagemain

importfmt

funcfibonacci(cquitchanint)

xy=11

for

select

caseclt-x

xy=yx+y

caselt-quit

fmtPrintln(quit)

return

funcmain()

c=make(chanint)

quit=make(chanint)

gofunc()

fori=0ilt10i++

fmtPrintln(lt-c)

quitlt-0

()

fibonacci(cquit)

selecthasadefaultcaseaswelljustlikeswitchWhenallthechannelsarenotreadyforuseitexecutesthedefaultcase(itdoesntwaitforthechannelanymore)

select

casei=lt-c

usei

default

executesherewhencisblocked

TimeoutSometimesagoroutinebecomesblockedHowcanweavoidthistopreventthewholeprogramfromblockingItssimplewecansetatimeoutintheselect

funcmain()

c=make(chanint)

o=make(chanbool)

gofunc()

for

select

casev=lt-c

println(v)

caselt-timeAfter(5timeSecond)

println(timeout)

olt-true

break

()

lt-o

Concurrency

76

RuntimegoroutineThepackageruntimehassomefunctionsfordealingwithgoroutines

runtimeGoexit()

Exitsthecurrentgoroutinebutdeferedfunctionswillbeexecutedasusual

runtimeGosched()

Letstheschedulerexecuteothergoroutinesandcomesbackatsomepoint

runtimeNumCPU()int

ReturnsthenumberofCPUcores

runtimeNumGoroutine()int

Returnsthenumberofgoroutines

runtimeGOMAXPROCS(nint)int

SetshowmanyCPUcoresyouwanttouse

LinksDirectoryPrevioussectioninterfaceNextsectionSummary

Concurrency

77

28SummaryInthischapterwemainlyintroducedthe25GokeywordsLetsreviewwhattheyareandwhattheydo

breakdefaultfuncinterfaceselect

casedefergomapstruct

chanelsegotopackageswitch

constfallthroughifrangetype

continueforimportreturnvar

varandconstareusedtodefinevariablesandconstantspackageandimportareforpackageusefuncisusedtodefinefunctionsandmethodsreturnisusedtoreturnvaluesinfunctionsormethodsdeferisusedtodefinedeferfunctionsgoisusedtostartanewgoroutineselectisusedtoswitchovermultiplechannelsforcommunicationinterfaceisusedtodefineinterfacesstructisusedtodefinespecialcustomizedtypesbreakcasecontinueforfallthroughelseifswitchgotoanddefaultwereintroducedinsection23chanisthetypeofchannelforcommunicationamonggoroutinestypeisusedtodefinecustomizedtypesmapisusedtodefinemapwhichissimilartohashtablesinotherlanguagesrangeisusedforreadingdatafromslicemapandchannel

Ifyouunderstandhowtousethese25keywordsyouvelearnedalotofGoalready

LinksDirectoryPrevioussectionConcurrencyNextchapterWebfoundation

Summary

78

3WebfoundationThereasonyouarereadingthisbookisthatyouwanttolearntobuildwebapplicationsinGoAsIvesaidbeforeGoprovidesmanypowerfulpackageslikehttpThesepackagescanhelpyoualotwhentryingtobuildwebapplicationsIllteachyoueverythingyouneedtoknowinthefollowingchaptersandwelltalkaboutsomeconceptsofthewebandhowtorunwebapplicationsinGointhischapter

LinksDirectoryPreviouschapterChapter2SummaryNextsectionWebworkingprinciples

Webfoundation

79

WebworkingprinciplesEverytimeyouopenyourbrowserstypesomeURLsandpressenteryouwillseebeautifulwebpagesappearonyourscreenButdoyouknowwhatishappeningbehindthesesimpleactions

NormallyyourbrowserisaclientAfteryoutypeaURLittakesthehostpartoftheURLandsendsittoaDomainNameServer(DNS)inordertogettheIPaddressofthehostThenitconnectstotheIPaddressandaskstosetupaTCPconnectionThebrowsersendsHTTPrequeststhroughtheconnectionTheserverhandlesthemandreplieswithHTTPresponsescontainingthecontentthatmakeupthewebpageFinallythebrowserrendersthebodyofthewebpageanddisconnectsfromtheserver

Figure31Processesofusersvisitawebsite

AwebserveralsoknownasanHTTPserverusestheHTTPprotocoltocommunicatewithclientsAllwebbrowserscanbeconsideredclients

Wecandividethewebsworkingprinciplesintothefollowingsteps

ClientusesTCPIPprotocoltoconnecttoserverClientsendsHTTPrequestpackagestoserverServerreturnsHTTPresponsepackagestoclientIftherequestedresourcesincludedynamicscriptsservercallsscriptenginefirstClientdisconnectsfromserverstartsrenderingHTML

ThisisasimpleworkflowofHTTPaffairs-noticethattheserverclosesitsconnectionsafteritsendsdatatotheclientsthenwaitsforthenextrequest

URLandDNSresolutionWealwaysuseURLstoaccesswebpagesbutdoyouknowhowURLswork

ThefullnameofaURLisUniformResourceLocatorItsfordescribingresourcesontheinternetanditsbasicformisasfollows

schemehost[port]path[query-string][anchor]

schemeassignunderlyingprotocol(suchasHTTPHTTPSFTP)

hostIPordomainnameofHTTPserver

portdefaultportis80anditcanbeomittedinthiscase

IfyouwanttouseotherportsyoumustspecifywhichportForexample

httpwwwcnblogscom8080

pathresourcespath

query-stringdataaresenttoserver

anchoranchor

DNSisanabbreviationofDomainNameSystemItsthenamingsystemforcomputernetworkservicesanditconvertsdomainnamestoactualIPaddressesjustlikeatranslator

Figure32DNSworkingprinciples

TounderstandmoreaboutitsworkingprincipleletsseethedetailedDNSresolutionprocessasfollows

1 AftertypingthedomainnamewwwqqcominthebrowsertheoperatingsystemwillcheckifthereareanymappingrelationshipsinthehostsfilesforthisdomainnameIfsothenthedomainnameresolutioniscomplete

2 IfnomappingrelationshipsexistinthehostsfilestheoperatingsystemwillcheckifanycacheexistsintheDNSIfso

Webworkingprinciples

80

thenthedomainnameresolutioniscomplete3 IfnomappingrelationshipsexistinboththehostandDNScachetheoperatingsystemfindsthefirstDNSresolution

serverinyourTCPIPsettingswhichislikelyyourlocalDNSserverWhenthelocalDNSserverreceivesthequeryifthedomainnamethatyouwanttoqueryiscontainedwithinthelocalconfigurationofitsregionalresourcesitreturnstheresultstotheclientThisDNSresolutionisauthoritative

4 IfthelocalDNSserverdoesntcontainthedomainnamebutamappingrelationshipexistsinthecachethelocalDNSservergivesbackthisresulttotheclientThisDNSresolutionisnotauthoritative

5 IfthelocalDNSservercannotresolvethisdomainnameeitherbyconfigurationofregionalresourcesorcacheitwillproceedtothenextstepwhichdependsonthelocalDNSserverssettings-IfthelocalDNSserverdoesntenableforwardingitroutestherequesttotherootDNSserverthenreturnstheIPaddressofatoplevelDNSserverwhichmayknowthedomainnamecominthiscaseIfthefirsttoplevelDNSserverdoesntrecognizethedomainnameitagainreroutestherequesttothenexttoplevelDNSserveruntilitreachesonethatrecognizesthedomainnameThenthetoplevelDNSserverasksthisnextlevelDNSserverfortheIPaddresscorrespondingtowwwqqcom-IfthelocalDNSserverhasforwardingenableditsendstherequesttoanupperlevelDNSserverIftheupperlevelDNSserveralsodoesntrecognizethedomainnamethentherequestkeepsgettingreroutedtohigherlevelsuntilitfinallyreachesaDNSserverwhichrecognizesthedomainname

WhetherornotthelocalDNSserverenablesforwardingtheIPaddressofthedomainnamealwaysreturnstothelocalDNSserverandthelocalDNSserversendsitbacktotheclient

Figure33DNSresolutionworkflow

RecursivequeryprocesssimplymeansthattheenquirerschangeintheprocessEnquirersdonotchangeinIterativequeryprocesses

NowweknowclientsgetIPaddressesintheendsothebrowsersarecommunicatingwithserversthroughIPaddresses

HTTPprotocolTheHTTPprotocolisacorepartofwebservicesItsimportanttoknowwhattheHTTPprotocolisbeforeyouunderstandhowthewebworks

HTTPistheprotocolthatisusedtofacilitatecommunicationbetweenbrowserandwebserverItisbasedontheTCPprotocolandusuallyusesport80onthesideofthewebserverItisaprotocolthatutilizestherequest-responsemodel-clientssendrequestsandserversrespondAccordingtotheHTTPprotocolclientsalwayssetupnewconnectionsandsendHTTPrequeststoserversServersarenotabletoconnecttoclientsproactivelyorestablishcallbackconnectionsTheconnectionbetweenaclientandaservercanbeclosedbyeithersideForexampleyoucancancelyourdownloadrequestandHTTPconnectionandyourbrowserwilldisconnectfromtheserverbeforeyoufinishdownloading

TheHTTPprotocolisstatelesswhichmeanstheserverhasnoideaabouttherelationshipbetweenthetwoconnectionseventhoughtheyarebothfromsameclientTosolvethisproblemwebapplicationsusecookiestomaintainthestateofconnections

BecausetheHTTPprotocolisbasedontheTCPprotocolallTCPattackswillaffectHTTPcommunicationsinyourserverExamplesofsuchattacksareSYNfloodingDoSandDDoSattacks

HTTPrequestpackage(browserinformation)

RequestpackagesallhavethreepartsrequestlinerequestheaderandbodyThereisoneblanklinebetweenheaderandbody

Webworkingprinciples

81

GETdomainsexampleHTTP11requestlinerequestmethodURLprotocolanditsversion

Hostwwwianaorgdomainname

User-AgentMozilla50(WindowsNT61)AppleWebKit5374(KHTMLlikeGecko)Chrome220122994Safari5374

browserinformation

Accepttexthtmlapplicationxhtml+xmlapplicationxmlq=09q=08mimethatclientscanaccept

Accept-Encodinggzipdeflatesdchstreamcompression

Accept-CharsetUTF-8q=05charactersetinclientside

blankline

bodyrequestresourcearguments(forexampleargumentsinPOST)

Weusefiddlertogetthefollowingrequestinformation

Figure34InformationofaGETrequestcaughtbyfiddler

Figure35InformationofaPOSTrequestcaughtbyfiddler

WecanseethatGETdoesnothavearequestbodyunlikePOSTwhichdoes

TherearemanymethodsyoucanusetocommunicatewithserversinHTTPGETPOSTPUTandDELETEarethe4basicmethodsthatwetypicallyuseAURLrepresentsaresourceonanetworksothese4methodsdefinethequerychangeaddanddeleteoperationsthatcanactontheseresourcesGETandPOSTareverycommonlyusedinHTTPGETcanappendqueryparameterstotheURLusingtoseparatetheURLandparametersandampbetweentheargumentslikeEditPostsaspxname=test1ampid=123456POSTputsdataintherequestbodybecausetheURLimplementsalengthlimitationviathebrowserThusPOSTcansubmitmuchmoredatathanGETAlsowhenwesubmitusernamesandpasswordswedontwantthiskindofinformationtoappearintheURLsoweusePOSTtokeeptheminvisible

HTTPresponsepackage(serverinformation)Letsseewhatinformationiscontainedintheresponsepackages

HTTP11200OKstatusline

Servernginx108webserversoftwareanditsversionintheservermachine

DateDateTue30Oct2012041425GMTrespondedtime

Content-Typetexthtmlrespondeddatatype

Transfer-Encodingchunkeditmeansdataweresentinfragments

Connectionkeep-alivekeepconnection

Content-Length90lengthofbody

blankline

ltDOCTYPEhtmlPUBLIC-W3CDTDXHTML10TransitionalENmessagebody

ThefirstlineiscalledthestatuslineItsuppliestheHTTPversionstatuscodeandstatusmessage

ThestatuscodeinformstheclientofthestatusoftheHTTPserversresponseInHTTP115kindsofstatuscodesweredefined

-1xxInformational

-2xxSuccess

-3xxRedirection

-4xxClientError

-5xxServerError

Letsseemoreexamplesaboutresponsepackages200meansserverrespondedcorrectly302meansredirection

Figure36Fullinformationforvisitingawebsite

HTTPisstatelessandConnectionkeep-alive

Webworkingprinciples

82

ThetermstatelessdoesntmeanthattheserverhasnoabilitytokeepaconnectionItsimplymeansthattheserverdoesntrecognizeanyrelationshipsbetweenanytworequests

InHTTP11Keep-aliveisusedbydefaultIfclientshaveadditionalrequeststheywillusethesameconnectionforthem

NoticethatKeep-alivecannotmaintainoneconnectionforevertheapplicationrunningintheserverdeterminesthelimitwithwhichtokeeptheconnectionaliveforandinmostcasesyoucanconfigurethislimit

Requestinstance

Figure37Allpackagesforopeningonewebpage

WecanseetheentirecommunicationprocessbetweenclientandserverfromtheabovepictureYoumaynoticethattherearemanyresourcefilesinthelistthesearecalledstaticfilesandGohasspecializedprocessingmethodsforthesefiles

ThisisthemostimportantfunctionofbrowserstorequestforaURLandretrievedatafromwebserversthenrendertheHTMLIfitfindssomefilesintheDOMsuchasCSSorJSfilesbrowserswillrequesttheseresourcesfromtheserveragainuntilalltheresourcesfinishrenderingonyourscreen

ReducingHTTPrequesttimesisonewayofimprovingtheloadingspeedofwebpagesByreducingthenumberofCSSandJSfilesthatneedtobeloadedbothrequestlatenciesandpressureonyourwebserverscanbereducedatthesametime

LinksDirectoryPrevioussectionWebfoundationNextsectionBuildasimplewebserver

Webworkingprinciples

83

32BuildasimplewebserverWevediscussedthatwebapplicationsarebasedontheHTTPprotocolandGoprovidesfullHTTPsupportinthenethttppackageItsveryeasytosetawebserverupusingthispackage

Usehttppackagesetupawebserver

packagemain

import(

fmt

nethttp

strings

log

)

funcsayhelloName(whttpResponseWriterrhttpRequest)

rParseForm()parseargumentsyouhavetocallthisbyyourself

fmtPrintln(rForm)printforminformationinserverside

fmtPrintln(pathrURLPath)

fmtPrintln(schemerURLScheme)

fmtPrintln(rForm[url_long])

forkv=rangerForm

fmtPrintln(keyk)

fmtPrintln(valstringsJoin(v))

fmtFprintf(wHelloastaxie)senddatatoclientside

funcmain()

httpHandleFunc(sayhelloName)setrouter

err=httpListenAndServe(9090nil)setlistenport

iferr=nil

logFatal(ListenAndServeerr)

Afterweexecutetheabovecodetheserverbeginslisteningtoport9090inlocalhost

Openyourbrowserandvisithttplocalhost9090YoucanseethatHelloastaxieisonyourscreen

Letstryanotheraddresswithadditionalargumentshttplocalhost9090url_long=111ampurl_long=222

Nowletsseewhathappensonboththeclientandserversides

Youshouldseethefollowinginformationontheserverside

Figure38Serverprintedinformation

Asyoucanseeweonlyneedtocalltwofunctionsinordertobuildasimplewebserver

IfyouareworkingwithPHPyoureprobablyaskingwhetherornotweneedsomethinglikeNginxorApacheTheansweriswedontsinceGolistenstotheTCPportbyitselfandthefunctionsayhelloNameisthelogicfunctionjustlikeacontrollerinPHP

IfyouareworkingwithPythonyoushouldknowtornadoandtheaboveexampleisverysimilartothat

IfyouareworkingwithRubyyoumaynoticeitislikescriptserverinROR(RubyonRails)

Buildasimplewebserver

84

WeusedtwosimplefunctionstosetupasimplewebserverinthissectionandthissimpleserveralreadyhasthecapacityforhighconcurrencyoperationsWewilltalkabouthowtoutilizethisinthenexttwosections

LinksDirectoryPrevioussectionWebworkingprinciplesNextsectionHowGoworkswithweb

Buildasimplewebserver

85

33HowGoworkswithwebWelearnedtousethenethttppackagetobuildasimplewebserverintheprevioussectionandallthoseworkingprinciplesarethesameasthosewewilltalkaboutinthefirstsectionofthischapter

ConceptsinwebprinciplesRequestrequestdatafromusersincludingPOSTGETCookieandURL

Responseresponsedatafromservertoclients

Connconnectionsbetweenclientsandservers

HandlerRequesthandlinglogicandresponsegeneration

httppackageoperatingmechanismThefollowingpictureshowstheworkflowofaGowebserver

Figure39httpworkflow

1 Createalisteningsocketlistentoaportandwaitforclients2 Acceptrequestsfromclients3 HandlerequestsreadHTTPheaderIftherequestusesPOSTmethodreaddatainthemessagebodyandpassthem

tohandlersFinallysocketreturnsresponsedatatoclients

OnceweknowtheanswerstothethreefollowingquestionsitseasytoknowhowthewebworksinGo

HowdowelistentoaportHowdoweacceptclientrequestsHowdoweallocatehandlers

IntheprevioussectionwesawthatGousesListenAndServetohandlethesestepsinitializeaserverobjectcallnetListen(tcpaddr)tosetupaTCPlistenerandlistentoaspecificaddressandport

Letstakealookatthehttppackagessourcecode

HowGoworkswithweb

86

Buildversiongo112

func(srvServer)Serve(lnetListener)error

deferlClose()

vartempDelaytimeDurationhowlongtosleeponacceptfailure

for

rwe=lAccept()

ife=nil

ifneok=e(netError)okampampneTemporary()

iftempDelay==0

tempDelay=5timeMillisecond

else

tempDelay=2

ifmax=1timeSecondtempDelaygtmax

tempDelay=max

logPrintf(httpAccepterrorvretryinginvetempDelay)

timeSleep(tempDelay)

continue

returne

tempDelay=0

cerr=srvnewConn(rw)

iferr=nil

continue

gocserve()

HowdoweacceptclientrequestsafterwebeginlisteningtoaportInthesourcecodewecanseethatsrvServe(netListener)iscalledtohandleclientrequestsInthebodyofthefunctionthereisaforItacceptsarequestcreatesanewconnectionthenstartsanewgoroutinepassingtherequestdatatothegocserve()goroutineThisishowGosupportshighconcurrencyandeverygoroutineisindependent

HowdoweusespecificfunctionstohandlerequestsconnparsesrequestcReadRequest()atfirstthengetsthecorrespondinghandlerhandler=shsrvHandlerwhichisthesecondargumentwepassedwhenwecalledListenAndServeBecausewepassednilGousesitsdefaulthandlerhandler=DefaultServeMuxSowhatisDefaultServeMuxdoinghereWellitstheroutervariablewhichcancallhandlerfunctionsforspecificURLsDidwesetthisYeswedidWedidthisinthefirstlinewhereweusedhttpHandleFunc(sayhelloName)WereusingthisfunctiontoregistertherouterruleforthepathWhentheURListheroutercallsthefunctionsayhelloNameDefaultServeMuxcallsServerHTTPtogethandlerfunctionsfordifferentpathscallingsayhelloNameinthisspecificcaseFinallytheserverwritesdataandrespondstoclients

Detailedworkflow

Figure310WorkflowofhandlinganHTTPrequest

IthinkyoushouldknowhowGorunswebserversnow

LinksDirectoryPrevioussectionBuildasimplewebserverNextsectionGetintohttppackage

HowGoworkswithweb

87

HowGoworkswithweb

88

34GetintohttppackageInprevioussectionswelearnedabouttheworkflowofthewebandtalkedalittlebitaboutGoshttppackageInthissectionwearegoingtolearnabouttwocorefunctionsinthehttppackageConnandServeMux

goroutineinConnUnlikenormalHTTPserversGousesgoroutinesforeveryjobinitiatedbyConninordertoachievehighconcurrencyandperformancesoeveryjobisindependent

Gousesthefollowingcodetowaitfornewconnectionsfromclients

cerr=srvnewConn(rw)

iferr=nil

continue

gocserve()

Asyoucanseeitcreatesanewgoroutineforeveryconnectionandpassesthehandlerthatisabletoreaddatafromtherequesttothegoroutine

CustomizedServeMuxWeusedGosdefaultrouterinprevioussectionswhendiscussingconnserverwiththerouterpassingrequestdatatoaback-endhandler

Thestructofthedefaultrouter

typeServeMuxstruct

musyncRWMutexbecauseofconcurrencywehavetouseamutexhere

mmap[string]muxEntryrouterruleseverystringmappingtoahandler

ThestructofmuxEntry

typemuxEntrystruct

explicitboolexactmatchornot

hHandler

TheinterfaceofHandler

typeHandlerinterface

ServeHTTP(ResponseWriterRequest)routingimplementer

HandlerisaninterfacebutifthefunctionsayhelloNamedidntimplementthisinterfacethenhowdidweadditashandlerTheanswerliesinanothertypecalledHandlerFuncinthehttppackageWecalledHandlerFunctodefineoursayhelloNamemethodsosayhelloNameimplementedHandleratthesametimeItslikewerecallingHandlerFunc(f)andthefunctionfisforceconvertedtotypeHandlerFunc

Getintohttppackage

89

typeHandlerFuncfunc(ResponseWriterRequest)

ServeHTTPcallsf(wr)

func(fHandlerFunc)ServeHTTP(wResponseWriterrRequest)

f(wr)

Howdoestheroutercallhandlersafterwesettherouterrules

TheroutercallsmuxhandlerServeHTTP(wr)whenitreceivesrequestsInotherwordsitcallstheServeHTTPinterfaceofthehandlerswhichhaveimplementedit

Nowletsseehowmuxhandlerworks

func(muxServeMux)handler(rRequest)Handler

muxmuRLock()

defermuxmuRUnlock()

Host-specificpatterntakesprecedenceovergenericones

h=muxmatch(rHost+rURLPath)

ifh==nil

h=muxmatch(rURLPath)

ifh==nil

h=NotFoundHandler()

returnh

TherouterusestherequestsURLasakeytofindthecorrespondinghandlersavedinthemapthencallshandlerServeHTTPtoexecutefunctionstohandlethedata

YoushouldunderstandthedefaultroutersworkflowbynowandGoactuallysupportscustomizedroutersThesecondargumentofListenAndServeisforconfiguringcustomizedroutersItsaninterfaceofHandlerThereforeanyrouterthatimplementstheHandlerinterfacecanbeused

Thefollowingexampleshowshowtoimplementasimplerouter

packagemain

import(

fmt

nethttp

)

typeMyMuxstruct

func(pMyMux)ServeHTTP(whttpResponseWriterrhttpRequest)

ifrURLPath==

sayhelloName(wr)

return

httpNotFound(wr)

return

funcsayhelloName(whttpResponseWriterrhttpRequest)

fmtFprintf(wHellomyroute)

funcmain()

mux=ampMyMux

httpListenAndServe(9090mux)

Getintohttppackage

90

RoutingIfyoudonotwanttouseaRouteryoucanstillachievewhatwewroteintheabovesectionbyreplacingthesecondargumenttoListenAndServetonilandregisteringtheURLsusingaHandleFuncfunctionwhichgoesthroughalltheregisteredURLstofindthebestmatchsocaremustbetakenabouttheorderoftheregistering

samplecode

httpHandleFunc(viewsShowAllTasksFunc)

httpHandleFunc(completeviewsCompleteTaskFunc)

httpHandleFunc(deleteviewsDeleteTaskFunc)

ShowAllTasksFuncisusedtohandletheURLwhichisthedefaultons

TODOaddhttp404error

funcShowAllTasksFunc(whttpResponseWriterrhttpRequest)

ifrMethod==GET

context=dbGetTasks(pending)truewhenyouwantnondeletedtasks

dbisapackagewhichinteractswiththedatabase

ifmessage=

contextMessage=message

homeTemplateExecute(wcontext)

message=

else

message=Methodnotallowed

httpRedirect(wrhttpStatusFound)

ThisisfineforsimpleapplicationswhichdoesntrequiresparameterizedroutingwhatwhenyouneedthatYoucaneitherusetheexistingtoolkitsorframeworksbutsincethisbookisaboutwritingwebappsingolangwearegoingtoteachhowtohandlethisscenarioaswell

WhenthematchismadeontheHandleFuncfunctiontheURLismatchedsosupposewearewritingatodolistmanagerandwewanttodeleteatasksotheURLwedecideforthatapplicationisdelete1soweregisterthedeleteURLlikethishttpHandleFunc(deleteviewsDeleteTaskFunc)delete1thisURLmatchesclosestwiththedeleteURLthananyotherURLsointherURLpathwegettheentireURLoftherequest

httpHandleFunc(deleteviewsDeleteTaskFunc)

DeleteTaskFuncisusedtodeleteatasktrash=movetorecyclebindelete=permanentdelete

funcDeleteTaskFunc(whttpResponseWriterrhttpRequest)

ifrMethod==DELETE

id=rURLPath[len(delete)]

ifid==all

dbDeleteAll()

httpRedirect(wrhttpStatusFound)

else

iderr=strconvAtoi(id)

iferr=nil

fmtPrintln(err)

else

err=dbDeleteTask(id)

iferr=nil

message=Errordeletingtask

else

message=Taskdeleted

httpRedirect(wrhttpStatusFound)

else

message=Methodnotallowed

httpRedirect(wrhttpStatusFound)

Getintohttppackage

91

linkhttpsgithubcomthewhitetulipTasksblobmasterviewsviewsgoL170-L195

InthisabovemethodwhatwebasicallydoisinthefunctionwhichhandlesthedeleteURLwetakeitscompeleteURLwhichisdelete1thenwetakeasliceofthestringandextracteverythingwhichstartsafterthedeletewordwhichistheactualparameterinthiscaseitis1ThenweusethestrconvpackagetoconvertittoanintegeranddeletethetaskwiththattaskID

InmorecomplexscenariostoowecanusethismethodtheadvantageisthatwedonthavetouseanythirdpartytoolkitbutthenagainthirdpartytoolkitsareusefulintheirownrightyouneedtomakeadecisionwhichmethodyoudpreferNoansweristherightanswer

GocodeexecutionflowLetstakealookatthewholeexecutionflow

CallhttpHandleFunc1 CallHandleFuncofDefaultServeMux2 CallHandleofDefaultServeMux3 Addrouterrulestomap[string]muxEntryofDefaultServeMux

CallhttpListenAndServe(9090nil)1 InstantiateServer2 CallListenAndServemethodofServer3 CallnetListen(tcpaddr)tolistentoport4 Startaloopandacceptrequestsintheloopbody5 InstantiateaConnandstartagoroutineforeveryrequestgocserve()6 Readrequestdatawerr=creadRequest()7 CheckwhetherhandlerisemptyornotifitsemptythenuseDefaultServeMux8 CallServeHTTPofhandler9 ExecutecodeinDefaultServeMuxinthiscase10 ChoosehandlerbyURLandexecutecodeinthathandlerfunctionmuxhandlerServeHTTP(wr)11 HowtochoosehandlerACheckrouterrulesforthisURLBCallServeHTTPinthathandlerifthereisoneCCall

ServeHTTPofNotFoundHandlerotherwise

LinksDirectoryPrevioussectionHowGoworkswithwebNextsectionSummary

Getintohttppackage

92

35SummaryInthischapterweintroducedHTTPDNSresolutionflowandhowtobuildasimplewebserverThenwetalkedabouthowGoimplementswebserversforusbylookingatthesourcecodeofthenethttppackage

IhopethatyounowknowmuchmoreaboutwebdevelopmentandyoushouldseethatitsquiteeasyandflexibletobuildawebapplicationinGo

LinksDirectoryPrevioussectionGetintohttppackageNextchapterUserform

Summary

93

4UserformAuserformissomethingthatisverycommonlyusedwhendevelopingwebapplicationsItprovidestheabilitytocommunicatebetweenclientsandserversYoumustbeveryfamiliarwithformsifyouareawebdeveloperifyouareaCC++programmeryoumaywanttoaskwhatisauserform

AformisanareathatcontainsformelementsUserscaninputinformationintoformelementsliketextboxesdropdownlistsradiobuttonscheckboxesetcWeusetheformtagltformgttodefineforms

ltformgt

inputelements

ltformgt

GoalreadyhasmanyconvenientfunctionstodealwithuserformsYoucaneasilygetformdatainHTTPrequestsandtheyareeasytointegrateintoyourownwebapplicationsInsection41wearegoingtotalkabouthowtohandleformdatainGoAlsosinceyoucannottrustanydatacomingfromtheclientsideyoumustfirstvalidatethedatabeforeusingitWellgothroughsomeexamplesabouthowtovalidateformdatainsection42

WesaythatHTTPisstatelessHowcanweidentifythatcertainformsarefromthesameuserAndhowdowemakesurethatoneformcanonlybesubmittedonceWelllookatsomedetailsconcerningcookies(acookieisinformationthatcanbesavedontheclientsideandaddedtotherequestheaderwhentherequestissenttotheserver)inbothsections43and44

Anothercommonuse-caseforformsisuploadingfilesInsection45youwilllearnhowtodothisaswellascontrollingthefileuploadsizebeforeitbeginsuploadinginGo

LinksDirectoryPreviouschapterChapter3SummaryNextsectionProcessforminputs

HTTPForm

94

41ProcessforminputsBeforewebeginletstakealookatasimpleexampleofatypicaluserformsavedaslogingtplinyourprojectfolder

lthtmlgt

ltheadgt

lttitlegtlttitlegt

ltheadgt

ltbodygt

ltformaction=loginmethod=postgt

Usernameltinputtype=textname=usernamegt

Passwordltinputtype=passwordname=passwordgt

ltinputtype=submitvalue=Logingt

ltformgt

ltbodygt

lthtmlgt

ThisformwillsubmittologinontheserverAftertheuserclickstheloginbuttonthedatawillbesenttotheloginhandlerregisteredbytheserverrouterThenweneedtoknowwhetheritusesthePOSTmethodorGET

ThisiseasytofindoutusingthehttppackageLetsseehowtohandletheformdataontheloginpage

Processforminputs

95

packagemain

import(

fmt

htmltemplate

log

nethttp

strings

)

funcsayhelloName(whttpResponseWriterrhttpRequest)

rParseForm()ParseurlparameterspassedthenparsetheresponsepacketforthePOSTbody(requestbody)

attentionIfyoudonotcallParseFormmethodthefollowingdatacannotbeobtainedform

fmtPrintln(rForm)printinformationonserverside

fmtPrintln(pathrURLPath)

fmtPrintln(schemerURLScheme)

fmtPrintln(rForm[url_long])

forkv=rangerForm

fmtPrintln(keyk)

fmtPrintln(valstringsJoin(v))

fmtFprintf(wHelloastaxie)writedatatoresponse

funclogin(whttpResponseWriterrhttpRequest)

fmtPrintln(methodrMethod)getrequestmethod

ifrMethod==GET

t_=templateParseFiles(logingtpl)

tExecute(wnil)

else

rParseForm()

logicpartoflogin

fmtPrintln(usernamerForm[username])

fmtPrintln(passwordrForm[password])

funcmain()

httpHandleFunc(sayhelloName)settingrouterrule

httpHandleFunc(loginlogin)

err=httpListenAndServe(9090nil)settinglisteningport

iferr=nil

logFatal(ListenAndServeerr)

HereweuserMethodtogettherequestmethodanditreturnsanhttpverb-GETPOSTPUTetc

IntheloginfunctionweuserMethodtocheckwhetheritsaloginpageorloginprocessinglogicInotherwordswechecktoseewhethertheuserissimplyopeningthepageortryingtologinServeshowsthepageonlywhentherequestcomesinviatheGETmethodanditexecutestheloginlogicwhentherequestusesthePOSTmethod

Youshouldseethefollowinginterfaceafteropeninghttp1270019090logininyourbrowser

Figure41Userlogininterface

TheserverwillnotprintanythinguntilafterwetypeinausernameandpasswordbecausethehandlerdoesntparsetheformuntilwecallrParseForm()LetsaddrParseForm()beforefmtPrintln(usernamerForm[username])compileourprogramandtestitagainYouwillfindthattheinformationisprintedontheserversidenow

rFormcontainsalloftherequestargumentsforinstancethequery-stringintheURLandthedatainPOSTandPUTIfthedatahasconflictsforexampleparametersthathavethesamenametheserverwillsavethedataintoaslicewithmultiplevaluesTheGodocumentationstatesthatGowillsavethedatafromGETandPOSTrequestsindifferentplaces

Processforminputs

96

Trychangingthevalueoftheactionintheformhttp1270019090logintohttp1270019090loginusername=astaxieinthelogingtplfiletestitagainandyouwillseethatthesliceisprintedontheserverside

Figure42Serverprintsrequestdata

ThetypeofrequestFormisurlValueItsavesdatawiththeformatkey=value

v=urlValues

vSet(nameAva)

vAdd(friendJess)

vAdd(friendSarah)

vAdd(friendZoe)

vEncode()==name=Avaampfriend=Jessampfriend=Sarahampfriend=Zoe

fmtPrintln(vGet(name))

fmtPrintln(vGet(friend))

fmtPrintln(v[friend])

TipsRequestshavetheabilitytoaccessformdatausingtheFormValue()methodForexampleyoucanchangerForm[username]torFormValue(username)andGocallsrParseFormautomaticallyNoticethatitreturnsthefirstvalueifthereareargumentswiththesamenameanditreturnsanemptystringifthereisnosuchargument

LinksDirectoryPrevioussectionUserformNextsectionVerificationofinputs

Processforminputs

97

42VerificationofinputsOneofthemostimportantprinciplesinwebdevelopmentisthatyoucannottrustanythingfromclientsideuserformsYouhavetovalidateallincomingdatabeforeuseitManywebsitesareaffectedbythisproblemwhichissimpleyetcrucial

TherearetwowaysofverifyingformdatathatareincommonuseThefirstisJavaScriptvalidationonthefront-endandthesecondisservervalidationontheback-endInthissectionwearegoingtotalkaboutserversidevalidationinwebdevelopment

RequiredfieldsSometimeswerequirethatusersinputsomefieldsbuttheyfailtocompletethefieldForexampleintheprevioussectionwhenwerequiredausernameYoucanusethelenfunctiontogetthelengthofafieldinordertoensurethatusershaveenteredsomething

iflen(rForm[username][0])==0

codeforemptyfield

rFormtreatsdifferentformelementtypesdifferentlywhentheyareblankForemptytextboxestextareasandfileuploadsitreturnsanemptystringforradiobuttonsandcheckboxesitdoesntevencreatethecorrespondingitemsInsteadyouwillgeterrorsifyoutrytoaccessitThereforeitssafertouserFormGet()togetfieldvaluessinceitwillalwaysreturnemptyifthevaluedoesnotexistOntheotherhandrFormGet()canonlygetonefieldvalueatatimesoyouneedtouserFormtogetthemapofvalues

NumbersSometimesyourequirenumbersratherthanothertextforthefieldvalueForexampleletssaythatyourequiretheageofauserinintegerformonlyie50or10insteadofoldenoughoryoungmanIfwerequireapositivenumberwecanconvertthevaluetotheinttypefirstthenprocessit

getinterr=strconvAtoi(rFormGet(age))

iferr=nil

erroroccurswhenconverttonumberitmaynotanumber

checkrangeofnumber

ifgetintgt100

toobig

Anotherwaytodothisisbyusingregularexpressions

ifm_=regexpMatchString(^[0-9]+$rFormGet(age))m

returnfalse

ForhighperformancepurposesregularexpressionsarenotefficienthoweversimpleregularexpressionsareusuallyfastenoughIfyouarefamiliarwithregularexpressionsitsaveryconvenientwaytoverifydataNoticethatGousesRE2soallUTF-8charactersaresupported

Chinese

Validationofinputs

98

SometimesweneeduserstoinputtheirChinesenamesandwehavetoverifythattheyalluseChineseratherthanrandomcharactersForChineseverificationregularexpressionsaretheonlyway

ifm_=regexpMatchString(^[x4e00-x9fa5]+$rFormGet(realname))m

returnfalse

EnglishlettersSometimesweneeduserstoinputonlyEnglishlettersForexamplewerequiresomeonesEnglishnamelikeastaxieinsteadofasta谢Wecaneasilyuseregularexpressionstoperformourverification

ifm_=regexpMatchString(^[a-zA-Z]+$rFormGet(engname))m

returnfalse

E-mailaddressIfyouwanttoknowwhetherusershaveenteredvalidE-mailaddressesyoucanusethefollowingregularexpression

ifm_=regexpMatchString(`^([w_]210)(w1)([a-z]24)$`rFormGet(email))m

fmtPrintln(no)

else

fmtPrintln(yes)

DropdownlistLetssaywerequireanitemfromourdropdownlistbutinsteadwegetavaluefabricatedbyhackersHowdowepreventthisfromhappening

Supposewehavethefollowingltselectgt

ltselectname=fruitgt

ltoptionvalue=applegtappleltoptiongt

ltoptionvalue=peargtpearltoptiongt

ltoptionvalue=bananagtbananaltoptiongt

ltselectgt

Wecanusethefollowingstrategytosanitizeourinput

slice=[]stringapplepearbanana

for_v=rangeslice

ifv==rFormGet(fruit)

returntrue

returnfalse

AllthefunctionsIveshownaboveareinmyopensourceprojectforoperatingonslicesandmapshttpsgithubcomastaxiebeeku

Radiobuttons

Validationofinputs

99

Ifwewanttoknowwhethertheuserismaleorfemalewemayusearadiobuttonreturning1formaleand2forfemaleHoweversomelittlekidwhojustreadhisfirstbookonHTTPdecidestosendtoyoua3WillyourprogramthrowanexceptionAsyoucanseeweneedtousethesamemethodaswedidforourdropdownlisttomakesurethatonlyexpectedvaluesarereturnedbyourradiobutton

ltinputtype=radioname=gendervalue=1gtMale

ltinputtype=radioname=gendervalue=2gtFemale

Andweusethefollowingcodetovalidatetheinput

slice=[]int12

for_v=rangeslice

ifv==rFormGet(gender)

returntrue

returnfalse

CheckboxesSupposetherearesomecheckboxesforuserinterestsandthatyoudontwantextraneousvalueshereeitherYoucanvalidatetheseasefollows

ltinputtype=checkboxname=interestvalue=footballgtFootball

ltinputtype=checkboxname=interestvalue=basketballgtBasketball

ltinputtype=checkboxname=interestvalue=tennisgtTennis

Inthiscasethesanitizationisalittlebitdifferenttovalidatingthebuttonandcheckboxinputssinceherewegetaslicefromthecheckboxes

slice=[]stringfootballbasketballtennis

a=Slice_diff(rForm[interest]slice)

ifa==nil

returntrue

returnfalse

DateandtimeSupposeyouwantuserstoinputvaliddatesortimesGohasthetimepackageforconvertingyearmonthanddaytotheircorrespondingtimesAfterthatitseasytocheckit

t=timeDate(2009timeNovember1023000timeUTC)

fmtPrintf(GolaunchedatsntLocal())

Afteryouhavethetimeyoucanusethetimepackageformoreoperationsdependingonyourneeds

InthissectionwevediscussedsomecommonmethodsofvalidatingformdataontheserversideIhopethatyounowunderstandmoreaboutdatavalidationinGoespeciallyhowtouseregularexpressionstoyouradvantage

LinksDirectory

Validationofinputs

100

PrevioussectionProcessforminputsNextsectionCrosssitescripting

Validationofinputs

101

43CrosssitescriptingTodayswebsiteshavemuchmoredynamiccontentinordertoimproveuserexperiencewhichmeansthatwemustprovidedynamicinformationdependingoneveryindividualsbehaviorUnfortunatelydynamicwebsitesaresusceptibletomaliciousattacksknownasCrosssitescripting(knownasXSS)StaticwebsitesarenotsusceptibletoCrosssitescripting

AttackersofteninjectmaliciousscriptslikeJavaScriptVBScriptActiveXorFlashintothosewebsitesthathaveloopholesOncetheyhavesuccessfullyinjectedtheirscriptsuserinformationcanbestolenandyourwebsitecanbefloodedwithspamTheattackerscanalsochangeusersettingstowhatevertheywant

Ifyouwishtopreventthiskindofattackyoushouldcombinethefollowingtwoapproaches

ValidationofalldatafromuserswhichwetalkedaboutintheprevioussectionCarefullyhandledatathatwillbesenttoclientsinordertopreventanyinjectedscriptsfromrunningonbrowsers

SohowcanwedothesetwothingsinGoFortunatelythehtmltemplatepackagehassomeusefulfunctionstoescapedataasfollows

funcHTMLEscape(wioWriterb[]byte)escapesbtowfuncHTMLEscapeString(sstring)stringreturnsastringafterescapingfromsfuncHTMLEscaper(argsinterface)stringreturnsastringafterescapingfrommultiplearguments

Letschangetheexampleinsection41

fmtPrintln(usernametemplateHTMLEscapeString(rFormGet(username)))printatserverside

fmtPrintln(passwordtemplateHTMLEscapeString(rFormGet(password)))

templateHTMLEscape(w[]byte(rFormGet(username)))respondedtoclients

Ifsomeonetriestoinputtheusernameasltscriptgtalert()ltscriptgtwewillseethefollowingcontentinthebrowser

Figure43JavaScriptafterescaped

FunctionsinthehtmltemplatepackagehelpyoutoescapeallHTMLtagsWhatifyoujustwanttoprintltscriptgtalert()ltscriptgttobrowsersYoushouldusetexttemplateinstead

importtexttemplate

terr=templateNew(foo)Parse(`defineTHelloend`)

err=tExecuteTemplate(outTltscriptgtalert(youhavebeenpwned)ltscriptgt)

Output

Helloltscriptgtalert(youhavebeenpwned)ltscriptgt

OryoucanusethetemplateHTMLtypeVariablecontentwillnotbeescapedifitstypeistemplateHTML

importhtmltemplate

terr=templateNew(foo)Parse(`defineTHelloend`)

err=tExecuteTemplate(outTtemplateHTML(ltscriptgtalert(youhavebeenpwned)ltscriptgt))

Output

Helloltscriptgtalert(youhavebeenpwned)ltscriptgt

Crosssitescripting

102

Onemoreexampleofescaping

importhtmltemplate

terr=templateNew(foo)Parse(`defineTHelloend`)

err=tExecuteTemplate(outTltscriptgtalert(youhavebeenpwned)ltscriptgt)

Output

Helloampltscriptampgtalert(amp39youhavebeenpwnedamp39)ampltscriptampgt

LinksDirectoryPrevioussectionVerificationofinputsNextsectionDuplicatesubmissions

Crosssitescripting

103

44DuplicatesubmissionsIdontknowifyouveeverseensomeblogsorBBSthathavemorethanonepostthatareexactlythesamebutIcantellyouthatitsbecauseuserssubmittedduplicatepostformsTherearemanythingsthatcancauseduplicatesubmissionssometimesusersjustdoubleclickthesubmitbuttonortheywanttomodifysomecontentafterpostingandpressthebackbuttonInsomecasesitisbytheintentionalactionsofmalicioususersItseasytoseehowduplicatesubmissionscanleadtomanyproblemsThuswehavetouseeffectivemeanstopreventit

ThesolutionistoaddahiddenfieldwithauniquetokentoyourformandtoalwayscheckthistokenbeforeprocessingtheincomingdataAlsoifyouareusingAjaxtosubmitaformuseJavaScripttodisablethesubmitbuttononcetheformhasbeensubmitted

Letsimprovetheexamplefromsection42

ltinputtype=checkboxname=interestvalue=footballgtFootball

ltinputtype=checkboxname=interestvalue=basketballgtBasketball

ltinputtype=checkboxname=interestvalue=tennisgtTennis

Usernameltinputtype=textname=usernamegt

Passwordltinputtype=passwordname=passwordgt

ltinputtype=hiddenname=tokenvalue=gt

ltinputtype=submitvalue=Logingt

WeuseanMD5hash(timestamp)togeneratethetokenandaddedittobothahiddenfieldontheclientsideformandasessioncookieontheserverside(Chapter6)Wecanthenusethistokentocheckwhetherornotthisformwassubmitted

funclogin(whttpResponseWriterrhttpRequest)

fmtPrintln(methodrMethod)getrequestmethod

ifrMethod==GET

crutime=timeNow()Unix()

h=md5New()

ioWriteString(hstrconvFormatInt(crutime10))

token=fmtSprintf(xhSum(nil))

t_=templateParseFiles(logingtpl)

tExecute(wtoken)

else

loginrequest

rParseForm()

token=rFormGet(token)

iftoken=

checktokenvalidity

else

giveerrorifnotoken

fmtPrintln(usernamelengthlen(rForm[username][0]))

fmtPrintln(usernametemplateHTMLEscapeString(rFormGet(username)))printinserverside

fmtPrintln(passwordtemplateHTMLEscapeString(rFormGet(password)))

templateHTMLEscape(w[]byte(rFormGet(username)))respondtoclient

Figure44Thecontentinbrowserafteraddingatoken

YoucanrefreshthispageandyouwillseeadifferenttokeneverytimeThisensuresthateveryformisunique

FornowyoucanpreventmanyduplicatesubmissionattacksbyaddingtokenstoyourformsbutitcannotpreventalldeceptiveattacksofthistypeThereismuchmoreworkthatneedstobedone

Duplicatesubmissions

104

LinksDirectoryPrevioussectionCrosssitescriptingNextsectionFileupload

Duplicatesubmissions

105

45FileuploadSupposeyouhaveawebsitelikeInstagramandyouwantuserstouploadtheirbeautifulphotosHowwouldyouimplementthatfunctionality

YouhavetoaddpropertyenctypetotheformthatyouwanttouseforuploadingphotosTherearethreepossiblevaluesforthisproperty

applicationx-www-form-urlencodedTranscodeallcharactersbeforeuploading(default)

multipartform-dataNotranscodingYoumustusethisvaluewhenyourformhasfileuploadcontrols

textplainConvertspacesto+butnotranscodingforspecialcharacters

ThereforetheHTMLcontentofafileuploadformshouldlooklikethis

lthtmlgt

ltheadgt

lttitlegtUploadfilelttitlegt

ltheadgt

ltbodygt

ltformenctype=multipartform-dataaction=http1270019090uploadmethod=postgt

ltinputtype=filename=uploadfilegt

ltinputtype=hiddenname=tokenvalue=gt

ltinputtype=submitvalue=uploadgt

ltformgt

ltbodygt

lthtmlgt

Weneedtoaddafunctionontheserversidetohandlethisform

httpHandleFunc(uploadupload)

uploadlogic

funcupload(whttpResponseWriterrhttpRequest)

fmtPrintln(methodrMethod)

ifrMethod==GET

crutime=timeNow()Unix()

h=md5New()

ioWriteString(hstrconvFormatInt(crutime10))

token=fmtSprintf(xhSum(nil))

t_=templateParseFiles(uploadgtpl)

tExecute(wtoken)

else

rParseMultipartForm(32ltlt20)

filehandlererr=rFormFile(uploadfile)

iferr=nil

fmtPrintln(err)

return

deferfileClose()

fmtFprintf(wvhandlerHeader)

ferr=osOpenFile(test+handlerFilenameosO_WRONLY|osO_CREATE0666)

iferr=nil

fmtPrintln(err)

return

deferfClose()

ioCopy(ffile)

Fileupload

106

AsyoucanseeweneedtocallrParseMultipartFormforuploadingfilesThefunctionParseMultipartFormtakesthemaxMemoryargumentAfteryoucallParseMultipartFormthefilewillbesavedintheservermemorywithmaxMemorysizeIfthefilesizeislargerthanmaxMemorytherestofthedatawillbesavedinasystemtemporaryfileYoucanuserFormFiletogetthefilehandleanduseioCopytosavetoyourfilesystem

YoudontneedtocallrParseFormwhenyouaccessothernon-filefieldsintheformbecauseGowillcallitwhenitsnecessaryAlsocallingParseMultipartFormonceisenough-multiplecallsmakenodifference

Weusethreestepsforuploadingfilesasfollows

1 Addenctype=multipartform-datatoyourform2 CallrParseMultipartFormontheserversidetosavethefileeithertomemoryortoatemporaryfile3 CallrFormFiletogetthefilehandleandsavetothefilesystem

ThefilehandleristhemultipartFileHeaderItusesthefollowingstruct

typeFileHeaderstruct

Filenamestring

HeadertextprotoMIMEHeader

containsfilteredorunexportedfields

Figure45Printinformationonserverafterreceivingfile

ClientsuploadfilesIshowedanexampleofusingaformtoauploadafileWecanimpersonateaclientformtouploadfilesinGoaswell

Fileupload

107

packagemain

import(

bytes

fmt

io

ioioutil

mimemultipart

nethttp

os

)

funcpostFile(filenamestringtargetUrlstring)error

bodyBuf=ampbytesBuffer

bodyWriter=multipartNewWriter(bodyBuf)

thisstepisveryimportant

fileWritererr=bodyWriterCreateFormFile(uploadfilefilename)

iferr=nil

fmtPrintln(errorwritingtobuffer)

returnerr

openfilehandle

fherr=osOpen(filename)

iferr=nil

fmtPrintln(erroropeningfile)

returnerr

deferfhClose()

iocopy

_err=ioCopy(fileWriterfh)

iferr=nil

returnerr

contentType=bodyWriterFormDataContentType()

bodyWriterClose()

resperr=httpPost(targetUrlcontentTypebodyBuf)

iferr=nil

returnerr

deferrespBodyClose()

resp_bodyerr=ioutilReadAll(respBody)

iferr=nil

returnerr

fmtPrintln(respStatus)

fmtPrintln(string(resp_body))

returnnil

sampleusage

funcmain()

target_url=httplocalhost9090upload

filename=astaxiepdf

postFile(filenametarget_url)

TheaboveexampleshowsyouhowtouseaclienttouploadfilesItusesmultipartWritetowritefilesintocacheandsendsthemtotheserverthroughthePOSTmethod

IfyouhaveotherfieldsthatneedtowriteintodatalikeusernamecallmultipartWriteFieldasneeded

Links

Fileupload

108

DirectoryPrevioussectionDuplicatesubmissionsNextsectionSummary

Fileupload

109

46SummaryInthischapterwemainlylearnedhowtoprocessformdatainGothroughseveralexampleslikelogginginusersanduploadingfilesWealsoemphasizedthatvalidatinguserdataisextremelyimportantforwebsitesecurityandweusedonesectiontotalkabouthowtofilterdatawithregularexpressions

Ihopethatyounowknowmoreaboutthecommunicationprocessbetweenclientandserver

LinksDirectoryPrevioussectionFileuploadNextchapterDatabase

Summary

110

5DatabaseForwebdevelopersthedatabaseisatthecoreofwebdevelopmentYoucansavealmostanythingintoadatabaseandqueryorupdatedatainsideitlikeuserinformationproductsornewsarticles

GodoesntprovideanydatabasedriversbutitdoeshaveadriverinterfacedefinedinthedatabasesqlpackagePeoplecandevelopdatabasedriversbasedonthatinterfaceInsection51wearegoingtotalkaboutdatabasedriverinterfacedesigninGoInsections52to54IwillintroducesomeSQLdatabasedriverstoyouInsection55IwillpresenttheORM thatIhavedevelopedwhichisbasedonthedatabasesqlinterfacestandardItiscompatiblewithmostdriversthathaveimplementedthedatabasesqlinterfaceanditmakesiteasytoaccessdatabasesidiomaticallyinGo

NoSQLhasbeenahottopicinrecentyearsMorewebsitesaredecidingtouseNoSQLdatabasesastheirmaindatabaseinsteadofjustforthepurposeofcachingIwillintroduceyoutotwoNoSQLdatabaseswhichareMongoDBandRedisinsection56

LinksDirectoryPreviousChapterChapter4SummaryNextsectiondatabasesqlinterface

Database

111

51databasesqlinterfaceGodoesntprovideanyofficialdatabasedriversunlikeotherlanguageslikePHPwhichdoHoweveritdoeshavesomedatabasedriverinterfacestandardsfordeveloperstodevelopdatabasedriverswithTheadvantageisthatifyourcodeisdevelopedaccordingtotheseinterfacestandardsyouwillnotneedtochangeanycodeifyourdatabasechangesLetsseewhatthesedatabaseinterfacestandardsare

sqlRegisterThisfunctionisinthedatabasesqlpackageforregisteringdatabasedriverswhenyouusethird-partydatabasedriversAlloftheseshouldcalltheRegister(namestringdriverdriverDriver)functionininit()inordertoregisterthemselves

Letstakealookatthecorrespondingmymysqlandsqlite3drivercode

httpsgithubcommattngo-sqlite3driver

funcinit()

sqlRegister(sqlite3ampSQLiteDriver)

httpsgithubcommikespookmymysqldriver

Driverautomaticallyregisteredindatabasesql

vard=Driverprototcpraddr1270013306

funcinit()

Register(SETNAMESutf8)

sqlRegister(mymysqlampd)

Weseethatallthird-partydatabasedriversimplementthisfunctiontoregisterthemselvesandGousesamaptosaveuserdriversinsideofdatabasesql

vardrivers=make(map[string]driverDriver)

drivers[name]=driver

Thereforethisregistrationfunctioncanregisterasmanydriversasyoumayrequireeachwithdifferentnames

Wealwaysseethefollowingcodewhenweusethird-partydrivers

import(

databasesql

_githubcommattngo-sqlite3

)

Heretheunderscore(alsoknownasablank)_canbequiteconfusingformanybeginnersbutthisisagreatfeatureinGoWealreadyknowthatthisunderscoreidentifierisusedfordiscardingvaluesfromfunctionreturnsandalsothatyoumustuseallpackagesthatyouveimportedinyourcodeinGoSowhentheblankisusedwithimportitmeansthatyouneedtoexecutetheinit()functionofthatpackagewithoutdirectlyusingitwhichisaperfectfitfortheuse-caseofregisteringdatabasedrivers

driverDriverDriverisaninterfacecontaininganOpen(namestring)methodthatreturnsaConninterface

databasesqlinterface

112

typeDriverinterface

Open(namestring)(Connerror)

Thisisaone-timeConnwhichmeansitcanonlybeusedoncepergoroutineThefollowingcodewillcauseerrorstooccur

gogoroutineA(Conn)query

gogoroutineB(Conn)insert

BecauseGohasnoideawhichgoroutinedoeswhichoperationthequeryoperationmaygettheresultoftheinsertoperationandvice-versa

Allthird-partydriversshouldhavethisfunctiontoparsethenameofConnandreturnthecorrectresults

driverConnThisisadatabaseconnectioninterfacewithsomemethodsandasivesaidabovethesameConncanonlybeusedoncepergoroutine

typeConninterface

Prepare(querystring)(Stmterror)

Close()error

Begin()(Txerror)

PreparereturnsthepreparestatusofcorrespondingSQLcommandsforqueryinganddeletingetcCloseclosesthecurrentconnectionandcleansresourcesMostthird-partydriversimplementsomekindofconnectionpoolsoyoudontneedtocacheconnectionswhichcancauseunexpectederrorsBeginreturnsaTxthatrepresentsatransactionhandleYoucanuseitforqueryingupdatingrollingbacktransactionsetc

driverStmtThisisareadystatusthatcorrespondswithConnsoitcanonlybeusedoncepergoroutine(asisthecasewithConn)

typeStmtinterface

Close()error

NumInput()int

Exec(args[]Value)(Resulterror)

Query(args[]Value)(Rowserror)

CloseclosesthecurrentconnectionbutstillreturnsrowdataifitisexecutingaqueryoperationNumInputreturnsthenumberofobligateargumentsDatabasedriversshouldchecktheircallersargumentswhentheresultisgreaterthan0anditreturns-1whendatabasedriversdontknowanyobligateargumentExecexecutestheupdateinsertSQLcommandspreparedinPreparereturnsResultQueryexecutestheselectSQLcommandpreparedinPreparereturnsrowdata

driverTx

databasesqlinterface

113

Generallytransactionhandlesonlyhavesubmitorrollbackmethodsanddatabasedriversonlyneedtoimplementthesetwomethods

typeTxinterface

Commit()error

Rollback()error

driverExecerThisisanoptionalinterface

typeExecerinterface

Exec(querystringargs[]Value)(Resulterror)

IfthedriverdoesntimplementthisinterfacewhenyoucallDBExecitwillautomaticallycallPreparethenreturnStmtAfterthatitexecutestheExecmethodofStmtthenclosesStmt

driverResultThisistheinterfaceforresultsofupdateinsertoperations

typeResultinterface

LastInsertId()(int64error)

RowsAffected()(int64error)

LastInsertIdreturnsauto-incrementIdnumberafteradatabaseinsertoperationRowsAffectedreturnsrowsthatwereaffectedbyqueryoperations

driverRowsThisistheinterfacefortheresultofaqueryoperation

typeRowsinterface

Columns()[]string

Close()error

Next(dest[]Value)error

ColumnsreturnsfieldinformationofdatabasetablesTheslicehasaone-to-onecorrespondencewithSQLqueryfieldsonlyanddoesnotreturnallfieldsofthatdatabasetableCloseclosesRowsiteratorNextreturnsnextdataandassignstodestconvertingallstringsintobytearraysandgetsioEOFerrorifnomoredataisavailable

driverRowsAffectedThisisanaliasofint64butitimplementstheResultinterface

databasesqlinterface

114

typeRowsAffectedint64

func(RowsAffected)LastInsertId()(int64error)

func(vRowsAffected)RowsAffected()(int64error)

driverValueThisisanemptyinterfacethatcancontainanykindofdata

typeValueinterface

TheValuemustbesomethingthatdriverscanoperateonornilsoitshouldbeoneofthefollowingtypes

int64

float64

bool

[]byte

string[]ExceptRowsNextwhichcannotreturnstring

timeTime

driverValueConverterThisdefinesaninterfaceforconvertingnormalvaluestodriverValue

typeValueConverterinterface

ConvertValue(vinterface)(Valueerror)

Thisinterfaceiscommonlyusedindatabasedriversandhasmanyusefulfeatures

ConvertsdriverValuetoacorrespondingdatabasefieldtypeforexampleconvertsint64touint16ConvertsdatabasequeryresultstodriverValueConvertsdriverValuetoauserdefinedvalueinthescanfunction

driverValuerThisdefinesaninterfaceforreturningdriverValue

typeValuerinterface

Value()(Valueerror)

ManytypesimplementthisinterfaceforconversionbetweendriverValueanditself

AtthispointyoushouldknowabitaboutdevelopingdatabasedriversinGoOnceyoucanimplementinterfacesforoperationslikeadddeleteupdateetcthereareonlyafewproblemsleftrelatedtocommunicatingwithspecificdatabases

databasesqldatabasesqldefinesevenmorehigh-levelmethodsontopofdatabasesqldriverformoreconvenientdatabaseoperationsanditsuggeststhatyouimplementaconnectionpool

databasesqlinterface

115

typeDBstruct

driverdriverDriver

dsnstring

musyncMutexprotectsfreeConnandclosed

freeConn[]driverConn

closedbool

AsyoucanseetheOpenfunctionreturnsaDBthathasafreeConnandthisisasimpleconnectionpoolItsimplementationisverysimpleanduglyItusesdeferdbputConn(cierr)intheDbpreparefunctiontoputaconnectionintotheconnectionpoolEverytimeyoucalltheConnfunctionitchecksthelengthoffreeConnIfitsgreaterthan0thatmeansthereisareusableconnectionanditdirectlyreturnstoyouOtherwiseitcreatesanewconnectionandreturns

LinksDirectoryPrevioussectionDatabaseNextsectionMySQL

databasesqlinterface

116

52MySQLTheLAMPstackhasbeenverypopularontheinternetinrecentyearsandtheMinLAMPstandforMySQLMySQLisfamousbecauseitsopensourceandeasytouseAssuchithasbecomethede-factodatabaseintheback-endsofmanywebsites

MySQLdriversThereareacoupleofdriversthatsupportMySQLinGoSomeofthemimplementthedatabasesqlinterfaceandothersusetheirowninterfacestandards

httpsgithubcomgo-sql-drivermysqlsupportsdatabasesqlwritteninpureGohttpsgithubcomziutekmymysqlsupportsdatabasesqlanduserdefinedinterfaceswritteninpureGo

Illusethefirstdriverinthefollowingexamples(Iusethisoneinmypersonalprojectstoo)andIalsorecommendthatyouuseitforthefollowingreasons

ItsanewdatabasedriverandsupportsmorefeaturesItfullysupportsdatabasesqlinterfacestandardsSupportskeep-alivelongconnectionswiththread-safety

SamplesInthefollowingsectionsIllusethesamedatabasetablestructurefordifferentdatabasesthencreateSQLasfollows

CREATETABLE`userinfo`(

`uid`INT(10)NOTNULLAUTO_INCREMENT

`username`VARCHAR(64)NULLDEFAULTNULL

`departname`VARCHAR(64)NULLDEFAULTNULL

`created`DATENULLDEFAULTNULL

PRIMARYKEY(`uid`)

)

Thefollowingexampleshowshowtooperateonadatabasebasedonthedatabasesqlinterfacestandards

packagemain

import(

_githubcomgo-sql-drivermysql

databasesql

fmt

)

funcmain()

dberr=sqlOpen(mysqlastaxieastaxietestcharset=utf8)

checkErr(err)

insert

stmterr=dbPrepare(INSERTuserinfoSETusername=departname=created=)

checkErr(err)

reserr=stmtExec(astaxie研发部门2012-12-09)

checkErr(err)

iderr=resLastInsertId()

checkErr(err)

fmtPrintln(id)

update

HowtouseMySQL

117

stmterr=dbPrepare(updateuserinfosetusername=whereuid=)

checkErr(err)

reserr=stmtExec(astaxieupdateid)

checkErr(err)

affecterr=resRowsAffected()

checkErr(err)

fmtPrintln(affect)

query

rowserr=dbQuery(SELECTFROMuserinfo)

checkErr(err)

forrowsNext()

varuidint

varusernamestring

vardepartmentstring

varcreatedstring

err=rowsScan(ampuidampusernameampdepartmentampcreated)

checkErr(err)

fmtPrintln(uid)

fmtPrintln(username)

fmtPrintln(department)

fmtPrintln(created)

delete

stmterr=dbPrepare(deletefromuserinfowhereuid=)

checkErr(err)

reserr=stmtExec(id)

checkErr(err)

affecterr=resRowsAffected()

checkErr(err)

fmtPrintln(affect)

dbClose()

funccheckErr(errerror)

iferr=nil

panic(err)

Letmeexplainafewoftheimportantfunctionshere

sqlOpen()opensaregistereddatabasedriverTheGo-MySQL-DriverregisteredthemysqldriverhereThesecondargumentistheDSN(DataSourceName)thatdefinesinformationpertainingtothedatabaseconnectionItsupportsfollowingformats

userunix(pathtosocket)dbnamecharset=utf8

userpasswordtcp(localhost5555)dbnamecharset=utf8

userpassworddbname

userpasswordtcp([deadbeefcafe]80)dbname

dbPrepare()returnsaSQLoperationthatisgoingtobeexecutedItalsoreturnstheexecutionstatusafterexecutingSQL

dbQuery()executesSQLandreturnsaRowsresultstmtExec()executesSQLthathasbeenpreparedandstoredinStmt

Notethatweusetheformat=topassargumentsThisisnecessaryforpreventingSQLinjectionattacks

HowtouseMySQL

118

LinksDirectoryPrevioussectiondatabasesqlinterfaceNextsectionSQLite

HowtouseMySQL

119

53SQLiteSQLiteisanopensourceembeddedrelationaldatabaseIthasaself-containedzero-configurationandtransaction-supporteddatabaseengineItscharacteristicsarehighlyportableeasytousecompactefficientandreliableInmostofcasesyouonlyneedabinaryfileofSQLitetocreateconnectandoperateadatabaseIfyouarelookingforanembeddeddatabasesolutionSQLiteisworthconsideringYoucansaySQLiteistheopensourceversionofAccess

SQLitedriversTherearemanydatabasedriversforSQLiteinGobutmanyofthemdonotsupportthedatabasesqlinterfacestandards

httpsgithubcommattngo-sqlite3supportsdatabasesqlbasedoncgohttpsgithubcomfeyeleanorgosqlite3doesntsupportdatabasesqlbasedoncgohttpsgithubcomphfgo-sqlite3doesntsupportdatabasesqlbasedoncgo

ThefirstdriveristheonlyonethatsupportsthedatabasesqlinterfacestandardinitsSQLitedriversoIusethisinmyprojects-itwillmakeiteasytomigratemycodeinthefutureifIneedto

SamplesWecreatethefollowingSQL

CREATETABLE`userinfo`(

`uid`INTEGERPRIMARYKEYAUTOINCREMENT

`username`VARCHAR(64)NULL

`departname`VARCHAR(64)NULL

`created`DATENULL

)

Anexample

packagemain

import(

databasesql

fmt

time

_githubcommattngo-sqlite3

)

funcmain()

dberr=sqlOpen(sqlite3foodb)

checkErr(err)

insert

stmterr=dbPrepare(INSERTINTOuserinfo(usernamedepartnamecreated)values())

checkErr(err)

reserr=stmtExec(astaxie研发部门2012-12-09)

checkErr(err)

iderr=resLastInsertId()

checkErr(err)

fmtPrintln(id)

update

stmterr=dbPrepare(updateuserinfosetusername=whereuid=)

checkErr(err)

HowtouseSQLite

120

reserr=stmtExec(astaxieupdateid)

checkErr(err)

affecterr=resRowsAffected()

checkErr(err)

fmtPrintln(affect)

query

rowserr=dbQuery(SELECTFROMuserinfo)

checkErr(err)

varuidint

varusernamestring

vardepartmentstring

varcreatedtimeTime

forrowsNext()

err=rowsScan(ampuidampusernameampdepartmentampcreated)

checkErr(err)

fmtPrintln(uid)

fmtPrintln(username)

fmtPrintln(department)

fmtPrintln(created)

rowsClose()goodhabittoclose

delete

stmterr=dbPrepare(deletefromuserinfowhereuid=)

checkErr(err)

reserr=stmtExec(id)

checkErr(err)

affecterr=resRowsAffected()

checkErr(err)

fmtPrintln(affect)

dbClose()

funccheckErr(errerror)

iferr=nil

panic(err)

YoumayhavenoticedthatthecodeisalmostthesameasintheprevioussectionandthatweonlychangedthenameoftheregistereddriverandcalledsqlOpentoconnecttoSQLiteinadifferentway

Notethatsometimesyoucantusetheforstatementbecauseyoudonthavemorethanonerowthenyoucanusetheifstatement

ifrowsNext()

err=rowsScan(ampuidampusernameampdepartmentampcreated)

checkErr(err)

fmtPrintln(uid)

fmtPrintln(username)

fmtPrintln(department)

fmtPrintln(created)

AlsoyouhavetodoarowsNext()withoutusingthatyoucantfetchdataintheScanfunction

Transactions

HowtouseSQLite

121

TheaboveexampleshowshowyoufetchdatafromthedatabasebutwhenyouwanttowriteawebapplicationthenitwillnotonlybenecessarytofetchdatafromthedbbutitwillalsoberequiredtowritedataintoitForthatpurposeyoushouldusetransactionsbecauseforvariousreasonssuchashavingmultiplegoroutineswhichaccessthedatabasethedatabasemightgetlockedThisisundesirableinyourwebapplicationandtheuseoftransactionsiseffectiveinensuringyourdatabaseactivitieseitherpassorfailcompletelydependingoncircumstancesItisclearthatusingtransactionscanpreventalotofthingsfromgoingwrongwiththewebapp

trashSQLerr=databasePrepare(updatetasksetis_deleted=Ylast_modified_at=datetime()whereid=)

iferr=nil

fmtPrintln(err)

txerr=databaseBegin()

iferr=nil

fmtPrintln(err)

_err=txStmt(trashSQL)Exec(id)

iferr=nil

fmtPrintln(doingrollback)

txRollback()

else

txCommit()

Asitisclearfromtheaboveblockofcodeyoufirstprepareastatementafterwhichyouexecuteitdependingontheoutputofthatexecutionthenyoueitherrollitbackorcommitit

AsafinalnoteonthissectionthereisausefulSQLitemanagementtoolavailablehttpsqlitebrowserorg

LinksDirectoryPrevioussectionMySQLNextsectionPostgreSQL

HowtouseSQLite

122

54PostgreSQLPostgreSQLisanobject-relationaldatabasemanagementsystemavailableformanyplatformsincludingLinuxFreeBSDSolarisMicrosoftWindowsandMacOSXItisreleasedunderanMIT-stylelicenseandisthusfreeandopensourcesoftwareItslargerthanMySQLbecauseitsdesignedforenterpriseusageasanalternativetoOraclePostgresqlisagoodchoiceforenterprisetypeprojects

PostgreSQLdriversTherearemanydatabasedriversavailableforPostgreSQLHerearethreeexamplesofthem

httpsgithubcomlibpqsupportsdatabasesqlwritteninpureGohttpsgithubcomjbarhamgopgsqldriversupportsdatabasesqlwritteninpureGohttpsgithubcomlxngo-pgsqlsupportsdatabasesqlwritteninpureGo

Iwillusethefirstoneintheexamplesthatfollow

SamplesWecreatethefollowingSQL

CREATETABLEuserinfo

(

uidserialNOTNULL

usernamecharactervarying(100)NOTNULL

departnamecharactervarying(500)NOTNULL

Createddate

CONSTRAINTuserinfo_pkeyPRIMARYKEY(uid)

)

WITH(OIDS=FALSE)

Anexample

packagemain

import(

databasesql

fmt

_githubcomlibpq

time

)

const(

DB_USER=postgres

DB_PASSWORD=postgres

DB_NAME=test

)

funcmain()

dbinfo=fmtSprintf(user=spassword=sdbname=ssslmode=disable

DB_USERDB_PASSWORDDB_NAME)

dberr=sqlOpen(postgresdbinfo)

checkErr(err)

deferdbClose()

fmtPrintln(Insertingvalues)

varlastInsertIdint

err=dbQueryRow(INSERTINTOuserinfo(usernamedepartnamecreated)VALUES($1$2$3)returninguidastax

ie研发部门2012-12-09)Scan(amplastInsertId)

HowtousePostgreSQL

123

checkErr(err)

fmtPrintln(lastinsertedid=lastInsertId)

fmtPrintln(Updating)

stmterr=dbPrepare(updateuserinfosetusername=$1whereuid=$2)

checkErr(err)

reserr=stmtExec(astaxieupdatelastInsertId)

checkErr(err)

affecterr=resRowsAffected()

checkErr(err)

fmtPrintln(affectrowschanged)

fmtPrintln(Querying)

rowserr=dbQuery(SELECTFROMuserinfo)

checkErr(err)

forrowsNext()

varuidint

varusernamestring

vardepartmentstring

varcreatedtimeTime

err=rowsScan(ampuidampusernameampdepartmentampcreated)

checkErr(err)

fmtPrintln(uid|username|department|created)

fmtPrintf(3v|8v|6v|6vnuidusernamedepartmentcreated)

fmtPrintln(Deleting)

stmterr=dbPrepare(deletefromuserinfowhereuid=$1)

checkErr(err)

reserr=stmtExec(lastInsertId)

checkErr(err)

affecterr=resRowsAffected()

checkErr(err)

fmtPrintln(affectrowschanged)

funccheckErr(errerror)

iferr=nil

panic(err)

NotethatPostgreSQLusesthe$1$2formatinsteadofthethatMySQLusesandithasadifferentDSNformatinsqlOpenAnotherthingisthatthePostgreSQLdriverdoesnotsupportsqlResultLastInsertId()Soinsteadofthis

stmterr=dbPrepare(INSERTINTOuserinfo(usernamedepartnamecreated)VALUES($1$2$3))

reserr=stmtExec(astaxie研发部门2012-12-09)

fmtPrintln(resLastInsertId())

usedbQueryRow()andScan()togetthevalueforthelastinsertedid

err=dbQueryRow(INSERTINTOTABLE_NAMEvalues($1)returninguidVALUE1)Scan(amplastInsertId)

fmtPrintln(lastInsertId)

LinksDirectoryPrevioussectionSQLite

HowtousePostgreSQL

124

NextsectionDevelopORMbasedonbeedb

HowtousePostgreSQL

125

55DevelopORMbasedonbeedb(Projectbeedbisnolongermaintainedbutthecodesstillthere)

beedbisanORM(object-relationalmapper)developedinGobymeItusesidiomaticGotooperateondatabasesimplementingstruct-to-databasemappingandactsasalightweightGoORMframeworkThepurposeofdevelopingthisORMisnotonlytohelppeoplelearnhowtowriteanORMbutalsotofindagoodbalancebetweenfunctionalityandperformancewhenitcomestodatapersistence

beedbisanopensourceprojectthatsupportsbasicORMfunctionalitybutdoesntsupportassociationqueries

BecausebeedbsupportsdatabasesqlinterfacestandardsanydriverthatimplementsthisinterfacecanbeusedwithbeedbIvetestedthefollowingdrivers

Mysqlgithubgo-mysql-drivermysql

PostgreSQLgithubcomlibpq

SQLitegithubcommattngo-sqlite3

Mysqlgithubcomziutekmymysqlgodrv

MSADODBgithubcommattngo-adodb

Oraclegithubcommattngo-oci8

ODBCbitbucketorgmiquellamgodbc

InstallationYoucanusegogettoinstallbeedblocally

gogetgithubcomastaxiebeedb

InitializationFirstyouhavetoimportallthenecessarypackages

import(

databasesql

githubcomastaxiebeedb

_githubcomziutekmymysqlgodrv

)

Thenyouneedtoopenadatabaseconnectionandcreateabeedbobject(MySQLinthisexample)

dberr=sqlOpen(mymysqltestxiemengjun123456)

iferr=nil

panic(err)

orm=beedbNew(db)

beedbNew()actuallyhastwoargumentsThefirstisthedatabaseobjectandthesecondisforindicatingwhichdatabaseengineyoureusingIfyoureusingMySQLSQLiteyoucanjustskipthesecondargument

OtherwisethisargumentmustbesuppliedForinstanceinthecaseofSQLServer

HowtousebeedbORM

126

orm=beedbNew(dbmssql)

PostgreSQL

orm=beedbNew(dbpg)

beedbsupportsdebuggingUsethefollowingcodetoenableit

beedbOnDebug=true

NextwehaveastructfortheUserinfodatabasetablethatweusedinprevioussections

typeUserinfostruct

Uidint`PK`iftheprimarykeyisnotidyouneedtoaddtag`PK`foryourcustomizedprimarykey

Usernamestring

Departnamestring

CreatedtimeTime

Beawarethatbeedbauto-convertscamelcasenamestolowersnakecaseForexampleifwehaveUserInfoasthestructnamebeedbwillconvertittouser_infointhedatabaseThesameruleappliestostructfieldnames

InsertdataThefollowingexampleshowsyouhowtousebeedbtosaveastructinsteadofusingrawSQLcommandsWeusethebeedbSavemethodtoapplythechange

varsaveoneUserinfo

saveoneUsername=TestAddUser

saveoneDepartname=TestAddDepartname

saveoneCreated=timeNow()

ormSave(ampsaveone)

YoucanchecksaveoneUidaftertherecordisinserteditsvalueisaself-incrementedIDwhichtheSavemethodtakescareofforyou

beedbprovidesanotherwayofinsertingdatathisisviaGosmaptype

add=make(map[string]interface)

add[username]=astaxie

add[departname]=clouddevelop

add[created]=2012-12-02

ormSetTable(userinfo)Insert(add)

Insertmultipledata

addslice=make([]map[string]interface10)

add=make(map[string]interface)

add2=make(map[string]interface)

add[username]=astaxie

add[departname]=clouddevelop

add[created]=2012-12-02

add2[username]=astaxie2

add2[departname]=clouddevelop2

add2[created]=2012-12-02

addslice=append(addsliceaddadd2)

ormSetTable(userinfo)InsertBatch(addslice)

HowtousebeedbORM

127

ThemethodshownaboveissimilartoachainedquerywhichyoushouldbefamiliarwithifyouveeverusedjqueryItreturnstheoriginalORMobjectaftercallsthencontinuesdoingotherjobs

ThemethodSetTabletellstheORMwewanttoinsertourdataintotheuserinfotable

UpdatedataLetscontinueworkingwiththeaboveexampletoseehowtoupdatedataNowthatwehavetheprimarykeyofsaveone(Uid)beedbexecutesanupdateoperationinsteadofinsertinganewrecord

saveoneUsername=UpdateUsername

saveoneDepartname=UpdateDepartname

saveoneCreated=timeNow()

ormSave(ampsaveone)update

Likebeforeyoucanalsousemapforupdatingdata

t=make(map[string]interface)

t[username]=astaxie

ormSetTable(userinfo)SetPK(uid)Where(2)Update(t)

Letmeexplainsomeofthemethodsusedabove

SetPK()tellstheORMthatuidistheprimarykeyrecordsintheuserinfotableWhere()setsconditionsandsupportsmultipleargumentsIfthefirstargumentisanintegeritsashortformforWhere(ltprimarykeygt=ltvaluegt)Update()methodacceptsamapandupdatesthedatabase

QuerydataThebeedbqueryinterfaceisveryflexibleLetsseesomeexamples

Example1querybyprimarykey

varuserUserinfo

Whereacceptstwoargumentssupportsintegers

ormWhere(uid=27)Find(ampuser)

Example2

varuser2Userinfo

ormWhere(3)Find(ampuser2)shortformthatomitsprimarykey

Example3otherqueryconditions

varuser3Userinfo

Wheretwoargumentsareacceptedwithsupportforchartype

ormWhere(name=john)Find(ampuser3)

Example4morecomplexconditions

varuser4Userinfo

Wherethreeargumentsareaccepted

ormWhere(name=andageltjohn88)Find(ampuser4)

Examplestogetmultiplerecords

HowtousebeedbORM

128

Example1gets10recordswithidgt3thatstartswithposition20

varallusers[]Userinfo

err=ormWhere(idgt3)Limit(1020)FindAll(ampallusers)

Example2omitsthesecondargumentoflimitsoitstartswith0andgets10records

vartenusers[]Userinfo

err=ormWhere(idgt3)Limit(10)FindAll(amptenusers)

Example3getsallrecords

vareveryone[]Userinfo

err=ormOrderBy(uiddescusernameasc)FindAll(ampeveryone)

AsyoucanseetheLimitmethodisforlimitingthenumberofresults

Limit()supportstwoargumentsthenumberofresultsandthestartingposition0isthedefaultvalueofthestartingpositionOrderBy()isfororderingresultsTheargumentistheordercondition

AlltheexamplesherearesimplymappingrecordstostructsYoucanalsojustputthedataintoamapasfollows

a_=ormSetTable(userinfo)SetPK(uid)Where(2)Select(uidusername)FindMap()

Select()tellsbeedbhowmanyfieldsyouwanttogetfromthedatabasetableIfunspecifiedallfieldsarereturnedbydefaultFindMap()returnsthe[]map[string][]bytetypesoyouneedtoconverttoothertypesyourself

Deletedatabeedbprovidesrichmethodstodeletedata

Example1deleteasinglerecord

saveoneistheoneinaboveexample

ormDelete(ampsaveone)

Example2deletemultiplerecords

alluseristheslicewhichgetsmultiplerecords

ormDeleteAll(ampalluser)

Example3deleterecordsbySQL

ormSetTable(userinfo)Where(uidgt3)DeleteRow()

AssociationqueriesbeedbdoesntsupportjoiningbetweenstructsHoweversincesomeapplicationsneedthisfeaturehereisanimplementation

a_=ormSetTable(userinfo)Join(LEFTuserdetailuserinfouid=userdetailuid)

Where(userinfouid=1)Select(userinfouiduserinfousernameuserdetailprofile)FindMap()

HowtousebeedbORM

129

WeseeanewmethodcalledJoin()thathasthreearguments

ThefirstargumentTypeofJoinINNERLEFTOUTERCROSSetcThesecondargumentthetableyouwanttojoinwithThethirdargumentjoincondition

GroupByandHavingbeedbalsohasanimplementationofgroupbyandhaving

a_=ormSetTable(userinfo)GroupBy(username)Having(username=astaxie)FindMap()

GroupBy()indicatesthefieldthatisforgroupbyHaving()indicatesconditionsofhaving

FutureIhavereceivedalotoffeedbackonbeedbfrommanypeopleallaroundtheworldandImthinkingaboutreconfiguringthefollowingaspects

ImplementaninterfacedesignsimilartodatabasesqldriverinordertofacilitateCRUDoperationsImplementrelationaldatabaseassociationslikeonetooneonetomanyandmanytomanyHeresasample

typeProfilestruct

Nicknamestring

Mobilestring

typeUserinfostruct

Uidint

PK_Usernamestring

Departnamestring

CreatedtimeTime

ProfileHasOne

Auto-createtablesandindexesImplementaconnectionpoolusinggoroutines

LinksDirectoryPrevioussectionPostgreSQLNextsectionNoSQLdatabase

HowtousebeedbORM

130

56NoSQLdatabaseANoSQLdatabaseprovidesamechanismforthestorageandretrievalofdatathatuseslooserconsistencymodelsthantypicalrelationaldatabasesinordertoachievehorizontalscalingandhigheravailabilitySomeauthorsrefertothemasNotonlySQLtoemphasizethatsomeNoSQLsystemsdoallowSQL-likequerylanguagestobeused

AstheClanguageofthe21stcenturyGohasgoodsupportforNoSQLdatabasesincludingthepopularredismongoDBCassandraandMembaseNoSQLdatabases

redisredisisakey-valuestoragesystemlikeMemcachedthatsupportsthestringlistsetandzset(orderedset)valuetypes

TherearesomeGodatabasedriversforredis

httpsgithubcomgaryburdredigohttpsgithubcomgo-redisredishttpsgithubcomhoisieredishttpsgithubcomalphazeroGo-Redishttpsgithubcomsimonz05godis

Letsseehowtousethedriverthatredigotooperateonadatabase

packagemain

import(

fmt

githubcomgaryburdredigoredis

os

ossignal

syscall

time

)

var(

PoolredisPool

)

funcinit()

redisHost=6379

Pool=newPool(redisHost)

close()

funcnewPool(serverstring)redisPool

returnampredisPool

MaxIdle3

IdleTimeout240timeSecond

Dialfunc()(redisConnerror)

cerr=redisDial(tcpserver)

iferr=nil

returnnilerr

returncerr

TestOnBorrowfunc(credisConnttimeTime)error

_err=cDo(PING)

returnerr

NOSQL

131

funcclose()

c=make(chanosSignal1)

signalNotify(cosInterrupt)

signalNotify(csyscallSIGTERM)

signalNotify(csyscallSIGKILL)

gofunc()

lt-c

PoolClose()

osExit(0)

()

funcGet(keystring)([]byteerror)

conn=PoolGet()

deferconnClose()

vardata[]byte

dataerr=redisBytes(connDo(GETkey))

iferr=nil

returndatafmtErrorf(errorgetkeysvkeyerr)

returndataerr

funcmain()

testerr=Get(test)

fmtPrintln(testerr)

IforkedthelastofthesepackagesfixedsomebugsanduseditinmyshortURLservice(2millionPVeveryday)

httpsgithubcomastaxiegoredis

LetsseehowtousethedriverthatIforkedtooperateonadatabase

packagemain

import(

githubcomastaxiegoredis

fmt

)

funcmain()

varclientgoredisClient

SetthedefaultportinRedis

clientAddr=1270016379

stringmanipulation

clientSet(a[]byte(hello))

val_=clientGet(a)

fmtPrintln(string(val))

clientDel(a)

listoperation

vals=[]stringabcde

for_v=rangevals

clientRpush(l[]byte(v))

dbvals_=clientLrange(l04)

foriv=rangedbvals

println(istring(v))

clientDel(l)

NOSQL

132

WecanseethatitisquiteeasytooperateredisinGoandithashighperformanceItsclientcommandsarealmostthesameasredisbuilt-incommands

mongoDBmongoDB(fromhumongous)isanopensourcedocument-orienteddatabasesystemdevelopedandsupportedby10genItispartoftheNoSQLfamilyofdatabasesystemsInsteadofstoringdataintablesasisdoneinaclassicalrelationaldatabaseMongoDBstoresstructureddataasJSON-likedocumentswithdynamicschemas(MongoDBcallstheformatBSON)makingtheintegrationofdataincertaintypesofapplicationseasierandfaster

Figure51MongoDBcomparedtoMysql

ThebestdriverformongoDBiscalledmgoanditispossiblethatitwillbeincludedinthestandardlibraryinthefuture

Installmgo

gogetgopkginmgov2

Hereistheexample

packagemain

import(

fmt

gopkginmgov2

gopkginmgov2bson

log

)

typePersonstruct

Namestring

Phonestring

funcmain()

sessionerr=mgoDial(server1examplecomserver2examplecom)

iferr=nil

panic(err)

defersessionClose()

OptionalSwitchthesessiontoamonotonicbehavior

sessionSetMode(mgoMonotonictrue)

c=sessionDB(test)C(people)

err=cInsert(ampPersonAle+555381169639

ampPersonCla+555384028510)

iferr=nil

logFatal(err)

result=Person

err=cFind(bsonMnameAle)One(ampresult)

iferr=nil

logFatal(err)

fmtPrintln(PhoneresultPhone)

NOSQL

133

WecanseethattherearenobigdifferenceswhenitcomestooperatingonmgoorbeedbdatabasestheyarebothbasedonstructsThisistheGowayofdoingthings

LinksDirectoryPrevioussectionDevelopORMbasedonbeedbNextsectionSummary

NOSQL

134

57SummaryInthischapteryoufirstlearnedaboutthedesignofthedatabasesqlinterfaceandmanythird-partydatabasedriversforvariousdatabasetypesThenIintroducedbeedbanORMforrelationaldatabasestoyouIalsoshowedyousomesampledatabaseoperationsIntheendItalkedaboutafewNoSQLdatabasesWesawthatGoprovidesverygoodsupportforthoseNoSQLdatabases

AfterreadingthischapterIhopethatyouhaveabetterunderstandingofhowtooperatedatabasesinGoThisisthemostimportantpartofwebdevelopmentsoIwantyoutocompletelyunderstandthedesignconceptsofthedatabasesqlinterface

LinksDirectoryPrevioussectionNoSQLdatabaseNextsectionDatastorageandsession

Summary

135

6DatastorageandsessionsAnimportanttopicinwebdevelopmentisprovidingagooduserexperiencebutthefactthatHTTPisastatelessprotocolseemscontrarytothisspiritHowcanwecontrolthewholeprocessofviewingwebsitesforusersTheclassicsolutionsareusingcookiesandsessionswherecookiesserveastheclientsidemechanismandsessionsaresavedontheserversidewithauniqueidentifierforeverysingleuserNotethatsessionscanbepassedinURLsorcookiesoreveninyourdatabase(whichismuchmoresecurebutmayhamperyourapplicationperformance)

Insection61wearegoingtotalkaboutdifferencesbetweencookiesandsessionsInsection62youlllearnhowtousesessionsinGowithanimplementationofasessionmanagerInsection63wewilltalkaboutsessionhijackingandhowtopreventitwhenyouknowthatsessionscanbesavedanywhereThesessionmanagerwewillimplementinsection63willsavesessionsinmemorybutifweneedtoexpandourapplicationtoallowforsessionsharingitsalwaysbettertosavethesesessionsdirectlyintoourdatabaseWelltalkmoreaboutthisinsection64

LinksDirectoryPreviousChapterChapter5SummaryNextsectionSessionandcookies

Datastorageandsession

136

61SessionandcookiesSessionsandcookiesaretwoverycommonwebconceptsandarealsoveryeasytomisunderstandHowevertheyareextremelyimportantfortheauthorizationofpagesaswellasforgatheringpagestatisticsLetstakealookatthesetwousecases

SupposeyouwanttocrawlapagethatrestrictspublicaccesslikeatwitterusershomepageforinstanceOfcourseyoucanopenyourbrowserandtypeinyourusernameandpasswordtologinandaccessthatinformationbutso-calledwebcrawlingmeansthatweuseaprogramtoautomatethisprocesswithoutanyhumaninterventionThereforewehavetofindoutwhatisreallygoingonbehindthesceneswhenweuseabrowsertologin

WhenwefirstreceivealoginpageandtypeinausernameandpasswordafterwepresstheloginbuttonthebrowsersendsaPOSTrequesttotheremoteserverTheBrowserredirectstotheuserhomepageaftertheserververifiesthelogininformationandreturnsanHTTPresponseThequestionhereishowdoestheserverknowthatwehaveaccessprivilegesforthedesiredwebpageBecauseHTTPisstatelesstheserverhasnowayofknowingwhetherornotwepassedtheverificationinlaststepTheeasiestandperhapsthemostnaivesolutionistoappendtheusernameandpasswordtotheURLThisworksbutputstoomuchpressureontheserver(theservermustvalidateeveryrequestagainstthedatabase)andcanbedetrimentaltotheuserexperienceAnalternativewayofachievingthisgoalistosavetheusersidentityeitherontheserversideorclientsideusingcookiesandsessions

Cookiesinshortstorehistoricalinformation(includinguserlogininformation)ontheclientscomputerTheclientsbrowsersendsthesecookieseverytimetheuservisitsthesamewebsiteautomaticallycompletingtheloginstepfortheuser

Figure61cookieprinciple

SessionsontheotherhandstorehistoricalinformationontheserversideTheserverusesasessionidtoidentifydifferentsessionsandthesessionidthatisgeneratedbytheservershouldalwaysberandomanduniqueYoucanusecookiesorURLargumentstogettheclientsidentity

Figure62sessionprinciple

CookiesCookiesaremaintainedbybrowsersTheycanbemodifiedduringcommunicationbetweenwebserversandbrowsersWebapplicationscanaccesscookieinformationwhenusersvisitthecorrespondingwebsitesWithinmostbrowsersettingsthereisonesettingpertainingtocookieprivacyYoushouldbeabletoseesomethingsimilartothefollowingwhenyouopenit

Figure63cookieinbrowsers

Cookieshaveanexpirytimeandtherearetwotypesofcookiesdistinguishedbytheirlifecylessessioncookiesandpersistentcookies

IfyourapplicationdoesntsetacookieexpirytimethebrowserwillnotsaveitintothelocalfilesystemafterthebrowserisclosedThesecookiesarecalledsessioncookiesandthistypeofcookieisusuallysavedinmemoryinsteadoftothelocalfilesystem

Ifyourapplicationdoessetanexpirytime(forexamplesetMaxAge(606024))thebrowserwillsavethiscookietothelocalfilesystemanditwillnotbedeleteduntilreachingtheallottedexpirytimeCookiesthataresavedtothelocalfilesystemcanbesharedbydifferentbrowserprocesses-forexamplebytwoIEwindowsdifferentbrowsersusedifferentprocessesfordealingwithcookiesthataresavedinmemory  

Sessionandcookies

137

SetcookiesinGoGousestheSetCookiefunctioninthenethttppackagetosetcookies

httpSetCookie(wResponseWritercookieCookie)

wistheresponseoftherequestandcookieisastructLetsseewhatitlookslike

typeCookiestruct

Namestring

Valuestring

Pathstring

Domainstring

ExpirestimeTime

RawExpiresstring

MaxAge=0meansnoMax-Ageattributespecified

MaxAgelt0meansdeletecookienowequivalentlyMax-Age0

MaxAgegt0meansMax-Ageattributepresentandgiveninseconds

MaxAgeint

Securebool

HttpOnlybool

Rawstring

Unparsed[]stringRawtextofunparsedattribute-valuepairs

Hereisanexampleofsettingacookie

expiration=timeNow()Add(36524timeHour)

cookie=httpCookieNameusernameValueastaxieExpiresexpiration

httpSetCookie(wampcookie)

FetchcookiesinGoTheaboveexampleshowshowtosetacookieNowletsseehowtogetacookiethathasbeenset

cookie_=rCookie(username)

fmtFprint(wcookie)

Hereisanotherwaytogetacookie

for_cookie=rangerCookies()

fmtFprint(wcookieName)

Asyoucanseeitsveryconvenienttogetcookiesfromrequests

SessionsAsessionisaseriesofactionsormessagesForexampleyoucanthinkoftheactionsyoubetweenpickingupyourtelephonetohanginguptobeatypeofsessionWhenitcomestonetworkprotocolssessionshavemoretodowithconnectionsbetweenbrowsersandservers

Sessionshelptostoretheconnectionstatusbetweenserverandclientandthiscansometimesbeintheformofadatastoragestruct

Sessionandcookies

138

Sessionsareaserver-sidemechanismandusuallyemployhashtables(orsomethingsimilar)tosaveincominginformation

WhenanapplicationneedstoassignanewsessiontoaclienttheservershouldcheckifthereareanyexistingsessionsforthesameclientwithauniquesessionidIfthesessionidalreadyexiststheserverwilljustreturnthesamesessiontotheclientOntheotherhandifasessioniddoesntexistfortheclienttheservercreatesabrandnewsession(thisusuallyhappenswhentheserverhasdeletedthecorrespondingsessionidbuttheuserhasappendedtheoldsessionmanually)

Thesessionitselfisnotcomplexbutitsimplementationanddeploymentaresoyoucannotuseonewaytorulethemall

SummaryInconclusionthepurposeofsessionsandcookiesarethesameTheyarebothforovercomingthestatelessnessofHTTPbuttheyusedifferentmethodsSessionsusecookiestosavesessionidsontheclientsideandsaveallotherinformationontheserversideCookiessaveallclientinformationontheclientsideYoumayhavenoticedthatcookieshavesomesecurityproblemsForexampleusernamesandpasswordscanpotentiallybecrackedandcollectedbymaliciousthirdpartywebsites

Herearetwocommonexploits

1 appAsettinganunexpectedcookieforappB2 XSSattackappAusestheJavaScriptdocumentcookietoaccessthecookiesofappB

AfterfinishingthissectionyoushouldknowsomeofthebasicconceptsofcookiesandsessionsYoushouldbeabletounderstandthedifferencesbetweenthemsothatyouwontkillyourselfwhenbugsinevitablyemergeWelldiscusssessionsinmoredetailinthefollowingsections

LinksDirectoryPrevioussectionDatastorageandsessionNextsectionHowtousesessioninGo

Sessionandcookies

139

62HowtousesessionsinGoInsection61welearnedthatsessionsareonesolutionforverifyingusersandthatfornowtheGostandardlibrarydoesnothavebaked-insupportforsessionsorsessionhandlingSoweregoingtoimplementourownversionofasessionmanagerinGo

CreatingsessionsThebasicprinciplebehindsessionsisthataservermaintainsinformationforeverysingleclientandclientsrelyonuniquesessionidstoaccessthisinformationWhenusersvisitthewebapplicationtheserverwillcreateanewsessionwiththefollowingthreestepsasneeded

CreateauniquesessionidOpenupadatastoragespacenormallywesavesessionsinmemorybutyouwillloseallsessiondataifthesystemisaccidentallyinterruptedThiscanbeaveryseriousissueifwebapplicationdealswithsensitivedatalikeinelectroniccommerceforinstanceInordertosolvethisproblemyoucaninsteadsaveyoursessiondatainadatabaseorfilesystemThismakesdatapersistencemorereliableandeasytosharewithotherapplicationsalthoughthetradeoffisthatmoreserver-sideIOisneededtoreadandwritethesesessionsSendtheuniquesessionidtotheclient

ThekeystephereistosendtheuniquesessionidtotheclientInthecontextofastandardHTTPresponseyoucaneitherusetheresponselineheaderorbodytoaccomplishthisthereforewehavetwowaystosendsessionidstoclientsbycookiesorURLrewrites

CookiestheservercaneasilyuseSet-cookieinsideofaresponseheadertosendasessionidtoaclientandaclientcanthenusethiscookieforfuturerequestsweoftensettheexpirytimeforcookiescontainingsessioninformationto0whichmeansthecookiewillbesavedinmemoryandonlydeletedafterusershaveclosetheirbrowsersURLrewriteappendthesessionidasargumentsintheURLforallpagesThiswayseemsmessybutitsthebestchoiceifclientshavedisabledcookiesintheirbrowsers

UseGotomanagesessionsWevetalkedaboutconstructingsessionsandyoushouldnowhaveageneraloverviewofitbuthowcanweusesessionsondynamicpagesLetstakeacloserlookatthelifecycleofasessionsowecancontinueimplementingourGosessionmanager

Sessionmanagementdesign

Hereisalistofsomeofthekeyconsiderationsinsessionmanagementdesign

GlobalsessionmanagerKeepsessioniduniqueHaveonesessionforeveryuserSessionstorageinmemoryfileordatabaseDealwithexpiredsessions

NextwellexamineacompleteexampleofaGosessionmanagerandtherationalebehindsomeofitsdesigndecisions

Sessionmanager

Defineaglobalsessionmanager

HowtousesessioninGo

140

typeManagerstruct

cookieNamestringprivatecookiename

locksyncMutexprotectssession

providerProvider

maxlifetimeint64

funcNewManager(provideNamecookieNamestringmaxlifetimeint64)(Managererror)

providerok=provides[provideName]

ifok

returnnilfmtErrorf(sessionunknownprovideq(forgottenimport)provideName)

returnampManagerproviderprovidercookieNamecookieNamemaxlifetimemaxlifetimenil

Createaglobalsessionmanagerinthemain()function

varglobalSessionssessionManager

Theninitializethesessionmanager

funcinit()

globalSessions=NewManager(memorygosessionid3600)

WeknowthatwecansavesessionsinmanywaysincludinginmemorythefilesystemordirectlyintothedatabaseWeneedtodefineaProviderinterfaceinordertorepresenttheunderlyingstructureofoursessionmanager

typeProviderinterface

SessionInit(sidstring)(Sessionerror)

SessionRead(sidstring)(Sessionerror)

SessionDestroy(sidstring)error

SessionGC(maxLifeTimeint64)

SessionInitimplementstheinitializationofasessionandreturnsanewsessionifitsucceedsSessionReadreturnsasessionrepresentedbythecorrespondingsidCreatesanewsessionandreturnsitifitdoesnotalreadyexistSessionDestroygivenansiddeletesthecorrespondingsessionSessionGCdeletesexpiredsessionvariablesaccordingtomaxLifeTime

SowhatmethodsshouldoursessioninterfacehaveIfyouhaveanyexperienceinwebdevelopmentyoushouldknowthatthereareonlyfouroperationsforsessionssetvaluegetvaluedeletevalueandgetcurrentsessionidSooursessioninterfaceshouldhavefourmethodstoperformtheseoperations

typeSessioninterface

Set(keyvalueinterface)errorsetsessionvalue

Get(keyinterface)interfacegetsessionvalue

Delete(keyinterface)errordeletesessionvalue

SessionID()stringbackcurrentsessionID

ThisdesigntakesitsrootsfromthedatabasesqldriverwhichdefinestheinterfacefirstthenregistersspecificstructureswhenwewanttouseitThefollowingcodeistheinternalimplementationofasessionregisterfunction

HowtousesessioninGo

141

varprovides=make(map[string]Provider)

Registermakesasessionprovideravailablebytheprovidedname

IfaRegisteriscalledtwicewiththesamenameorifthedriverisnil

itpanics

funcRegister(namestringproviderProvider)

ifprovider==nil

panic(sessionRegisterproviderisnil)

if_dup=provides[name]dup

panic(sessionRegistercalledtwiceforprovider+name)

provides[name]=provider

UniquesessionidsSessionidsareforidentifyingusersofwebapplicationssotheymustbeuniqueThefollowingcodeshowshowtoachievethisgoal

func(managerManager)sessionId()string

b=make([]byte32)

if_err=ioReadFull(randReaderb)err=nil

return

returnbase64URLEncodingEncodeToString(b)

CreatingasessionWeneedtoallocateorgetanexistingsessioninordertovalidateuseroperationsTheSessionStartfunctionisforcheckingtheexistenceofanysessionsrelatedtothecurrentuserandcreatinganewsessionifnoneisfound

func(managerManager)SessionStart(whttpResponseWriterrhttpRequest)(sessionSession)

managerlockLock()

defermanagerlockUnlock()

cookieerr=rCookie(managercookieName)

iferr=nil||cookieValue==

sid=managersessionId()

session_=managerproviderSessionInit(sid)

cookie=httpCookieNamemanagercookieNameValueurlQueryEscape(sid)PathHttpOnlytrueM

axAgeint(managermaxlifetime)

httpSetCookie(wampcookie)

else

sid_=urlQueryUnescape(cookieValue)

session_=managerproviderSessionRead(sid)

return

Hereisanexamplethatusessessionsforaloginoperation

funclogin(whttpResponseWriterrhttpRequest)

sess=globalSessionsSessionStart(wr)

rParseForm()

ifrMethod==GET

t_=templateParseFiles(logingtpl)

wHeader()Set(Content-Typetexthtml)

tExecute(wsessGet(username))

else

sessSet(usernamerForm[username])

httpRedirect(wr302)

HowtousesessioninGo

142

Operationvaluesetgetanddelete

TheSessionStartfunctionreturnsavariablethatimplementsasessioninterfaceHowdoweuseit

YousawsessionGet(uid)intheaboveexampleforabasicoperationNowletsexamineamoredetailedexample

funccount(whttpResponseWriterrhttpRequest)

sess=globalSessionsSessionStart(wr)

createtime=sessGet(createtime)

ifcreatetime==nil

sessSet(createtimetimeNow()Unix())

elseif(createtime(int64)+360)lt(timeNow()Unix())

globalSessionsSessionDestroy(wr)

sess=globalSessionsSessionStart(wr)

ct=sessGet(countnum)

ifct==nil

sessSet(countnum1)

else

sessSet(countnum(ct(int)+1))

t_=templateParseFiles(countgtpl)

wHeader()Set(Content-Typetexthtml)

tExecute(wsessGet(countnum))

AsyoucanseeoperatingonsessionssimplyinvolvesusingthekeyvaluepatternintheSetGetandDeleteoperations

BecausesessionshavetheconceptofanexpirytimewedefinetheGCtoupdatethesessionslatestmodifytimeThiswaytheGCwillnotdeletesessionsthathaveexpiredbutarestillbeingused

ResetsessionsWeknowthatwebapplicationshavealogoutoperationWhenuserslogoutweneedtodeletethecorrespondingsessionWevealreadyusedtheresetoperationinaboveexample-nowletstakealookatthefunctionbody

Destroysessionid

func(managerManager)SessionDestroy(whttpResponseWriterrhttpRequest)

cookieerr=rCookie(managercookieName)

iferr=nil||cookieValue==

return

else

managerlockLock()

defermanagerlockUnlock()

managerproviderSessionDestroy(cookieValue)

expiration=timeNow()

cookie=httpCookieNamemanagercookieNamePathHttpOnlytrueExpiresexpirationMaxAge-1

httpSetCookie(wampcookie)

Deletesessions

LetsseehowtoletthesessionmanagerdeleteasessionWeneedtostarttheGCinthemain()function

HowtousesessioninGo

143

funcinit()

goglobalSessionsGC()

func(managerManager)GC()

managerlockLock()

defermanagerlockUnlock()

managerproviderSessionGC(managermaxlifetime)

timeAfterFunc(timeDuration(managermaxlifetime)func()managerGC())

WeseethattheGCmakesfulluseofthetimerfunctioninthetimepackageItautomaticallycallsGCwhenthesessiontimesoutensuringthatallsessionsareusableduringmaxLifeTimeAsimilarsolutioncanbeusedtocountonlineusers

SummarySofarweimplementedasessionmanagertomanageglobalsessionsinthewebapplicationanddefinedtheProviderinterfaceasthestorageimplementationofSessionInthenextsectionwearegoingtotalkabouthowtoimplementProviderforadditionalsessionstoragestructureswhichyouwillbeabletoreferenceinthefuture

LinksDirectoryPrevioussectionSessionandcookiesNextsectionSessionstorage

HowtousesessioninGo

144

63SessionstorageWeintroducedasimplesessionmanagersworkingprinciplesintheprevioussectionandamongotherthingswedefinedasessionstorageinterfaceInthissectionImgoingtoshowyouanexampleofamemorybasedsessionstorageenginethatimplementsthisinterfaceYoucantailorthistootherformsofsessionstorageaswell

packagememory

import(

containerlist

githubcomastaxiesession

sync

time

)

varpder=ampProviderlistlistNew()

typeSessionStorestruct

sidstringuniquesessionid

timeAccessedtimeTimelastaccesstime

valuemap[interface]interfacesessionvaluestoredinside

func(stSessionStore)Set(keyvalueinterface)error

stvalue[key]=value

pderSessionUpdate(stsid)

returnnil

func(stSessionStore)Get(keyinterface)interface

pderSessionUpdate(stsid)

ifvok=stvalue[key]ok

returnv

else

returnnil

returnnil

func(stSessionStore)Delete(keyinterface)error

delete(stvaluekey)

pderSessionUpdate(stsid)

returnnil

func(stSessionStore)SessionID()string

returnstsid

typeProviderstruct

locksyncMutexlock

sessionsmap[string]listElementsaveinmemory

listlistListgc

func(pderProvider)SessionInit(sidstring)(sessionSessionerror)

pderlockLock()

deferpderlockUnlock()

v=make(map[interface]interface0)

newsess=ampSessionStoresidsidtimeAccessedtimeNow()valuev

element=pderlistPushBack(newsess)

pdersessions[sid]=element

returnnewsessnil

func(pderProvider)SessionRead(sidstring)(sessionSessionerror)

ifelementok=pdersessions[sid]ok

Sessionstorage

145

returnelementValue(SessionStore)nil

else

sesserr=pderSessionInit(sid)

returnsesserr

returnnilnil

func(pderProvider)SessionDestroy(sidstring)error

ifelementok=pdersessions[sid]ok

delete(pdersessionssid)

pderlistRemove(element)

returnnil

returnnil

func(pderProvider)SessionGC(maxlifetimeint64)

pderlockLock()

deferpderlockUnlock()

for

element=pderlistBack()

ifelement==nil

break

if(elementValue(SessionStore)timeAccessedUnix()+maxlifetime)lttimeNow()Unix()

pderlistRemove(element)

delete(pdersessionselementValue(SessionStore)sid)

else

break

func(pderProvider)SessionUpdate(sidstring)error

pderlockLock()

deferpderlockUnlock()

ifelementok=pdersessions[sid]ok

elementValue(SessionStore)timeAccessed=timeNow()

pderlistMoveToFront(element)

returnnil

returnnil

funcinit()

pdersessions=make(map[string]listElement0)

sessionRegister(memorypder)

TheaboveexampleimplementsamemorybasedsessionstoragemechanismItusesitsinit()functiontoregisterthisstorageenginetothesessionmanagerSohowdoweregisterthisenginefromourmainprogram

import(

githubcomastaxiesession

_githubcomastaxiesessionprovidersmemory

)

Weusetheblankimportmechanism(whichwillinvokethepackagesinit()functionautomatically)toregisterthisenginetoasessionmanagerWethenusethefollowingcodetoinitializethesessionmanager

Sessionstorage

146

varglobalSessionssessionManager

initializeininit()function

funcinit()

globalSessions_=sessionNewManager(memorygosessionid3600)

goglobalSessionsGC()

LinksDirectoryPrevioussectionHowtousesessionsinGoNextsectionPreventsessionhijacking

Sessionstorage

147

64PreventingsessionhijackingSessionhijackingisacommonyetserioussecuritythreatClientsusesessionidsforvalidationandotherpurposeswhencommunicatingwithserversUnfortunatelymaliciousthirdpartiescansometimestrackthesecommunicationsandfigureouttheclientsessionid

Inthissectionwearegoingtoshowyouhowtohijackasessionforeducationalpurposes

ThesessionhijackingprocessThefollowingcodeisacounterforthecountvariable

funccount(whttpResponseWriterrhttpRequest)

sess=globalSessionsSessionStart(wr)

ct=sessGet(countnum)

ifct==nil

sessSet(countnum1)

else

sessSet(countnum(ct(int)+1))

t_=templateParseFiles(countgtpl)

wHeader()Set(Content-Typetexthtml)

tExecute(wsessGet(countnum))

Thecontentofcountgtplisasfollows

HiNowcount

Wecanseethefollowingcontentinthebrowser

Figure64countinbrowser

Keeprefreshinguntilthenumberbecomes6thenopenthebrowserscookiemanager(Iusechromehere)Youshouldbeabletoseethefollowinginformation

Figure65cookiessavedinabrowser

Thisstepisveryimportantopenanotherbrowser(Iusefirefoxhere)copytheURLtothenewbrowseropenacookiesimulatortocreateanewcookieandinputexactlythesamevalueasthecookiewesawinourfirstbrowser

Figure66Simulateacookie

Refreshthepageandyoullseethefollowing

Figure67hijackingthesessionhassucceeded

HereweseethatwecanhijacksessionsbetweendifferentbrowsersandactionsperformedinonebrowsercanaffectthestateofapageinanotherbrowserBecauseHTTPisstatelessthereisnowayofknowingthatthesessionidfromfirefoxissimulatedandchromeisalsonotabletoknowthatitssessionidhasbeenhijacked

Preventhijackofsession

148

preventsessionhijacking

cookieonlyandtoken

ThroughthissimpleexampleofhijackingasessionyoucanseethatitsverydangerousbecauseitallowsattackerstodowhatevertheywantSohowcanwepreventsessionhijacking

ThefirststepistoonlysetsessionidsincookiesinsteadofinURLrewritesAlsoweshouldsetthehttponlycookiepropertytotrueThisrestrictsclient-sidescriptsfromgainingaccesstothesessionidUsingthesetechniquescookiescannotbeaccessedbyXSSanditwontbeaseasyaswedemonstratedtogetasessionidfromacookiemanager

ThesecondstepistoaddatokentoeveryrequestSimilartothemannerinwhichwedealtwithrepeatingformsubmissionsinprevioussectionsweaddahiddenfieldthatcontainsatokenWhenarequestissenttotheserverwecanverifythistokentoprovethattherequestisunique

h=md5New()

salt=astaxie^7amp8888

ioWriteString(hsalt+timeNow()String())

token=fmtSprintf(xhSum(nil))

ifrForm[token]=token

asktologin

sessSet(tokentoken)

SessionidtimeoutAnothersolutionistoaddacreatetimeforeverysessionandtoreplaceexpiredsessionidswithnewonesThiscanpreventsessionhijackingundercertaincircumstancessuchaswhenthehijackisattemptedtoolate

createtime=sessGet(createtime)

ifcreatetime==nil

sessSet(createtimetimeNow()Unix())

elseif(createtime(int64)+60)lt(timeNow()Unix())

globalSessionsSessionDestroy(wr)

sess=globalSessionsSessionStart(wr)

Wesetavaluetosavethecreatetimeandcheckifitsexpired(Iset60secondshere)Thisstepcanoftenthwartsessionhijackingattempts

BycombiningthetwosolutionssetoutaboveyouwillbeabletopreventmostsessionhijackingattemptsfromsucceedingOntheonehandsessionidsthatarefrequentlyresetwillresultinanattackeralwaysgettingexpiredanduselesssessionidsontheotherhandbysettingthehttponlypropertyoncookiesandensuringthatsessionidscanonlybepassedviacookiesallURLbasedattacksaremitigatedFinallywesetMaxAge=0onourcookieswhichmeansthatthesessionidswillnotbesavedinthebrowserhistory

LinksDirectoryPrevioussectionSessionstorageNextsectionSummary

Preventhijackofsession

149

65SummaryInthischapterwelearnedaboutthedefinitionandpurposeofsessionsandcookiesandtherelationshipbetweenthetwoSinceGodoesntsupportsessionsinitsstandardlibrarywealsodesignedourownsessionmanagerWewentthrougheverythingfromcreatingclientsessionstodeletingthemWethendefinedaninterfacecalledProviderwhichsupportsallsessionstoragestructuresInsection63weimplementedamemorybasedsessionmanagertopersistclientdataacrosssessionsInsection64IdemonstratedonewayofhijackingasessionThenwelookedathowtopreventyourownsessionsfrombeinghijackedIhopethatyounowunderstandmostoftheworkingprinciplesbehindsessionssothatyoureabletosafelyusetheminyourapplications

LinksDirectoryPrevioussectionPreventsessionhijackingNextchapterTextfiles

Summary

150

7TextfilesHandlingtextfilesisabigpartofwebdevelopmentWeoftenneedtoproduceorhandlereceivedtextcontentincludingstringsnumbersJSONXMLetcAsahighperformancelanguageGohasgoodsupportforthisinitsstandardlibraryYoullfindthatthesesupportinglibrariesarejustawesomeandwillallowyoutoeasilydealwithanytextcontentyoumayencounterThischaptercontains4sectionsandwillgiveyouafullintroductiontotextprocessinginGo

XMLisaninteractivelanguagethatiscommonlyusedinmanyAPIsmanywebserverswritteninJavauseXMLastheirstandardinteractionlanguageWellmoretalkaboutXMLinsection71Insection72welltakealookatJSONwhichhasbeenverypopularinrecentyearsandismuchmoreconvenientthanXMLInsection73wearegoingtotalkaboutregularexpressionswhich(forthemajorityofpeople)lookslikealanguageusedbyaliensInsection74youwillseehowtheMVCpatternisusedtodevelopapplicationsinGoandalsohowtouseGostemplatepackagefortemplatingyourviewsInsection75wellintroduceyoutofileandfolderoperationsFinallywewillexplainsomeGostringoperationsinsection76

LinksDirectoryPreviousChapterChapter6SummaryNextsectionXML

Textfiles

151

71XMLXMLisacommonlyuseddatacommunicationformatinwebservicesTodayitsassumingamoreandmoreimportantroleinwebdevelopmentInthissectionweregoingtointroducehowtoworkwithXMLthroughGosstandardlibrary

IwillnotmakeanyattemptstoteachXMLssyntaxorconventionsForthatpleasereadmoredocumentationaboutXMLitselfWewillonlyfocusonhowtoencodeanddecodeXMLfilesinGo

SupposeyouworkinITandyouhavetodealwiththefollowingXMLconfigurationfile

ltxmlversion=10encoding=utf-8gt

ltserversversion=1gt

ltservergt

ltserverNamegtShanghai_VPNltserverNamegt

ltserverIPgt127001ltserverIPgt

ltservergt

ltservergt

ltserverNamegtBeijing_VPNltserverNamegt

ltserverIPgt127002ltserverIPgt

ltservergt

ltserversgt

TheaboveXMLdocumentcontainstwokindsofinformationaboutyourservertheservernameandIPWewillusethisdocumentinourfollowingexamples

ParseXMLHowdoweparsethisXMLdocumentWecanusetheUnmarshalfunctioninGosxmlpackagetodothis

funcUnmarshal(data[]bytevinterface)error

thedataparameterreceivesadatastreamfromanXMLsourceandvisthestructureyouwanttooutputtheparsedXMLtoItisaninterfacewhichmeansyoucanconvertXMLtoanystructureyoudesireHerewellonlytalkabouthowtoconvertfromXMLtothestructtypesincetheysharesimilartreestructures

Samplecode

XML

152

packagemain

import(

encodingxml

fmt

ioioutil

os

)

typeRecurlyserversstruct

XMLNamexmlName`xmlservers`

Versionstring`xmlversionattr`

Svs[]server`xmlserver`

Descriptionstring`xmlinnerxml`

typeserverstruct

XMLNamexmlName`xmlserver`

ServerNamestring`xmlserverName`

ServerIPstring`xmlserverIP`

funcmain()

fileerr=osOpen(serversxml)Forreadaccess

iferr=nil

fmtPrintf(errorverr)

return

deferfileClose()

dataerr=ioutilReadAll(file)

iferr=nil

fmtPrintf(errorverr)

return

v=Recurlyservers

err=xmlUnmarshal(dataampv)

iferr=nil

fmtPrintf(errorverr)

return

fmtPrintln(v)

XMLisactuallyatreedatastructureandwecandefineaverysimilarstructureusingstructsinGothenusexmlUnmarshaltoconvertfromXMLtoourstructobjectThesamplecodewillprintthefollowingcontent

servers1[serverShanghai_VPN127001serverBeijing_VPN127002]

ltservergt

ltserverNamegtShanghai_VPNltserverNamegt

ltserverIPgt127001ltserverIPgt

ltservergt

ltservergt

ltserverNamegtBeijing_VPNltserverNamegt

ltserverIPgt127002ltserverIPgt

ltservergt

WeusexmlUnmarshaltoparsetheXMLdocumenttothecorrespondingstructobjectYoushouldseethatwehavesomethinglikexmlserverNameinourstructThisisafeatureofstructscalledstructtagsforhelpingwithreflectionLetsseethedefinitionofUnmarshalagain

funcUnmarshal(data[]bytevinterface)error

XML

153

ThefirstargumentisanXMLdatastreamThesecondargumentisstoragetypeandsupportsthestructsliceandstringtypesGosXMLpackageusesreflectionfordatamappingsoallfieldsinvshouldbeexportedHoweverthiscausesaproblemhowdoesitknowwhichXMLfieldcorrespondstothemappedstructfieldTheansweristhattheXMLparserparsesdatainacertainorderThelibrarywilltrytofindthematchingstructtagfirstIfamatchcannotbefoundthenitsearchesthroughthestructfieldnamesBeawarethatalltagsfieldnamesandXMLelementsarecasesensitivesoyouhavetomakesurethatthereisaone-to-onecorrespondenceforthemappingtosucceed

GosreflectionmechanismallowsyoutousethistaginformationtoreflectXMLdatatoastructobjectIfyouwanttoknowmoreaboutreflectioninGopleasereadthepackagedocumentationonstructtagsandreflection

HerearesomeruleswhenusingthexmlpackagetoparseXMLdocumentstostructs

Ifthefieldtypeisastringor[]bytewiththetaginnerxmlUnmarshalwillassignrawXMLdatatoitlikeDescriptionintheaboveexample

Shanghai_VPN127001Beijing_VPN127002

IfafieldiscalledXMLNameanditstypeisxmlNamethenitgetstheelementnamelikeserversinaboveexample

IfafieldstagcontainsthecorrespondingelementnamethenitgetstheelementnameaswelllikeservernameandserveripintheaboveexampleIfafieldstagcontainsattrthenitgetsthecorrespondingelementsattributelikeversioninaboveexampleIfafieldstagcontainssomethinglikeagtbgtcitgetsthevalueoftheelementcofnodebofnodeaIfafieldstagcontains=thenitgetsnothingIfafieldstagcontainsanythenitgetsallchildelementswhichdonotfittheotherrulesIftheXMLelementshaveoneormorecommentsallofthesecommentswillbeaddedtothefirstfieldthathasthetagthatcontainscommentsThisfieldtypecanbeastringor[]byteIfthiskindoffielddoesnotexistallcommentsarediscarded

TheserulestellyouhowtodefinetagsinstructsOnceyouunderstandtheserulesmappingXMLtostructswillbeaseasyasthesamplecodeaboveBecausetagsandXMLelementshaveaone-to-onecorrespondencewecanalsouseslicestorepresentmultipleelementsonthesamelevel

Notethatallfieldsinstructsshouldbeexported(capitalized)inordertoparsedatacorrectly

ProduceXMLWhatifwewanttoproduceanXMLdocumentinsteadofparsingoneHowdowedothisinGoUnsurprisinglythexmlpackageprovidestwofunctionswhichareMarshalandMarshalIndentwherethesecondfunctionautomaticallyindentsthemarshalledXMLdocumentTheirdefinitionasfollows

funcMarshal(vinterface)([]byteerror)

funcMarshalIndent(vinterfaceprefixindentstring)([]byteerror)

ThefirstargumentinbothofthesefunctionsisforstoringamarshalledXMLdatastream

Letslookatanexampletoseehowthisworks

XML

154

packagemain

import(

encodingxml

fmt

os

)

typeServersstruct

XMLNamexmlName`xmlservers`

Versionstring`xmlversionattr`

Svs[]server`xmlserver`

typeserverstruct

ServerNamestring`xmlserverName`

ServerIPstring`xmlserverIP`

funcmain()

v=ampServersVersion1

vSvs=append(vSvsserverShanghai_VPN127001)

vSvs=append(vSvsserverBeijing_VPN127002)

outputerr=xmlMarshalIndent(v)

iferr=nil

fmtPrintf(errorvnerr)

osStdoutWrite([]byte(xmlHeader))

osStdoutWrite(output)

Theaboveexampleprintsthefollowinginformation

ltxmlversion=10encoding=UTF-8gt

ltserversversion=1gt

ltservergt

ltserverNamegtShanghai_VPNltserverNamegt

ltserverIPgt127001ltserverIPgt

ltservergt

ltservergt

ltserverNamegtBeijing_VPNltserverNamegt

ltserverIPgt127002ltserverIPgt

ltservergt

ltserversgt

AswevepreviouslydefinedthereasonwehaveosStdoutWrite([]byte(xmlHeader))isbecausebothxmlMarshalIndentandxmlMarshaldonotoutputXMLheadersontheirownsowehavetoexplicitlyprinttheminordertoproduceXMLdocumentscorrectly

HerewecanseethatMarshalalsoreceivesavparameteroftypeinterfaceSowhataretheruleswhenmarshallingtoanXMLdocument

IfvisanarrayorsliceitprintsallelementslikeavalueIfvisapointeritprintsthecontentthatvispointingtoprintingnothingwhenvisnilIfvisainterfaceitdealwiththeinterfaceaswellIfvisoneoftheothertypesitprintsthevalueofthattype

SohowdoesxmlMarshaldecidetheelementsnameItfollowstheensuingrules

IfvisastructitdefinesthenameinthetagofXMLNameThefieldnameisXMLNameandthetypeisxmlNameFieldtaginstructFieldnameinstructTypenameofmarshal

XML

155

ThenweneedtofigureouthowtosettagsinordertoproducethefinalXMLdocument

XMLNamewillnotbeprintedFieldsthathavetagscontaining-willnotbeprintedIfatagcontainsnameattritusesnameastheattributenameandthefieldvalueasthevaluelikeversionintheaboveexampleIfatagcontainsattritusesthefieldsnameastheattributenameandthefieldvalueasitsvalueIfatagcontainschardataitprintscharacterdatainsteadofelementIfatagcontainsinnerxmlitprintstherawvalueIfatagcontainscommentitprintsitasacommentwithoutescapingsoyoucannothave--initsvalueIfatagcontainsomitemptyitomitsthisfieldifitsvalueiszero-valueincludingfalse0nilpointerornilinterfacezerolengthofarrayslicemapandstringIfatagcontainsagtbgtcitprintsthreeelementswhereacontainsbandbcontainsclikeinthefollowingcode `xmlFirstNamestringxmlnamegtfirstLastNamestringxmlnamegtlast`

Asta

Xieltnamegt```YoumayhavenoticedthatstructtagsareveryusefulfordealingwithXMLandthesamegoesfortheotherdataformatswellbediscussinginthefollowingsectionsIfyoustillfindthatyouhaveproblemswithworkingwithstructtagsyoushouldprobablyreadmoredocumentationaboutthembeforedivingintothenextsection

LinksDirectoryPrevioussectionTextfilesNextsectionJSON

XML

156

72JSONJSON(JavaScriptObjectNotation)isalightweightdataexchangelanguagewhichisbasedontextdescriptionItsadvantagesincludebeingself-descriptiveeasytounderstandetcEventhoughitisasubsetofJavaScriptJSONusesadifferenttextformattheresultbeingthatitcanbeconsideredasanindependentlanguageJSONbearssimilaritytoC-familylanguages

ThebiggestdifferencebetweenJSONandXMListhatXMLisacompletemarkuplanguagewhereasJSONisnotJSONissmallerandfasterthanXMLthereforeitsmucheasierandquickertoparseinbrowserswhichisoneofthereasonswhymanyopenplatformschoosetouseJSONastheirdataexchangeinterfacelanguage

SinceJSONisbecomingmoreandmoreimportantinwebdevelopmentletstakealookatthelevelofsupportGohasforJSONYoullfindthatGosstandardlibraryhasverygoodsupportforencodinganddecodingJSON

HereweuseJSONtorepresenttheexampleintheprevioussection

servers[serverNameShanghai_VPNserverIP127001serverNameBeijing_VPNserverIP127002]

TherestofthissectionwillusethisJSONdatatointroduceJSONconceptsinGo

ParseJSON

Parsetostruct

SupposewehavetheJSONintheaboveexampleHowcanweparsethisdataandmapittoastructinGoGoprovidesthefollowingfunctionforjustthispurpose

funcUnmarshal(data[]bytevinterface)error

Wecanusethisfunctionlikeso

packagemain

import(

encodingjson

fmt

)

typeServerstruct

ServerNamestring

ServerIPstring

typeServerslicestruct

Servers[]Server

funcmain()

varsServerslice

str=`servers[serverNameShanghai_VPNserverIP127001serverNameBeijing_VPNserverIP

127002]`

jsonUnmarshal([]byte(str)amps)

fmtPrintln(s)

JSON

157

IntheaboveexamplewedefinedacorrespondingstructsinGoforourJSONusingsliceforanarrayofJSONobjectsandfieldnameasourJSONkeysButhowdoesGoknowwhichJSONobjectcorrespondstowhichspecificstructfiledSupposewehaveakeycalledFooinJSONHowdowefinditscorrespondingfield

FirstGotriestofindthe(capitalised)exportedfieldwhosetagcontainsFooIfnomatchcanbefoundlookforthefieldwhosenameisFooIftherearestillnotmatcheslookforsomethinglikeFOOorFoOignoringcasesensitivity

YoumayhavenoticedthatallfieldsthataregoingtobeassignedshouldbeexportedandGoonlyassignsfieldsthatcanbefoundignoringallothersThiscanbeusefulifyouneedtodealwithlargechunksofJSONdatabutyouonlyaspecificsubsetofitthedatayoudontneedcaneasilybediscarded

ParsetointerfaceWhenweknowwhatkindofJSONtoexpectinadvancewecanparseittoaspecificstructButwhatifwedontknow

WeknowthataninterfacecanbeanythinginGosoitisthebestcontainertosaveourJSONofunknownformatTheJSONpackageusesmap[string]interfaceand[]interfacetosaveallkindsofJSONobjectsandarraysHereisalistofJSONmappingrelations

boolrepresentsJSONbooleansfloat64representsJSONnumbersstringrepresentsJSONstringsnilrepresentsJSONnull

SupposewehavethefollowingJSONdata

b=[]byte(`NameWednesdayAge6Parents[GomezMorticia]`)

NowweparsethisJSONtoaninterface

varfinterface

err=jsonUnmarshal(bampf)

Thefstoresamapwherekeysarestringsandvaluesareinterfaces

f=map[string]interface

NameWednesday

Age6

Parents[]interface

Gomez

Morticia

SohowdoweaccessthisdataTypeassertion

m=f(map[string]interface)

Afterassertedyoucanusethefollowingcodetoaccessdata

JSON

158

forkv=rangem

switchvv=v(type)

casestring

fmtPrintln(kisstringvv)

caseint

fmtPrintln(kisintvv)

casefloat64

fmtPrintln(kisfloat64vv)

case[]interface

fmtPrintln(kisanarray)

foriu=rangevv

fmtPrintln(iu)

default

fmtPrintln(kisofatypeIdontknowhowtohandle)

AsyoucanseewecannowparseJSONofanunknownformatthroughinterfaceandtypeassertion

TheaboveexampleistheofficialsolutionbuttypeassertingisnotalwaysconvenientSoIrecommendanopensourceprojectcalledsimplejsoncreatedandmaintainedbybitlyHereisanexampleofhowtousethisprojecttodealwithJSONofanunknownformat

jserr=NewJson([]byte(`

test

array[123]

int10

float5150

bignum9223372036854775807

stringsimplejson

booltrue

`))

arr_=jsGet(test)Get(array)Array()

i_=jsGet(test)Get(int)Int()

ms=jsGet(test)Get(string)MustString()

ItsnothardtoseehowconvenientthisisCheckouttherepositorytoseemoreinformationhttpsgithubcombitlygo-simplejson

ProducingJSONInmanysituationsweneedtoproduceJSONdataandrespondtoclientsInGotheJSONpackagehasafunctioncalledMarshaltodojustthat

funcMarshal(vinterface)([]byteerror)

SupposeweneedtoproduceaserverinformationlistWehavefollowingsample

JSON

159

packagemain

import(

encodingjson

fmt

)

typeServerstruct

ServerNamestring

ServerIPstring

typeServerslicestruct

Servers[]Server

funcmain()

varsServerslice

sServers=append(sServersServerServerNameShanghai_VPNServerIP127001)

sServers=append(sServersServerServerNameBeijing_VPNServerIP127002)

berr=jsonMarshal(s)

iferr=nil

fmtPrintln(jsonerrerr)

fmtPrintln(string(b))

Output

Servers[ServerNameShanghai_VPNServerIP127001ServerNameBeijing_VPNServerIP127002]

AsyouknowallfieldnamesarecapitalizedbutifyouwantyourJSONkeynamestostartwithalowercaseletteryoushouldusestructtagsOtherwiseGowillnotproducedataforinternalfields

typeServerstruct

ServerNamestring`jsonserverName`

ServerIPstring`jsonserverIP`

typeServerslicestruct

Servers[]Server`jsonservers`

AfterthismodificationwecanproducethesameJSONdataasbefore

HerearesomepointsyouneedtokeepinmindwhentryingtoproduceJSON

Fieldtagscontaining-willnotbeoutputtedIfatagcontainsacustomizednameGousesthisinsteadofthefieldnamelikeserverNameintheaboveexampleIfatagcontainsomitemptythisfieldwillnotbeoutputtedifitiszero-valueIfthefieldtypeisboolstringintint64etcanditstagcontainsstringGoconvertsthisfieldtoitscorrespondingJSONtype

Example

JSON

160

typeServerstruct

IDwillnotbeoutputed

IDint`json-`

ServerName2willbeconvertedtoJSONtype

ServerNamestring`jsonserverName`

ServerName2string`jsonserverName2string`

IfServerIPisemptyitwillnotbeoutputted

ServerIPstring`jsonserverIPomitempty`

s=Server

ID3

ServerName`Go10`

ServerName2`Go10`

ServerIP``

b_=jsonMarshal(s)

osStdoutWrite(b)

Output

serverNameGo10serverName2Go10

TheMarshalfunctiononlyreturnsdatawhenithassucceededsoherearesomepointsweneedtokeepinmind

JSONonlysupportsstringsaskeyssoifyouwanttoencodeamapitstypehastobemap[string]TwhereTisthetypeinGoTypeslikechannelcomplextypesandfunctionsarenotcapableofbeingencodedtoJSONDonottrytoencodecyclicdataitleadstoaninfiniterecursionIfthefieldisapointerGooutputsthedatathatitpointstoorelseoutputsnullifitpointstonil

InthissectionweintroducedhowtodecodeandencodeJSONdatainGoWealsolookedatonethird-partyprojectcalledsimplejsonwhichisusefulforparsingJSONorunknownformatTheseareallusefulconceptsfordevelopingwebapplicationsinGo

LinksDirectoryPrevioussectionXMLNextsectionRegexp

JSON

161

73RegexpRegularExpressions(Regexp)isacomplicatedbutpowerfultoolforpatternmatchingandtextmanipulationAlthoughitdoesnotperformaswellaspuretextmatchingitsmoreflexibleBasedonitssyntaxyoucanfilteralmostanykindoftextfromyoursourcecontentIfyouneedtocollectdatainwebdevelopmentitsnotdifficulttouseRegexptoretrievemeaningfuldata

GohastheregexppackagewhichprovidesofficialsupportforregexpIfyouvealreadyusedregexpinotherprogramminglanguagesyoushouldbefamiliarwithitNotethatGoimplementedRE2standardexceptforCFormoredetailsfollowthislinkhttpcodegooglecompre2wikiSyntax

Gosstringspackagecanactuallydomanyjobslikesearching(ContainsIndex)replacing(Replace)parsing(SplitJoin)etcanditsfasterthanRegexpHoweverthesearealltrivialoperationsIfyouwanttosearchacaseinsensitivestringRegexpshouldbeyourbestchoiceSoifthestringspackageissufficientforyourneedsjustuseitsinceitseasytouseandreadifyouneedtoperformmoreadvancedoperationsuseRegexp

IfyourecallformvalidationfromprevioussectionsweusedRegexptoverifythevalidityofuserinputinformationBeawarethatallcharactersareUTF-8LetslearnmoreabouttheGoregexppackage

MatchTheregexppackagehas3functionstomatchifitmatchesapatternthenitreturnstruereturningfalseotherwise

funcMatch(patternstringb[]byte)(matchedboolerrorerror)

funcMatchReader(patternstringrioRuneReader)(matchedboolerrorerror)

funcMatchString(patternstringsstring)(matchedboolerrorerror)

All3functionscheckifpatternmatchestheinputsourcereturningtrueifitmatchesHoweverifyourRegexhassyntaxerrorsitwillreturnanerrorThe3inputsourcesofthesefunctionsaresliceofbyteRuneReaderandstring

HereisanexampleofhowtoverifyanIPaddress

funcIsIP(ipstring)(bbool)

ifm_=regexpMatchString(^[0-9]13[0-9]13[0-9]13[0-9]13$ip)m

returnfalse

returntrue

AsyoucanseeusingpatternintheregexppackageisnotthatdifferentHeresonemoreexampleonverifyingwhetheruserinputisvalid

funcmain()

iflen(osArgs)==1

fmtPrintln(Usageregexp[string])

osExit(1)

elseifm_=regexpMatchString(^[0-9]+$osArgs[1])m

fmtPrintln(Number)

else

fmtPrintln(Notnumber)

IntheaboveexamplesweuseMatch(Reader|String)tocheckifcontentisvalidbuttheyarealleasytouse

Regexp

162

FilterMatchmodecanverifycontentbutitcannotcutfilterorcollectdatafromitIfyouwanttodothatyouhavetousethecomplexmodeofRegexp

LetssayweneedtowriteacrawlerHereisanexampleforwhenyoumustuseRegexptofilterandcutdata

packagemain

import(

fmt

ioioutil

nethttp

regexp

strings

)

funcmain()

resperr=httpGet(httpwwwbaiducom)

iferr=nil

fmtPrintln(httpgeterror)

deferrespBodyClose()

bodyerr=ioutilReadAll(respBody)

iferr=nil

fmtPrintln(httpreaderror)

return

src=string(body)

ConvertHTMLtagstolowercase

re_=regexpCompile(lt[Ss]+gt)

src=reReplaceAllStringFunc(srcstringsToLower)

RemoveSTYLE

re_=regexpCompile(ltstyle[Ss]+ltstylegt)

src=reReplaceAllString(src)

RemoveSCRIPT

re_=regexpCompile(ltscript[Ss]+ltscriptgt)

src=reReplaceAllString(src)

RemoveallHTMLcodeinanglebracketsandreplacewithnewline

re_=regexpCompile(lt[Ss]+gt)

src=reReplaceAllString(srcn)

Removecontinuousnewline

re_=regexpCompile(s2)

src=reReplaceAllString(srcn)

fmtPrintln(stringsTrimSpace(src))

InthisexampleweuseCompileasthefirststepforcomplexmodeItverifiesthatyourRegexsyntaxiscorrectthenreturnsaRegexpforparsingcontentinotheroperations

HerearesomefunctionstoparseyourRegexpsyntax

funcCompile(exprstring)(Regexperror)

funcCompilePOSIX(exprstring)(Regexperror)

funcMustCompile(strstring)Regexp

funcMustCompilePOSIX(strstring)Regexp

Regexp

163

ThedifferencebetweenComplePOSIXandCompileisthattheformerhastousePOSIXsyntaxwhichisleftmostlongestsearchandthelatterisonlyleftmostsearchForinstanceforRegexp[a-z]24andcontentaa09aaa88aaaaCompilePOSIXreturnsaaaabutCompilereturnsaaMustprefixmeanspanicwhentheRegexpsyntaxisnotcorrectreturningerrorotherwise

NowthatweknowhowtocreateanewRegexpletsseehowthemethodsprovidedbythisstructcanhelpustooperateoncontent

func(reRegexp)Find(b[]byte)[]byte

func(reRegexp)FindAll(b[]bytenint)[][]byte

func(reRegexp)FindAllIndex(b[]bytenint)[][]int

func(reRegexp)FindAllString(sstringnint)[]string

func(reRegexp)FindAllStringIndex(sstringnint)[][]int

func(reRegexp)FindAllStringSubmatch(sstringnint)[][]string

func(reRegexp)FindAllStringSubmatchIndex(sstringnint)[][]int

func(reRegexp)FindAllSubmatch(b[]bytenint)[][][]byte

func(reRegexp)FindAllSubmatchIndex(b[]bytenint)[][]int

func(reRegexp)FindIndex(b[]byte)(loc[]int)

func(reRegexp)FindReaderIndex(rioRuneReader)(loc[]int)

func(reRegexp)FindReaderSubmatchIndex(rioRuneReader)[]int

func(reRegexp)FindString(sstring)string

func(reRegexp)FindStringIndex(sstring)(loc[]int)

func(reRegexp)FindStringSubmatch(sstring)[]string

func(reRegexp)FindStringSubmatchIndex(sstring)[]int

func(reRegexp)FindSubmatch(b[]byte)[][]byte

func(reRegexp)FindSubmatchIndex(b[]byte)[]int

These18methodsincludeidenticalfunctionsfordifferentinputsources(byteslicestringandioRuneReader)sowecanreallysimplifythislistbyignoringinputsourcesasfollows

func(reRegexp)Find(b[]byte)[]byte

func(reRegexp)FindAll(b[]bytenint)[][]byte

func(reRegexp)FindAllIndex(b[]bytenint)[][]int

func(reRegexp)FindAllSubmatch(b[]bytenint)[][][]byte

func(reRegexp)FindAllSubmatchIndex(b[]bytenint)[][]int

func(reRegexp)FindIndex(b[]byte)(loc[]int)

func(reRegexp)FindSubmatch(b[]byte)[][]byte

func(reRegexp)FindSubmatchIndex(b[]byte)[]int

Codesample

Regexp

164

packagemain

import(

fmt

regexp

)

funcmain()

a=IamlearningGolanguage

re_=regexpCompile([a-z]24)

Findthefirstmatch

one=reFind([]byte(a))

fmtPrintln(Findstring(one))

Findallmatchesandsavetoaslicenlessthan0meansreturnallmatchesindicateslengthofsliceifit

sgreaterthan0

all=reFindAll([]byte(a)-1)

fmtPrintln(FindAllall)

Findindexoffirstmatchstartandendposition

index=reFindIndex([]byte(a))

fmtPrintln(FindIndexindex)

Findindexofallmatchesthendoessamejobasabove

allindex=reFindAllIndex([]byte(a)-1)

fmtPrintln(FindAllIndexallindex)

re2_=regexpCompile(am()lang())

Findfirstsubmatchandreturnarraythefirstelementcontainsallelementsthesecondelementcontainsthe

resultoffirst()thethirdelementcontainstheresultofsecond()

Output

thefirstelementamlearningGolanguage

thesecondelementlearningGonoticespaceswillbeoutputedaswell

thethirdelementuage

submatch=re2FindSubmatch([]byte(a))

fmtPrintln(FindSubmatchsubmatch)

for_v=rangesubmatch

fmtPrintln(string(v))

SameasFindIndex()

submatchindex=re2FindSubmatchIndex([]byte(a))

fmtPrintln(submatchindex)

FindAllSubmatchfindallsubmatches

submatchall=re2FindAllSubmatch([]byte(a)-1)

fmtPrintln(submatchall)

FindAllSubmatchIndexfindindexofallsubmatches

submatchallindex=re2FindAllSubmatchIndex([]byte(a)-1)

fmtPrintln(submatchallindex)

AswevepreviouslymentionedRegexpalsohas3methodsformatchingTheydotheexactsamethingastheexportedfunctionsInfactthoseexportedfunctionsactuallycallthesemethodsunderthehood

func(reRegexp)Match(b[]byte)bool

func(reRegexp)MatchReader(rioRuneReader)bool

func(reRegexp)MatchString(sstring)bool

NextletsseehowtoreplacestringsusingRegexp

Regexp

165

func(reRegexp)ReplaceAll(srcrepl[]byte)[]byte

func(reRegexp)ReplaceAllFunc(src[]bytereplfunc([]byte)[]byte)[]byte

func(reRegexp)ReplaceAllLiteral(srcrepl[]byte)[]byte

func(reRegexp)ReplaceAllLiteralString(srcreplstring)string

func(reRegexp)ReplaceAllString(srcreplstring)string

func(reRegexp)ReplaceAllStringFunc(srcstringreplfunc(string)string)string

Theseareusedinthecrawlingexamplesowewillnotexplainanyfurtherhere

LetstakealookatthedefinitionofExpand

func(reRegexp)Expand(dst[]bytetemplate[]bytesrc[]bytematch[]int)[]byte

func(reRegexp)ExpandString(dst[]bytetemplatestringsrcstringmatch[]int)[]byte

SohowdoweuseExpand

funcmain()

src=[]byte(`

callhelloalice

hellobob

callhelloeve

`)

pat=regexpMustCompile(`(m)(call)s+(Pltcmdgtw+)s+(Pltarggt+)s$`)

res=[]byte

for_s=rangepatFindAllSubmatchIndex(src-1)

res=patExpand(res[]byte($cmd($arg)n)srcs)

fmtPrintln(string(res))

AtthispointyouvelearntthewholeregexppackageinGoIhopethatyoucanunderstandmorebystudyingexamplesofkeymethodssothatyoucandosomethinginterestingonyourown

LinksDirectoryPrevioussectionJSONNextsectionTemplates

Regexp

166

74Templates

WhatisatemplateHopefullyyoureawareoftheMVC(ModelViewController)designmodelwheremodelsprocessdataviewsshowtheresultsandfinallycontrollershandleuserrequestsForviewsmanydynamiclanguagesgeneratedatabywritingcodeinstaticHTMLfilesForinstanceJSPisimplementedbyinsertinglt==gtPHPbyinsertingltphpgtetc

Thefollowingdemonstratesthetemplatemechanism

Figure71Templatemechanism

MostofthecontentthatwebapplicationsrespondtoclientswithisstaticandthedynamicpartsareusuallyverysmallForexampleifyouneedtodisplayalistuserswhohavevisitedapageonlytheusernamewouldbedynamicThestyleofthelistremainsthesameAsyoucanseetemplatesareusefulforreusingstaticcontent

TemplatinginGoInGowehavethetemplatepackagetohelphandletemplatesWecanusefunctionslikeParseParseFileandExecutetoloadtemplatesfromplaintextorfilesthenevaluatethedynamicpartsasshowninfigure71

Example

funchandler(whttpResponseWriterrhttpRequest)

t=templateNew(sometemplate)Createatemplate

t_=tParseFiles(tmplwelcomehtmlnil)Parsetemplatefile

user=GetUser()Getcurrentuserinfomration

tExecute(wuser)merge

AsyoucanseeitsveryeasytouseloadandrenderdataintemplatesinGojustasinotherprogramminglanguages

Forthesakeofconveniencewewillusethefollowingrulesinourexamples

UseParsetoreplaceParseFilesbecauseParsecantestcontentdirectlyfromstringssowedontneedanyextrafilesUsemainforeveryexampleanddonotusehandlerUseosStdouttoreplacehttpResponseWritersinceosStdoutalsoimplementstheioWriterinterface

InsertingdataintoatemplateWevejustshownyouhowtoparseandrendertemplatesLetstakeitonestepfurtherandrenderdatatoourtemplatesEverytemplateisanobjectinGosohowdoweinsertfieldstotemplates

Fields

InGoEveryfieldthatyouintendtoberenderedwithinatemplateshouldbeputinsideofisshorthandforthecurrentobjectwhichissimilartoitsJavaorC++counterpartIfyouwanttoaccessthefieldsofthecurrentobjectyoushoulduseFieldNameNoticethatonlyexportedfieldscanbeaccessedintemplatesHereisanexample

Templates

167

packagemain

import(

htmltemplate

os

)

typePersonstruct

UserNamestring

funcmain()

t=templateNew(fieldnameexample)

t_=tParse(helloUserName)

p=PersonUserNameAstaxie

tExecute(osStdoutp)

TheaboveexampleoutputshelloAstaxiecorrectlybutifwemodifyourstructalittlebitthefollowingerroremerges

typePersonstruct

UserNamestring

emailstringFieldisnotexported

t_=tParse(helloUserNameemail)

ThispartofthecodewillnotbecompiledbecausewetrytoaccessafieldthathasnotbeenexportedHoweverifwetrytouseafieldthatdoesnotexistGosimplyoutputsanemptystringinsteadofanerror

IfyouprintinatemplateGooutputsaformattedstringofthisobjectcallingfmtunderthecovers

Nestedfields

WeknowhowtooutputafieldnowWhatifthefieldisanobjectanditalsohasitsownfieldsHowdoweprintthemallinoneloopWecanusewithhelliphellipendandrangehellipendforexactlythatpurpose

rangejustlikerangeinGowithletsyouwritethesameobjectnameonceanduseasshorthandforit(SimilartowithinVB)

Moreexamples

Templates

168

packagemain

import(

htmltemplate

os

)

typeFriendstruct

Fnamestring

typePersonstruct

UserNamestring

Emails[]string

Friends[]Friend

funcmain()

f1=FriendFnameminuxma

f2=FriendFnamexushiwei

t=templateNew(fieldnameexample)

t_=tParse(`helloUserName

rangeEmails

anemail

end

withFriends

range

myfriendnameisFname

end

end

`)

p=PersonUserNameAstaxie

Emails[]stringastaxiebeegomeastaxiegmailcom

Friends[]Friendampf1ampf2

tExecute(osStdoutp)

ConditionsIfyouneedtocheckforconditionsintemplatesyoucanusetheif-elsesyntaxjustlikeyoudoinregularGoprogramsIfthepipelineisemptythedefaultvalueofifisfalseThefollowingexampleshowshowtouseif-elseintemplates

packagemain

import(

os

texttemplate

)

funcmain()

tEmpty=templateNew(templatetest)

tEmpty=templateMust(tEmptyParse(Emptypipelineifdemoif``willnotbeoutputtedendn))

tEmptyExecute(osStdoutnil)

tWithValue=templateNew(templatetest)

tWithValue=templateMust(tWithValueParse(Notemptypipelineifdemoif`anything`willbeoutputtede

ndn))

tWithValueExecute(osStdoutnil)

tIfElse=templateNew(templatetest)

tIfElse=templateMust(tIfElseParse(if-elsedemoif`anything`ifpartelseelsepartendn))

tIfElseExecute(osStdoutnil)

Asyoucanseeitseasytouseif-elseintemplates

Templates

169

AttentionYouCANNOTuseconditionalexpressionsinifforinstanceMail==astaxiegmailcomOnlybooleanvaluesareacceptable

pipelines

Unixusersshouldbefamiliarwiththepipeoperatorlikels|grepbeegoThiscommandfiltersfilesandonlyshowsthosethatcontainthewordbeegoOnethingthatIlikeaboutGotemplatesisthattheysupportpipesAnythingincanbethedataofpipelinesThee-mailweusedabovecanrenderourapplicationvulnerabletoXSSattacksHowcanweaddressthisissueusingpipes

|html

Wecanusethismethodtoescapethee-mailbodytoHTMLItsquitesimilartowritingaUnixcommandanditisconvenientforuseintemplatefunctions

TemplatevariablesSometimesweneedtouselocalvariablesintemplatesWecanusethemwiththewithrangeandifkeywordsandtheirscopeisbetweenthesekeywordsandendHeresanexampleofdeclaringaglobalvariable

$variable=pipeline

Moreexamples

with$x=output|printfq$xend

with$x=outputprintfq$xend

with$x=output$x|printfqend

Templatefunctions

GousesthefmtpackagetoformatoutputintemplatesbutsometimesweneedtodosomethingelseForexampleconsiderthefollowingscenarioletssaywewanttoreplacewithatinoure-mailaddresslikeastaxieatbeegomeAtthispointwehavetowriteacustomizedfunction

EverytemplatefunctionhasauniquenameandisassociatedwithonefunctioninyourGoprogramasfollows

typeFuncMapmap[string]interface

SupposewehaveanemailDealtemplatefunctionassociatedwithitsEmailDealWithcounterpartfunctioninourGoprogramWecanusethefollowingcodetoregisterthisfunction

t=tFuncs(templateFuncMapemailDealEmailDealWith)

EmailDealWithdefinition

funcEmailDealWith(argshellipinterface)string

Example

Templates

170

packagemain

import(

fmt

htmltemplate

os

strings

)

typeFriendstruct

Fnamestring

typePersonstruct

UserNamestring

Emails[]string

Friends[]Friend

funcEmailDealWith(argsinterface)string

ok=false

varsstring

iflen(args)==1

sok=args[0](string)

ifok

s=fmtSprint(args)

findthesymbol

substrs=stringsSplit(s)

iflen(substrs)=2

returns

replacethebyat

return(substrs[0]+at+substrs[1])

funcmain()

f1=FriendFnameminuxma

f2=FriendFnamexushiwei

t=templateNew(fieldnameexample)

t=tFuncs(templateFuncMapemailDealEmailDealWith)

t_=tParse(`helloUserName

rangeEmails

anemails|emailDeal

end

withFriends

range

myfriendnameisFname

end

end

`)

p=PersonUserNameAstaxie

Emails[]stringastaxiebeegomeastaxiegmailcom

Friends[]Friendampf1ampf2

tExecute(osStdoutp)

Hereisalistofbuilt-intemplatefunctions

Templates

171

varbuiltins=FuncMap

andand

callcall

htmlHTMLEscaper

indexindex

jsJSEscaper

lenlength

notnot

oror

printfmtSprint

printffmtSprintf

printlnfmtSprintln

urlqueryURLQueryEscaper

MustThetemplatepackagehasafunctioncalledMustwhichisforvalidatingtemplateslikethematchingofbracescommentsandvariablesLetstakealookatanexampleofMust

packagemain

import(

fmt

texttemplate

)

funcmain()

tOk=templateNew(first)

templateMust(tOkParse(somestatictextandacomment))

fmtPrintln(ThefirstoneparsedOK)

templateMust(templateNew(second)Parse(somestatictextName))

fmtPrintln(ThesecondoneparsedOK)

fmtPrintln(Thenextoneoughttofail)

tErr=templateNew(checkparseerrorwithMust)

templateMust(tErrParse(somestatictextName))

Output

ThefirstoneparsedOK

ThesecondoneparsedOK

Thenextoneoughttofail

panictemplatecheckparseerrorwithMust1unexpectedincommand

NestedtemplatesJustlikeinmostwebapplicationscertainpartsoftemplatescanbereusedacrossothertemplatesliketheheadersandfootersofablogWecandeclareheadercontentandfooterassub-templatesanddeclaretheminGousingthefollowingsyntax

definesub-templatecontentend

Thesub-templateiscalledusingthefollowingsyntax

templatesub-template

Templates

172

Heresacompleteexamplesupposingthatwehavethefollowingthreefilesheadertmplcontenttmplandfootertmplinthefoldertemplateswewillreadthefolderandstorethefilenamesinastringarraywhichwewillthenusetoparsefiles

Maintemplate

raw

headertmpl

defineheader

lthtmlgt

ltheadgt

lttitlegtSomethingherelttitlegt

ltheadgt

ltbodygt

end

contenttmpl

definecontent

templateheader

lth1gtNestedherelth1gt

ltulgt

ltligtNestedusagltligt

ltligtCalltemplateltligt

ltulgt

templatefooter

end

footertmpl

definefooter

ltbodygt

lthtmlgt

end

Whenusingsubtemplatingmakesurethatyouhaveparsedeachsubtemplatefile

otherwisethecompilerwouldntunderstandwhattosubstitutewhenitreadsthetemplateheader

endraw

Code

Templates

173

packagemain

import(

fmt

os

ioioutil

texttemplate

)

vartemplatestemplateTemplate

funcmain()

varallFiles[]string

fileserr=ioutilReadDir(templates)

iferr=nil

fmtPrintln(err)

for_file=rangefiles

filename=fileName()

ifstringsHasSuffix(filenametmpl)

allFiles=append(allFilestemplates+filename)

templateserr=templateParseFiles(allFiles)parsesalltmplfilesinthetemplatesfolder

s1=templatesLookup(headertmpl)

s1ExecuteTemplate(osStdoutheadernil)

fmtPrintln()

s2=templatesLookup(contenttmpl)

s2ExecuteTemplate(osStdoutcontentnil)

fmtPrintln()

s3=templatesLookup(footertmpl)

s3ExecuteTemplate(osStdoutfooternil)

fmtPrintln()

s3Execute(osStdoutnil)

HerewecanseethattemplateParseFilesparsesallnestedtemplatesintocacheandthateverytemplatedefinedbydefineareindependentofeachotherTheyarepersistedinsomethinglikeamapwherethetemplatenamesarekeysandthevaluesarethetemplatebodiesWecanthenuseExecuteTemplatetoexecutethecorrespondingsub-templatessothattheheaderandfooterareindependentandcontentcontainsthembothNotethatifwetrytoexecutes1Executenothingwillbeoutputtedbecausethereisnodefaultsub-templateavailable

Whenyoudontwanttousedefinethenyoucanjustcreateatextfilewiththenameofthesubtemplateforinstance_headtmplisasubtemplatewhichyoulluseacrossyourprojectthencreatethisfileinthetemplatesfolderandusethenormalsyntaxLookupcacheisbasicallycreatedsothatyoudontreadthefileeverytimeyouservearequestbecauseifyoudothenyouarewastingalotofresourcesforreadingafilewhichwontchangeunlessthecodebaseisbeingrewrittenitdoesntmakesensetoparsethetemplatefilesduringeachHTTPGETrequestsothetechniqueisusedwhereweparsethefilesonceandthendoaLookup()onthecachetoexecutethetemplatewhenweneedittodisplaydata

Templatesinonesetknoweachotherbutyoumustparsethemforeverysingleset

Sometimesyouwanttocontextualizetemplatesforinstanceyouhavea_headhtmlyoumighthaveaheaderwhosvalueyouhavetopopulatebasedonwhichdatayouareloadingforinstanceforatodolistmanageryoucanhavethreecategoriespendingcompleteddeletedforthissupposeyouhaveanifstatementlikethis

lttitlegtifeqNavigationpendingTasks

elseifeqNavigationcompletedCompleted

elseifeqNavigationdeletedDeleted

elseifeqNavigationeditEdit

end

lttitlegt

Templates

174

NoteGotemplatesfollowthePolishnotationwhileperformingthecomparisonwhereyougivetheoperatorfirstandthecomparisonvalueandthevaluetobecomparedwithTheelseifpartisprettystraightforward

Typicallyweusearangeoperatortoloopthroughthecontextvariablewhichwepasstothetemplatewhileexecutionlikethis

presentinviewspackage

context=dbGetTasks(pending)truewhenyouwantnondeletednotes

homeTemplateExecute(wcontext)

Wegetthecontextobjectfromthedatabaseasastructobjectthedefinitionisasbelow

Taskisthestructusedtoidentifytasks

typeTaskstruct

Idint

Titlestring

Contentstring

Createdstring

Contextisthestructpassedtotemplates

typeContextstruct

Tasks[]Task

Navigationstring

Searchstring

Messagestring

presentindatabasepackage

vartask[]typesTask

varcontexttypesContext

context=typesContextTaskstaskNavigationstatus

Thislineisinthedatabasepackagewherethecontextisreturnedbacktotheview

WeusethetaskarrayandtheNavigationinourtemplateswesawhowweusetheNavigationinthetemplatewellseehowwellusetheactualtaskarrayinourtemplate

HereintheifTaskswefirstcheckiftheTasksfieldofourcontextobjectwhichwepassedtothetemplatewhileexecutingisemptyornotIfitisnotemptythenwewillrangethroughthatarraytopopulatethetitleandcontentofTaskThebelowexampleisveryimportantwhenitcomestoloopingthroughanarrayinatemplatewestartwiththeRangeoperatorthenwecangiveanymemberofthatstructasNamemyTaskstructurehasaTitleandaContent(pleasenotethecapitalTandCtheyareexportednamesandtheyneedtobecapitalisedunlessyouwanttomakethemprivate)

rangeTasks

Title

Content

end

ThisblockofcodewillprinteachtitleandcontentoftheTaskarrayBelowisafullexamplefromgithubcomthewhitetulipTaskshomehtmltemplate

Templates

175

ltdivclass=timelinegt

ifTasksrangeTasks

ltdivclass=notegt

ltpclass=noteHeadinggtTitleltpgt

lthrgt

ltpclass=noteContentgtContentltpgt

ltulgt

ltspangt

ltdivgt

endelse

ltdivclass=notegt

ltpclass=noteHeadinggtNoTaskshereltpgt

ltpclass=notefootergt

Createnewtaskltbuttonclass=floating-action-icon-addgthereltbuttongtltpgt

ltdivgt

end

SummaryInthissectionyoulearnedhowtocombinedynamicdatawithtemplatesusingtechniquesincludingprintingdatainloopstemplatefunctionsandnestedtemplatesBylearningabouttemplateswecanconcludediscussingtheV(View)partoftheMVCarchitectureInthefollowingchapterswewillcovertheM(Model)andC(Controller)aspectsofMVC

LinksDirectoryPrevioussectionRegexpNextsectionFiles

Templates

176

75FilesFilesareessentialobjectsoneverysinglecomputerdeviceItwontcomeasanysurprisetoyouthatwebapplicationsalsomakeheavyuseofthemInthissectionweregoingtolearnhowtooperateonfilesinGo

DirectoriesInGomostofthefileoperationfunctionsarelocatedintheospackageHerearesomedirectoryfunctions

funcMkdir(namestringpermFileMode)error

Createadirectorywithnamepermisthedirectorypermissionsie0777

funcMkdirAll(pathstringpermFileMode)error

Createmultipledirectoriesaccordingtopathlikeastaxietest1test2

funcRemove(namestring)error

RemovesdirectorywithnameReturnserrorifitsnotadirectoryornotempty

funcRemoveAll(pathstring)error

RemovesmultipledirectoriesaccordingtopathDirectorieswillnotbedeletedifpathisasinglepath

Codesample

packagemain

import(

fmt

os

)

funcmain()

osMkdir(astaxie0777)

osMkdirAll(astaxietest1test20777)

err=osRemove(astaxie)

iferr=nil

fmtPrintln(err)

osRemoveAll(astaxie)

Files

Createandopenfiles

Therearetwofunctionsforcreatingfiles

funcCreate(namestring)(fileFileerrError)

Createafilewithnameandreturnaread-writablefileobjectwithpermission0666

funcNewFile(fduintptrnamestring)File

Createafileandreturnafileobject

Therearealsotwofunctionstoopenfiles

funcOpen(namestring)(fileFileerrError)

Files

177

Opensafilecallednamewithread-onlyaccesscallingOpenFileunderthecovers

funcOpenFile(namestringflagintpermuint32)(fileFileerrError)

Opensafilecallednameflagisopenmodelikeread-onlyread-writeetcpermarethefilepermissions

WritefilesFunctionsforwritingfiles

func(fileFile)Write(b[]byte)(ninterrError)

Writebytetypecontenttoafile

func(fileFile)WriteAt(b[]byteoffint64)(ninterrError)

Writebytetypecontenttoaspecificpositionofafile

func(fileFile)WriteString(sstring)(retinterrError)

Writeastringtoafile

Codesample

packagemain

import(

fmt

os

)

funcmain()

userFile=astaxietxt

fouterr=osCreate(userFile)

iferr=nil

fmtPrintln(userFileerr)

return

deferfoutClose()

fori=0ilt10i++

foutWriteString(Justatestrn)

foutWrite([]byte(Justatestrn))

ReadfilesFunctionsforreadingfiles

func(fileFile)Read(b[]byte)(ninterrError)

Readdatatob

func(fileFile)ReadAt(b[]byteoffint64)(ninterrError)

Readdatafrompositionofftob

Codesample

Files

178

packagemain

import(

fmt

os

)

funcmain()

userFile=asatxietxt

flerr=osOpen(userFile)

iferr=nil

fmtPrintln(userFileerr)

return

deferflClose()

buf=make([]byte1024)

for

n_=flRead(buf)

if0==n

break

osStdoutWrite(buf[n])

DeletefilesGousesthesamefunctionforremovingfilesanddirectories

funcRemove(namestring)Error

Removeafileordirectorycalledname(anameendingwithsignifiesthatitsadirectory)

LinksDirectoryPrevioussectionTemplatesNextsectionStrings

Files

179

76StringsOnthewebalmosteverythingwesee(includinguserinputsdatabaseaccessetc)isrepresentedbystringsTheyareaveryimportantpartofwebdevelopmentInmanycaseswealsoneedtosplitjoinconvertandotherwisemanipulatestringsInthissectionwearegoingtointroducethestringsandstrconvpackagesfromtheGostandardlibrary

stringsThefollowingfunctionsarefromthestringspackageSeetheofficialdocumentationformoredetails

funcContains(ssubstrstring)bool

Checkifstringscontainsstringsubstrreturnsabooleanvalue```GofmtPrintln(stringsContains(seafoodfoo))fmtPrintln(stringsContains(seafoodbar))fmtPrintln(stringsContains(seafood))fmtPrintln(stringsContains())

Outputtruefalsetruetrue

-funcJoin(a[]stringsepstring)string

Combinestringsfromslicewithseparator`sep`

```Go

s=[]stringfoobarbaz

fmtPrintln(stringsJoin(s))

Outputfoobarbaz

funcIndex(ssepstring)int

Findindexofsepinstringsreturns-1ifitsnotfound

fmtPrintln(stringsIndex(chickenken))

fmtPrintln(stringsIndex(chickendmr))

Output4

-1

funcRepeat(sstringcountint)string

Repeatstringscounttimes

fmtPrintln(ba+stringsRepeat(na2))

Outputbanana

funcReplace(soldnewstringnint)string

ReplacestringoldwithstringnewinstringsnisthenumberofreplacementsIfnislessthan0replaceallinstances

fmtPrintln(stringsReplace(oinkoinkoinkkky2))

fmtPrintln(stringsReplace(oinkoinkoinkoinkmoo-1))

Outputoinkyoinkyoink

moomoomoo

funcSplit(ssepstring)[]string

Splitstringswithseparatorsepintoaslice

Strings

180

fmtPrintf(qnstringsSplit(abc))

fmtPrintf(qnstringsSplit(amanaplanacanalpanamaa))

fmtPrintf(qnstringsSplit(xyz))

fmtPrintf(qnstringsSplit(BernardoOHiggins))

Output[abc]

[manplancanalpanama]

[xyz]

[]

funcTrim(sstringcutsetstring)string

Removecutsetofstringsifitsleftmostorrightmost

fmtPrintf([q]stringsTrim(Achtung))

Output[Achtung]

funcFields(sstring)[]string

Removespaceitemsandsplitstringwithspaceintoaslice

fmtPrintf(FieldsareqstringsFields(foobarbaz))

OutputFieldsare[foobarbaz]

strconvThefollowingfunctionsarefromthestrconvpackageAsusualpleaseseeofficialdocumentationformoredetails

Appendseriesconvertdatatostringandappendtocurrentbyteslice```Gopackagemain

import(fmtstrconv)

funcmain()str=make([]byte0100)str=strconvAppendInt(str456710)str=strconvAppendBool(strfalse)str=strconvAppendQuote(strabcdefg)str=strconvAppendQuoteRune(str单)fmtPrintln(string(str))

-Formatseriesconvertotherdatatypesintostring

```Go

packagemain

import(

fmt

strconv

)

funcmain()

a=strconvFormatBool(false)

b=strconvFormatFloat(12323g1264)

c=strconvFormatInt(123410)

d=strconvFormatUint(1234510)

e=strconvItoa(1023)

fmtPrintln(abcde)

Parseseriesconvertstringstoothertypes```Gopackagemain

import(fmtstrconv)

funcmain()aerr=strconvParseBool(false)iferr=nilfmtPrintln(err)berr=strconvParseFloat(1232364)iferr=nilfmtPrintln(err)cerr=strconvParseInt(12341064)iferr=nilfmtPrintln(err)derr=strconvParseUint(123451064)iferr=nilfmtPrintln(err)eerr=strconvItoa(1023)iferr=nilfmtPrintln(err)fmtPrintln(abcde)```

Strings

181

LinksDirectoryPrevioussectionFilesNextsectionSummary

Strings

182

77SummaryInthischapterweintroducedsometextprocessingtoolslikeXMLJSONRegexpandwealsotalkedabouttemplatesXMLandJSONaredataexchangetoolsYoucanrepresentalmostanykindofinformationusingthesetwoformatsRegexpisapowerfultoolforsearchingreplacingandcuttingtextcontentWithtemplatesyoucaneasilycombinedynamicdatawithstaticfilesThesetoolsareallusefulwhendevelopingwebapplicationsIhopethatyounowhaveabetterunderstandingofprocessinganddisplayingcontentusingGo

LinksDirectoryPrevioussectionStringsNextchapterWebservices

Summary

183

8WebservicesWebservicesallowyouuseformatslikeXMLorJSONtoexchangeinformationthroughHTTPForexampleifyouwanttoknowtheweatherinShanghaitomorrowthecurrentsharepriceofAppleorproductinformationonAmazonyoucanwriteapieceofcodetofetchthatinformationfromopenplatformsInGothisprocesscanbecomparabletocallingalocalfunctionandgettingitsreturnvalue

ThekeypointisthatwebservicesareplatformindependentThisallowsyoutodeployyourapplicationsonLinuxandinteractwithASPNETapplicationsinWindowsforexamplejustlikeyouwouldnthaveaprobleminteractingwithJSPonFreeBSDeither

TheRESTarchitectureandSOAPprotocolarethemostpopularstylesinwhichwebservicescanbeimplementedthesedays

RESTrequestsareprettystraightforwardbecauseitsbasedonHTTPEveryRESTrequestisactuallyanHTTPrequestandservershandlerequestsusingdifferentmethodsBecausemanydevelopersarefamiliarwithHTTPalreadyRESTshouldfeellikeitsalreadyintheirbackpocketsWearegoingtoshowyouhowtoimplementRESTinGoinsection83SOAPisastandardforcross-networkinformationtransmissionandremotecomputerfunctioncallslaunchedbyW3CTheproblemwithSOAPisthatitsspecificationisverylongandcomplicatedanditsstillgettinglongerGobelievesthatthingsshouldbesimplesowerenotgoingtotalkaboutSOAPFortunatelyGoprovidessupportforRPC(RemoteProcedureCalls)whichhasgoodperformanceandiseasytodevelopwithsowewillintroducehowtoimplementRPCinGoinsection84

GoistheClanguageofthe21stcenturyaspiringtobesimpleyetperformantWiththesequalitiesinmindwellintroduceyoutosocketprogramminginGoinsection81Nowadaysmanyreal-timeserversusesocketstoovercomethelowperformanceofHTTPAlongwiththerapiddevelopmentofHTML5websocketsarenowusedbymanywebbasedgamecompaniesandwewilltalkaboutthismoreinsection82

LinksDirectoryPreviousChapterChapter7SummaryNextsectionSockets

Webservices

184

81SocketsSomenetworkapplicationdeveloperssaythatthelowerapplicationlayersareallaboutsocketprogrammingThismaynotbetrueforallcasesbutmanymodernwebapplicationsdoindeedusesocketstotheiradvantageHaveyoueverwonderedhowbrowserscommunicatewithwebserverswhenyouaresurfingtheinternetOrHowMSNconnectsyouandyourfriendstogetherinachatroomrelayingeachmessageinreal-timeManyservicesliketheseusesocketstotransferdataAsyoucanseesocketsoccupyanimportantpositioninnetworkprogrammingtodayandweregoingtolearnaboutusingsocketsinGointhissection

WhatisasocketSocketsoriginatefromUnixandgiventhebasiceverythingisafilephilosophyofUnixeverythingcanbeoperatedonwithopen-gtwriteread-gtcloseSocketsareoneimplementationofthisphilosophySocketshaveafunctioncallforopeningasocketjustlikeyouwouldopenafileThisreturnsanintdescriptorofthesocketwhichcanthenbeusedforoperationslikecreatingconnectionstransferringdataetc

Twotypesofsocketsthatarecommonlyusedarestreamsockets(SOCK_STREAM)anddatagramsockets(SOCK_DGRAM)Streamsocketsareconnection-orientedlikeTCPwhiledatagramsocketsdonotestablishconnectionslikeUDP

SocketcommunicationBeforeweunderstandhowsocketscommunicatewithoneanotherweneedtofigureouthowtomakesurethateverysocketisuniqueotherwiseestablishingareliablecommunicationchannelisalreadyoutofthequestionWecangiveeveryprocessauniquePIDwhichservesourpurposelocallyhoweverthatsnotabletoworkoveranetworkFortunatelyTCPIPhelpsussolvethisproblemTheIPaddressesofthenetworklayerareuniqueinanetworkofhostsandprotocol+portisalsouniqueamonghostapplicationsSowecanusetheseprinciplestomakesocketswhichareunique

Figure81networkprotocollayers

ApplicationsthatarebasedonTCPIPallusesocketAPIsintheircodeinonewayoranotherGiventhatnetworkedapplicationsarebecomingmoreandmoreprevalentinthemoderndayitsnowondersomedevelopersaresayingthateverythingisaboutsockets

SocketbasicknowledgeWeknowthatsocketshavetwotypeswhichareTCPsocketsandUDPsocketsTCPandUDPareprotocolsandasmentionedwealsoneedanIPaddressandportnumbertohaveauniquesocket

IPv4TheglobalinternetusesTCPIPasitsprotocolwhereIPisthenetworklayerandacorepartofTCPIPIPv4signifiesthatitsversionis4infrastructuredevelopmenttodatehasspannedover30years

ThenumberofbitsinanIPv4addressis32whichmeansthat2^32devicesareabletouniquelyconnecttotheinternetDuetotherapiddevelopoftheinternetIPaddressesarealreadyrunningoutofstockinrecentyears

Addressformat127001172122121111

IPv6

Sockets

185

IPv6isthenextversionornextgenerationoftheinternetItsbeingdevelopedforsolvingmanyoftheproblemsinherentwithIPv4DevicesusingIPv6haveanaddressthats128bitslongsowellneverneedtoworryaboutashortageofuniqueaddressesToputthisintoperspectiveyoucouldhavemorethan1000IPaddressesforeverysquaremeteronearthwithIPv6Otherproblemslikepeertopeerconnectionservicequality(QoS)securitymultiplebroadcastetcarealsobeimproved

Addressformat2002c0e882e7000c0e882e7

IPtypesinGo

ThenetpackageinGoprovidesmanytypesfunctionsandmethodsfornetworkprogrammingThedefinitionofIPasfollows

typeIP[]byte

FunctionParseIP(sstring)IPistoconverttheIPv4orIPv6formattoanIP

packagemain

import(

net

os

fmt

)

funcmain()

iflen(osArgs)=2

fmtFprintf(osStderrUsagesip-addrnosArgs[0])

osExit(1)

name=osArgs[1]

addr=netParseIP(name)

ifaddr==nil

fmtPrintln(Invalidaddress)

else

fmtPrintln(TheaddressisaddrString())

osExit(0)

ItreturnsthecorrespondingIPformatforagivenIPaddress

TCPsocketWhatcanwedowhenweknowhowtovisitawebservicethroughanetworkportAsaclientwecansendarequesttoanappointednetworkportandgetsitsresponseasaserverweneedtobindaservicetoanappointednetworkportwaitforclientsrequestsandsupplyaresponse

InGosnetpackagetheresatypecalledTCPConnthatfacilitatesthiskindofclientsserversinteractionThistypehastwokeyfunctions

func(cTCPConn)Write(b[]byte)(ninterrosError)

func(cTCPConn)Read(b[]byte)(ninterrosError)

TCPConncanbeusedbyeitherclientorserverforreadingandwritingdata

WealsoneedaTCPAddrtorepresentTCPaddressinformation

Sockets

186

typeTCPAddrstruct

IPIP

Portint

WeusetheResolveTCPAddrfunctiontogetaTCPAddrinGo

funcResolveTCPAddr(netaddrstring)(TCPAddrosError)

Argumentsofnetcanbeoneoftcp4tcp6ortcpwhicheachsignifyIPv4-onlyIPv6-onlyandeitherIPv4orIPv6respectivelyaddrcanbeadomainnameorIPaddresslikewwwgooglecom80or12700122

TCPclientGoclientsusetheDialTCPfunctioninthenetpackagetocreateaTCPconnectionwhichreturnsaTCPConnobjectafteraconnectionisestablishedtheserverhasthesametypeofconnectionobjectforthecurrentconnectionandclientandservercanbeginexchangingdatawithoneanotherIngeneralclientssendrequeststoserversthroughaTCPConnandreceiveinformationfromtheserverresponseserversreadandparseclientrequeststhenreturnfeedbackThisconnectionwillremainvaliduntileithertheclientorserverclosesitThefunctionforcreatingaconnectionisasfollows

funcDialTCP(netstringladdrraddrTCPAddr)(cTCPConnerrosError)

Argumentsofnetcanbeoneoftcp4tcp6ortcpwhicheachsignifyIPv4-onlyIPv6-onlyandeitherIPv4orIPv6respectivelyladdrrepresentsthelocaladdresssetittonilinmostcasesraddrrepresentstheremoteaddress

LetswriteasimpleexampletosimulateaclientrequestingaconnectiontoaserverbasedonanHTTPrequestWeneedasimpleHTTPrequestheader

HEADHTTP10rnrn

Serverresponseinformationformatmaylooklikethefollowing

HTTP10200OK

ETag-9985996

Last-ModifiedThu25Mar2010175110GMT

Content-Length18074

Connectionclose

DateSat28Aug2010004348GMT

Serverlighttpd1423

Clientcode

Sockets

187

packagemain

import(

fmt

ioioutil

net

os

)

funcmain()

iflen(osArgs)=2

fmtFprintf(osStderrUsageshostportosArgs[0])

osExit(1)

service=osArgs[1]

tcpAddrerr=netResolveTCPAddr(tcp4service)

checkError(err)

connerr=netDialTCP(tcpniltcpAddr)

checkError(err)

_err=connWrite([]byte(HEADHTTP10rnrn))

checkError(err)

resulterr=ioutilReadAll(conn)

checkError(err)

fmtPrintln(string(result))

osExit(0)

funccheckError(errerror)

iferr=nil

fmtFprintf(osStderrFatalerrorserrError())

osExit(1)

IntheaboveexampleweuseuserinputastheserviceargumentofnetResolveTCPAddrtogetatcpAddrPassingtcpAddrtotheDialTCPfunctionwecreateaTCPconnectionconnWecanthenuseconntosendrequestinformationtotheserverFinallyweuseioutilReadAlltoreadallthecontentfromconnwhichcontainstheserverresponse

TCPserver

WehaveaTCPclientnowWecanalsousethenetpackagetowriteaTCPserverOntheserversideweneedtobindourservicetoaspecificinactiveportandlistenforanyincomingclientrequests

funcListenTCP(netstringladdrTCPAddr)(lTCPListenererrosError)

func(lTCPListener)Accept()(cConnerrosError)

TheargumentsrequiredhereareidenticaltothoserequiredbytheDialTCPfunctionweusedearlierLetsimplementatimesyncingserviceusingport7777

Sockets

188

packagemain

import(

fmt

net

os

time

)

funcmain()

service=7777

tcpAddrerr=netResolveTCPAddr(tcp4service)

checkError(err)

listenererr=netListenTCP(tcptcpAddr)

checkError(err)

for

connerr=listenerAccept()

iferr=nil

continue

daytime=timeNow()String()

connWrite([]byte(daytime))dontcareaboutreturnvalue

connClose()werefinishedwiththisclient

funccheckError(errerror)

iferr=nil

fmtFprintf(osStderrFatalerrorserrError())

osExit(1)

AftertheserviceisstarteditwaitsforclientrequestsWhenitreceivesaclientrequestitAcceptsitandreturnsaresponsetotheclientcontaininginformationaboutthecurrenttimeItsworthnotingthatwhenerrorsoccurintheforlooptheservicecontinuesrunninginsteadofexitingInsteadofcrashingtheserverwillrecordtheerrortoaservererrorlog

TheabovecodeisstillnotgoodenoughhoweverWedidntmakeuseofgoroutineswhichwouldhaveallowedustoacceptsimultaneousrequestsLetsdothisnow

Sockets

189

packagemain

import(

fmt

net

os

time

)

funcmain()

service=1200

tcpAddrerr=netResolveTCPAddr(tcp4service)

checkError(err)

listenererr=netListenTCP(tcptcpAddr)

checkError(err)

for

connerr=listenerAccept()

iferr=nil

continue

gohandleClient(conn)

funchandleClient(connnetConn)

deferconnClose()

daytime=timeNow()String()

connWrite([]byte(daytime))dontcareaboutreturnvalue

werefinishedwiththisclient

funccheckError(errerror)

iferr=nil

fmtFprintf(osStderrFatalerrorserrError())

osExit(1)

ByseparatingoutourbusinessprocessfromthehandleClientfunctionandbyusingthegokeywordwevealreadyimplementedconcurrencyinourserviceThisisagooddemonstrationofthepowerandsimplicityofgoroutines

SomeofyoumaybethinkingthefollowingthisserverdoesnotdoanythingmeaningfulWhatifweneededtosendmultiplerequestsfordifferenttimeformatsoverasingleconnectionHowwouldwedothat

Sockets

190

packagemain

import(

fmt

net

os

time

strconv

)

funcmain()

service=1200

tcpAddrerr=netResolveTCPAddr(tcp4service)

checkError(err)

listenererr=netListenTCP(tcptcpAddr)

checkError(err)

for

connerr=listenerAccept()

iferr=nil

continue

gohandleClient(conn)

funchandleClient(connnetConn)

connSetReadDeadline(timeNow()Add(2timeMinute))set2minutestimeout

request=make([]byte128)setmaximumrequestlengthto128Btopreventfloodbasedattacks

deferconnClose()closeconnectionbeforeexit

for

read_lenerr=connRead(request)

iferr=nil

fmtPrintln(err)

break

ifread_len==0

breakconnectionalreadyclosedbyclient

elseifstring(request[read_len])==timestamp

daytime=strconvFormatInt(timeNow()Unix()10)

connWrite([]byte(daytime))

else

daytime=timeNow()String()

connWrite([]byte(daytime))

funccheckError(errerror)

iferr=nil

fmtFprintf(osStderrFatalerrorserrError())

osExit(1)

InthisexampleweuseconnRead()toconstantlyreadclientrequestsWecannotclosetheconnectionbecauseclientsmayissuemorethanonerequestDuetothetimeoutwesetusingconnSetReadDeadline()theconnectionclosesautomaticallyafterourallottedtimeperiodWhentheexpirytimehaselapsedourprogrambreaksfromtheforloopNoticethatrequestneedstobecreatedwithamaxsizelimitationinordertopreventfloodattacks

ControllingTCPconnections

ControllingTCPfunctions

funcDialTimeout(netaddrstringtimeouttimeDuration)(Connerror)

Sockets

191

SettingthetimeoutofconnectionsThesearesuitableforuseonbothclientsandservers

func(cTCPConn)SetReadDeadline(ttimeTime)error

func(cTCPConn)SetWriteDeadline(ttimeTime)error

Settingthewritereadtimeoutofoneconnection

func(cTCPConn)SetKeepAlive(keepalivebool)osError

ItsworthtakingsometimetothinkabouthowlongyouwantyourconnectiontimeoutstobeLongconnectionscanreducetheamountofoverheadinvolvedincreatingconnectionsandaregoodforapplicationsthatneedtoexchangedatafrequently

FormoredetailedinformationjustlookuptheofficialdocumentationforGosnetpackage

UDPsocketsTheonlydifferencebetweenaUDPsocketandaTCPsocketistheprocessingmethodfordealingwithmultiplerequestsonserversideThisarisesfromthefactthatUDPdoesnothaveafunctionlikeAcceptAlloftheotherfunctionshaveUDPcounterpartsjustreplaceTCPwithUDPinthefunctionsmentionedabove

funcResolveUDPAddr(netaddrstring)(UDPAddrosError)

funcDialUDP(netstringladdrraddrUDPAddr)(cUDPConnerrosError)

funcListenUDP(netstringladdrUDPAddr)(cUDPConnerrosError)

func(cUDPConn)ReadFromUDP(b[]byte)(nintaddrUDPAddrerrosError

func(cUDPConn)WriteToUDP(b[]byteaddrUDPAddr)(ninterrosError)

UDPclientcodesample

packagemain

import(

fmt

net

os

)

funcmain()

iflen(osArgs)=2

fmtFprintf(osStderrUsageshostportosArgs[0])

osExit(1)

service=osArgs[1]

udpAddrerr=netResolveUDPAddr(udp4service)

checkError(err)

connerr=netDialUDP(udpniludpAddr)

checkError(err)

_err=connWrite([]byte(anything))

checkError(err)

varbuf[512]byte

nerr=connRead(buf[0])

checkError(err)

fmtPrintln(string(buf[0n]))

osExit(0)

funccheckError(errerror)

iferr=nil

fmtFprintf(osStderrFatalerrorerrError())

osExit(1)

Sockets

192

UDPservercodesample

packagemain

import(

fmt

net

os

time

)

funcmain()

service=1200

udpAddrerr=netResolveUDPAddr(udp4service)

checkError(err)

connerr=netListenUDP(udpudpAddr)

checkError(err)

for

handleClient(conn)

funchandleClient(connnetUDPConn)

varbuf[512]byte

_addrerr=connReadFromUDP(buf[0])

iferr=nil

return

daytime=timeNow()String()

connWriteToUDP([]byte(daytime)addr)

funccheckError(errerror)

iferr=nil

fmtFprintf(osStderrFatalerrorerrError())

osExit(1)

SummaryThroughdescribingandcodingsomesimpleprogramsusingTCPandUDPsocketswecanseethatGoprovidesexcellentsupportforsocketprogrammingandthattheyarefunandeasytouseGoalsoprovidesmanyfunctionsforbuildinghighperformancesocketapplications

LinksDirectoryPrevioussectionWebservicesNextsectionWebSocket

Sockets

193

82WebSocketsWebSocketsareanimportantfeatureofHTML5Itimplementsbrowserbasedremotesocketswhichallowsbrowserstohavefull-duplexcommunicationswithserversMainstreambrowserslikeFirefoxGoogleChromeandSafariprovidesupportforthisWebSockets

PeopleoftenusedrollpollingforinstantmessagingservicesbeforeWebSocketswerebornwhichallowclientstosendHTTPrequestsperiodicallyTheserverthenreturnsthelatestdatatoclientsThedownsidetothismethodisthatitrequiresclientstokeepsendingmanyrequeststotheserverwhichcanconsumealargeamountofbandwidth

WebSocketsuseaspecialkindofheaderthatreducesthenumberofhandshakesrequiredbetweenbrowserandservertoonlyoneforestablishingaconnectionThisconnectionwillremainactivethroughoutitslifetimeandyoucanuseJavaScripttowriteorreaddatafromthisconnectionasinthecaseofaconventionalTCPsocketsItsolvesmanyoftheheadacheinvolvedwithreal-timewebdevelopmentandhasthefollowingadvantagesovertraditionalHTTP

OnlyoneTCPconnectionforasinglewebclientWebSocketserverscanpushdatatowebclientsLightweightheadertoreducedatatransmissionoverhead

WebSocketURLsbeginwithwsorwss(SSL)ThefollowingfigureshowsthecommunicationprocessofWebSocketsAparticularHTTPheaderissenttotheserveraspartofthehandshakingprotocolandtheconnectionisestablishedThenserversorclientsareabletosendorreceivedatathroughJavaScriptviaWebSocketThissocketcanthenbeusedbyaneventhandlertoreceivedataasynchronously

Figure82WebSocketprinciple

WebSocketprinciplesTheWebSocketprotocolisactuallyquitesimpleAftersuccessfullycompletingtheinitialhandshakeaconnectionisestablishedSubsequentdatacommunicationswillallbeginwithx00andendwithxFFThisprefixandsuffixwillbevisibletoclientsbecausetheWebSocketwillbreakoffbothendyieldingtherawdataautomatically

WebSocketconnectionsarerequestedbybrowsersandrespondedtobyserversafterwhichtheconnectionisestablishedThisprocessisoftencalledhandshaking

Considerthefollowingrequestsandresponses

Figure83WebSocketrequestandresponse

Sec-WebSocket-keyisgeneratedrandomlyasyoumayhavealreadyguessedanditsbase64encodedServersneedtoappendthiskeytoafixedstringafteracceptingarequest

258EAFA5-E914-47DA-95CA-C5AB0DC85B11

Supposewehavef7cb4ezEAl6C3wRaU6JORA==thenwehave

f7cb4ezEAl6C3wRaU6JORA==258EAFA5-E914-47DA-95CA-C5AB0DC85B11

Usesha1tocomputethebinaryvalueandusebase64toencodeitWewillthenwehave

rE91AJhfC+6JdVcVXOGJEADEJdQ=

WebSocket

194

UsethisasthevalueoftheSec-WebSocket-Acceptresponseheader

WebSocketinGoTheGostandardlibrarydoesnotsupportWebSocketsHoweverthewebsocketpackagewhichisasub-packageofgonetdoesandisofficiallymaintainedandsupported

Usegogettoinstallthispackage

gogetgolangorgxnetwebsocket

WebSocketshavebothclientandserversidesLetsseeasimpleexamplewhereauserinputssomeinformationontheclientsideandsendsittotheserverthroughaWebSocketfollowedbytheserverpushinginformationbacktotheclient

Clientcode

lthtmlgt

ltheadgtltheadgt

ltbodygt

ltscripttype=textjavascriptgt

varsock=null

varwsuri=ws1270011234

windowonload=function()

consolelog(onload)

sock=newWebSocket(wsuri)

sockonopen=function()

consolelog(connectedto+wsuri)

sockonclose=function(e)

consolelog(connectionclosed(+ecode+))

sockonmessage=function(e)

consolelog(messagereceived+edata)

functionsend()

varmsg=documentgetElementById(message)value

socksend(msg)

ltscriptgt

lth1gtWebSocketEchoTestlth1gt

ltformgt

ltpgt

Messageltinputid=messagetype=textvalue=Helloworldgt

ltpgt

ltformgt

ltbuttononclick=send()gtSendMessageltbuttongt

ltbodygt

lthtmlgt

AsyoucanseeitsveryeasytousetheclientsideJavaScriptfunctionstoestablishaconnectionTheonopeneventgetstriggeredaftersuccessfullycompletingtheaforementionedhandshakingprocessIttellstheclientthattheconnectionhasbeencreatedsuccessfullyClientsattemptingtoopenaconnectiontypicallybindtofourevents

1)onopentriggeredafterconnectionhasbeenestablished2)onmessagetriggeredafterreceivingamessage3)onerrortriggeredafteranerrorhasoccurred

WebSocket

195

4)onclosetriggeredaftertheconnectionhasclosed

Servercode

packagemain

import(

golangorgxnetwebsocket

fmt

log

nethttp

)

funcEcho(wswebsocketConn)

varerrerror

for

varreplystring

iferr=websocketMessageReceive(wsampreply)err=nil

fmtPrintln(Cantreceive)

break

fmtPrintln(Receivedbackfromclient+reply)

msg=Received+reply

fmtPrintln(Sendingtoclient+msg)

iferr=websocketMessageSend(wsmsg)err=nil

fmtPrintln(Cantsend)

break

funcmain()

httpHandle(websocketHandler(Echo))

iferr=httpListenAndServe(1234nil)err=nil

logFatal(ListenAndServeerr)

WhenaclientSendsuserinputinformationtheserverReceivesitandusesSendonceagaintoreturnaresponse

Figure84WebSocketserverreceivedinformation

ThroughtheexampleabovewecanseethattheclientandserversideimplementationofWebSocketsisveryconvenientWecanusethenetpackagedirectlyinGoWiththerapiddevelopmentofHTML5IthinkthatWebSocketswilltakeonamuchmoreimportantroleinmoderndaywebdevelopmentweshouldallbeatleastalittlebitfamiliarwiththem

LinksDirectoryPrevioussectionSocketsNextsectionREST

WebSocket

196

83RESTRESTisthemostpopularsoftwarearchitectureontheinternettodaybecauseitisfoundedonwelldefinedstrictstandardsanditseasytounderstandandexpandMoreandmorewebsitesarebasingtheirdesignsontopofRESTInthissectionwearegoingtohaveacloselookatimplementingtheRESTarchitectureinGoand(hopefully)learnhowtoleverageittoourbenefit

WhatisRESTThefirstdeclarationoftheconceptofREST(REpresentationalStateTransfer)wasintheyear2000inRoyThomasFieldingsdoctoraldissertationwhoalsojusthappenstobetheco-founderoftheHTTPprotocolItspecifiesthearchitecturesconstraintsandprinciplesandanythingimplementedwiththisarchitecturecanbecalledaRESTfulsystem

BeforeweunderstandwhatRESTisweneedtocoverthefollowingconcepts

Resources

RESTisthePresentationLayerStateTransferwherethepresentationlayerisactuallytheresourcepresentatio

nlayer

SowhatareresourcesPicturesdocumentsorvideosetcareallexamplesofresourcesandcanbelocatedby

URI

Representation

ResourcesarespecificinformationentitiesthatcanbeshowninavarietyofwayswithinthepresentationlayerForinstanceaTXTdocumentcanberepresentedasHTMLJSONXMLetcanimagecanberepresentedasjpgpngetc

URIsareusedtoidentifyresourcesbuthowdowedetermineitsspecificmanifestationsYouarereferredtotheAcceptandContent-TypeinanHTTPrequestheaderthesetwofieldsdescribethepresentationlayer

StateTransfer

AninteractiveprocessisinitiatedbetweenclientandservereachtimeyouvisitanypageofawebsiteDuringthisprocesscertaindatarelatedtothecurrentpagestateneedtobesavedHoweveryoullrecallthatHTTPisastatelessprotocolItsobviousthatweneedtosavethisclientstateonourserversideItfollowsthatifaclientmodifiessomedataandwantstopersistthechangestheremustbeawaytoinformtheserversideaboutthenewstate

MostofthetimeclientsinformserversofstatechangesusingHTTPTheyhavefouroperationswithwhichtodothis

-GETisusedtoobtainresources-POSTsisusedtocreateorupdateresources-PUTupdatesresources-DELETEdeletesresources

Tosummarizetheabove

(1)EveryURIrepresentsaresource(2)Thereisarepresentationlayerfortransferringresourcesbetweenclientsandservers(3)ClientsusefourHTTPmethodstoimplementPresentationLayerStateTransferallowingthemtooperateonremoteresources

ThemostimportantprincipleofwebapplicationsthatimplementRESTisthattheinteractionbetweenclientsandserversarestatelesseveryrequestshouldencapsulatealloftherequiredinformationServersshouldbeabletorestartatanytimewithouttheclientsbeingnotifiedInadditionrequestscanberespondedbyanyserverofthesameservicewhichisidealforcloudcomputingLastlybecauseitsstatelessclientscancachedataforimprovingperformance

REST

197

AnotherimportantprincipleofRESTissystemdelaminationwhichmeansthatcomponentsinonelayerhavenowayofinteractingdirectlywithcomponentsinotherlayersThiscanlimitsystemcomplexityandencourageindependenceintheunderlyingcomponents

Figure85RESTarchitecture

WhenRESTfulconstraintsarejudiciouslyabidedbywebapplicationscanbescaledtoaccommodatemassivenumbersofclientsUsingtheRESTarchitecturecanalsohelpreducedelaysbetweenclientsandserverssimplifysystemarchitectureandimprovethevisibilityofsub-systemendpoints

Figure86RESTsexpansibility

RESTfulimplementationGodoesnthavedirectsupportforRESTbutsinceRESTfulwebapplicationsareallHTTP-basedwecanusethenethttppackagetoimplementitonourownOfcoursewewillfirstneedtomakesomemodificationsbeforeweareabletofullyimplementREST

RESTusesdifferentmethodstohandleresourcesdependingontheinteractionthatsrequiredwiththatresourceManyexistingapplicationsclaimtobeRESTfulbuttheydonotactuallyimplementRESTImgoingtocategorizetheseapplicationsintoseverallevelsdependsonwhichHTTPmethodstheyimplement

Figure87RESTslevel

ThepictureaboveshowsthreelevelsthatarecurrentlyimplementedinRESTYoumaynotchoosetofollowalltherulesandconstraintsofRESTwhendevelopingyourownapplicationsbecausesometimesitsrulesarenotagoodfitforallsituationsRESTfulwebapplicationsuseeverysingleHTTPmethodincludingDELETEandPUTbutinmanycasesHTTPclientscanonlysendGETandPOSTrequests

HTMLstandardallowsclientssendGETandPOSTrequeststhroughlinksandformsItsnotpossibletosendPUTorDELETErequestswithoutAJAXsupportSomefirewallsinterceptPUTandDELETErequestsandclientshavetousePOSTinordertoimplementthemFullyRESTfulservicesareinchargeoffindingtheoriginalHTTPmethodsandrestoringthem

WecansimulatePUTandDELETErequestsbyaddingahidden_methodfieldinourPOSTrequestshowevertheserequestsmustbeconvertedontheserversidebeforetheyareprocessedMypersonalapplicationsusethisworkflowtoimplementRESTinterfacesStandardRESTfulinterfacesareeasilyimplementedinGoasthefollowingexampledemonstrates

REST

198

packagemain

import(

fmt

githubcomjulienschmidthttprouter

log

nethttp

)

funcIndex(whttpResponseWriterrhttpRequest_httprouterParams)

fmtFprint(wWelcomen)

funcHello(whttpResponseWriterrhttpRequestpshttprouterParams)

fmtFprintf(whellosnpsByName(name))

funcgetuser(whttpResponseWriterrhttpRequestpshttprouterParams)

uid=psByName(uid)

fmtFprintf(wyouaregetusersuid)

funcmodifyuser(whttpResponseWriterrhttpRequestpshttprouterParams)

uid=psByName(uid)

fmtFprintf(wyouaremodifyusersuid)

funcdeleteuser(whttpResponseWriterrhttpRequestpshttprouterParams)

uid=psByName(uid)

fmtFprintf(wyouaredeleteusersuid)

funcadduser(whttpResponseWriterrhttpRequestpshttprouterParams)

uid=rFormValue(uid)

uid=psByName(uid)

fmtFprintf(wyouareaddusersuid)

funcmain()

router=httprouterNew()

routerGET(Index)

routerGET(hellonameHello)

routerGET(useruidgetuser)

routerPOST(adduseruidadduser)

routerDELETE(deluseruiddeleteuser)

routerPUT(moduseruidmodifyuser)

logFatal(httpListenAndServe(8080router))

ThissamplecodeshowsyouhowtowriteaverybasicRESTapplicationOurresourcesareusersandweusedifferentfunctionsfordifferentmethodsHereweimportedathird-partypackagecalledgithubcomjulienschmidthttprouterWevealreadycoveredhowtoimplementacustomrouterinpreviouschapters-thejulienschmidthttprouterpackageimplementssomeveryconvenientroutermappingrulesthatmakeitveryconvenientforimplementingRESTfularchitectureAsyoucanseeRESTrequiresyoutoimplementdifferentlogicfordifferentHTTPmethodsofthesameresource

SummaryRESTisastyleofwebarchitecturebuildingonpastsuccessfulexperienceswithWWWstatelessnessresource-centricfulluseofHTTPandURIprotocolsandtheprovisionofunifiedinterfacesThesesuperiordesignconsiderationshaveallowedRESTtobecomethemostpopularwebservicesstandardInasensebyemphasizingtheURIandleveraging

REST

199

earlyInternetstandardssuchasHTTPRESThaspavedthewayforlargeandscalablewebapplicationsCurrentlythesupportthatGohasForRESTisstillverybasicHoweverbyimplementingcustomroutingrulesanddifferentrequesthandlersforeachtypeofHTTPrequestwecanachieveRESTfularchitectureinourGowebapps

LinksDirectoryPrevioussectionWebSocketNextsectionRPC

REST

200

84RPCInprevioussectionswetalkedabouthowtowritenetworkapplicationsbasedonSocketsandHTTPWelearnedthatbothofthemusetheinformationexchangemodelinwhichclientssendrequestsandserversrespondtothemThiskindofdataexchangeisbasedonaspecificformatsothatbothsidesareabletocommunicatewithoneanotherHowevermanyindependentapplicationsdonotusethismodelbutinsteadcallservicesjustliketheywouldcallnormalfunctions

RPCwasintendedtobethefunctioncallmodefornetworkedsystemsClientsexecuteRPCsliketheycallnativefunctionsexcepttheypackagethefunctionparametersandsendthemthroughthenetworktotheserverTheservercanthenunpacktheseparametersandprocesstherequestexecutingtheresultsbacktotheclient

Incomputersciencearemoteprocedurecall(RPC)isatypeofinter-processcommunicationthatallowsacomputerprogramtocauseasubroutineorproceduretoexecuteinanotheraddressspace(commonlyonanothercomputeronasharednetwork)withouttheprogrammerexplicitlycodingthedetailsforthisremoteinteractionThatistheprogrammerwritesessentiallythesamecodewhetherthesubroutineislocaltotheexecutingprogramorremoteWhenthesoftwareinquestionusesobject-orientedprinciplesRPCiscalledremoteinvocationorremotemethodinvocation

RPCworkingprinciple

Figure88RPCworkingprinciple

NormallyanRPCcallfromclienttoserverhasthefollowingtensteps

1 Calltheclienthandleexecutetransferarguments

1 Calllocalsystemkerneltosendnetworkmessages

1 Sendmessagestoremotehosts

1 Theserverreceiveshandleandarguments

1 Executeremoteprocesses

1 Returnexecutionresulttocorrespondinghandle

1 Theserverhandlecallsremotesystemkernel

1 Messagessentbacktolocalsystemkernel

1 Theclienthandlereceivesmessagesfromsystemkernel

1 Theclientgetsresultsfromcorrespondinghandle

GoRPCGohasofficialsupportforRPCinitsstandardlibraryonthreelevelswhichareTCPHTTPandJSONRPCNotethatGoRPCisnotlikeothertraditionalRPCsystemsItrequiresyoutouseGoapplicationsonbothclientandserversidesbecauseitencodescontentusingGob

RPC

201

FunctionsofGoRPCmustabidebythefollowingrulesforremoteaccessotherwisethecorrespondingcallswillbeignored

Functionsareexported(capitalized)FunctionsmusthavetwoargumentswithexportedtypesThefirstargumentisforreceivingfromtheclientandthesecondonehastobeapointerandisforreplyingtotheclientFunctionsmusthaveareturnvalueoferrortype

Forexample

func(tT)MethodName(argTypeT1replyTypeT2)error

WhereTT1andT2mustbeabletobeencodedbythepackagegobpackage

AnykindofRPChastogothroughanetworktotransferdataGoRPCcaneitheruseHTTPorTCPThebenefitsofusingHTTPisthatyoucanreusesomefunctionsfromthenethttppackage

HTTPRPCHTTPserversidecode

RPC

202

packagemain

import(

errors

fmt

nethttp

netrpc

)

typeArgsstruct

ABint

typeQuotientstruct

QuoRemint

typeArithint

func(tArith)Multiply(argsArgsreplyint)error

reply=argsAargsB

returnnil

func(tArith)Divide(argsArgsquoQuotient)error

ifargsB==0

returnerrorsNew(dividebyzero)

quoQuo=argsAargsB

quoRem=argsAargsB

returnnil

funcmain()

arith=new(Arith)

rpcRegister(arith)

rpcHandleHTTP()

err=httpListenAndServe(1234nil)

iferr=nil

fmtPrintln(errError())

WeregisteredaRPCserviceofAriththenregisteredthisserviceonHTTPthroughrpcHandleHTTPAfterthatweareabletotransferdatathroughHTTP

Clientsidecode

RPC

203

packagemain

import(

fmt

log

netrpc

os

)

typeArgsstruct

ABint

typeQuotientstruct

QuoRemint

funcmain()

iflen(osArgs)=2

fmtPrintln(UsageosArgs[0]server)

osExit(1)

serverAddress=osArgs[1]

clienterr=rpcDialHTTP(tcpserverAddress+1234)

iferr=nil

logFatal(dialingerr)

Synchronouscall

args=Args178

varreplyint

err=clientCall(ArithMultiplyargsampreply)

iferr=nil

logFatal(aritherrorerr)

fmtPrintf(Arithdd=dnargsAargsBreply)

varquotQuotient

err=clientCall(ArithDivideargsampquot)

iferr=nil

logFatal(aritherrorerr)

fmtPrintf(Arithdd=dremainderdnargsAargsBquotQuoquotRem)

WecompiletheclientandtheserversidecodeseparatelythenstarttheserverandclientYoullthenhavesomethingsimilarasfollowsafteryouinputsomedata

$http_clocalhost

Arith178=136

Arith178=2remainder1

AsyoucanseewedefinedastructforthereturntypeWeuseitastypeoffunctionargumentontheserversideandasthetypeofthesecondandthirdargumentsontheclientclientCallThiscallisveryimportantIthasthreeargumentswherethefirstoneisthenameofthefunctionthatisgoingtobecalledthesecondistheargumentyouwanttopassandthelastoneisthereturnvalue(ofpointertype)SofarweseethatitseasytoimplementRPCinGo

TCPRPCLetstrytheRPCthatisbasedonTCPhereistheserversidecode

RPC

204

packagemain

import(

errors

fmt

net

netrpc

os

)

typeArgsstruct

ABint

typeQuotientstruct

QuoRemint

typeArithint

func(tArith)Multiply(argsArgsreplyint)error

reply=argsAargsB

returnnil

func(tArith)Divide(argsArgsquoQuotient)error

ifargsB==0

returnerrorsNew(dividebyzero)

quoQuo=argsAargsB

quoRem=argsAargsB

returnnil

funcmain()

arith=new(Arith)

rpcRegister(arith)

tcpAddrerr=netResolveTCPAddr(tcp1234)

checkError(err)

listenererr=netListenTCP(tcptcpAddr)

checkError(err)

for

connerr=listenerAccept()

iferr=nil

continue

rpcServeConn(conn)

funccheckError(errerror)

iferr=nil

fmtPrintln(FatalerrorerrError())

osExit(1)

ThedifferencebetweenHTTPRPCandTCPRPCisthatwehavetocontrolconnectionsbyourselvesifweuseTCPRPCthenpassconnectionstoRPCforprocessing

AsyoumayhaveguessedthisisablockingpatternYouarefreetousegoroutinestoextendthisapplicationasamoreadvancedexperiment

Theclientsidecode

RPC

205

packagemain

import(

fmt

log

netrpc

os

)

typeArgsstruct

ABint

typeQuotientstruct

QuoRemint

funcmain()

iflen(osArgs)=2

fmtPrintln(UsageosArgs[0]serverport)

osExit(1)

service=osArgs[1]

clienterr=rpcDial(tcpservice)

iferr=nil

logFatal(dialingerr)

Synchronouscall

args=Args178

varreplyint

err=clientCall(ArithMultiplyargsampreply)

iferr=nil

logFatal(aritherrorerr)

fmtPrintf(Arithdd=dnargsAargsBreply)

varquotQuotient

err=clientCall(ArithDivideargsampquot)

iferr=nil

logFatal(aritherrorerr)

fmtPrintf(Arithdd=dremainderdnargsAargsBquotQuoquotRem)

TheonlydifferenceintheclientsidecodeisthatHTTPclientsuseDialHTTPwhereasTCPclientsuseDial(TCP)

JSONRPC

JSONRPCencodesdatatoJSONinsteadofgobLetsseeanexampleofaGoJSONRPContheserver

RPC

206

packagemain

import(

errors

fmt

net

netrpc

netrpcjsonrpc

os

)

typeArgsstruct

ABint

typeQuotientstruct

QuoRemint

typeArithint

func(tArith)Multiply(argsArgsreplyint)error

reply=argsAargsB

returnnil

func(tArith)Divide(argsArgsquoQuotient)error

ifargsB==0

returnerrorsNew(dividebyzero)

quoQuo=argsAargsB

quoRem=argsAargsB

returnnil

funcmain()

arith=new(Arith)

rpcRegister(arith)

tcpAddrerr=netResolveTCPAddr(tcp1234)

checkError(err)

listenererr=netListenTCP(tcptcpAddr)

checkError(err)

for

connerr=listenerAccept()

iferr=nil

continue

jsonrpcServeConn(conn)

funccheckError(errerror)

iferr=nil

fmtPrintln(FatalerrorerrError())

osExit(1)

JSONRPCisbasedonTCPanddoesntsupportHTTPyet

Theclientsidecode

RPC

207

packagemain

import(

fmt

log

netrpcjsonrpc

os

)

typeArgsstruct

ABint

typeQuotientstruct

QuoRemint

funcmain()

iflen(osArgs)=2

fmtPrintln(UsageosArgs[0]serverport)

logFatal(1)

service=osArgs[1]

clienterr=jsonrpcDial(tcpservice)

iferr=nil

logFatal(dialingerr)

Synchronouscall

args=Args178

varreplyint

err=clientCall(ArithMultiplyargsampreply)

iferr=nil

logFatal(aritherrorerr)

fmtPrintf(Arithdd=dnargsAargsBreply)

varquotQuotient

err=clientCall(ArithDivideargsampquot)

iferr=nil

logFatal(aritherrorerr)

fmtPrintf(Arithdd=dremainderdnargsAargsBquotQuoquotRem)

SummaryGohasgoodsupportforHTTPTPCandJSONRPCimplementationwhichallowustoeasilydevelopdistributedwebapplicationshoweveritisregrettablethatGodoesnthavebuilt-insupportforSOAPRPCalthoughsomeopensourcethird-partypackagesdoofferthis

LinksDirectoryPrevioussectionRESTNextsectionSummary

RPC

208

85SummaryInthischapterIintroducedyoutoseveralmainstreamwebapplicationdevelopmentmodelsInsection81IdescribedthebasicsofnetworkprogrammingsocketsBecauseoftherapidevolutionofnetworktechnologyandinfrastructureandgiventhattheSocketisthecornerstoneofthesechangesyoumustmastertheconceptsbehindsocketprogramminginordertobeacompetentwebdeveloperInsection82IdescribedHTML5WebSocketswhichsupportfull-duplexcommunicationsbetweenclientandserverandeliminatetheneedforpollingwithAJAXInsection83weimplementedasimpleapplicationusingtheRESTarchitecturewhichisparticularlysuitableforthedevelopmentofnetworkAPIsduetotherapidriseofmobileapplicationsIbelievethatRESTfulAPIswillbeanongoingtrendInsection84welearnedaboutGoRPCs

GoprovidesexcellentsupportforthefourkindsofdevelopmentmethodsmentionedaboveNotethatthenetpackageanditssub-packagesistheplacewhereGosnetworkprogrammingtoolsGoresideIfyouwantamorein-depthunderstandingoftherelevantimplementationdetailsyoushouldtryreadingthesourcecodeofthosepackages

LinksDirectoryPrevioussectionRPCNextchapterSecurityandencryption

Summary

209

9SecurityandencryptionSecurityisanextremelyimportantaspectofmostwebapplicationsThistopichasbeengettingmoreandmoreattentionlatelyespeciallyinlightoftherecentCSDNLinkedinandYahoopasswordleaksAsGodeveloperswemustbeawareofvulnerabilitiesinourapplicationsandtakeprecautionsinordertopreventattackersfromtakingoveroursystems

Manyofthesecurityproblemsthatariseinmodernwebapplicationsoriginatefromdataprovidedbythird-partiesForexampleuserinputshouldalwaysbevalidatedandsanitizedbeforebeingstoredassecuredataIfthisisntdonewhenthedataisoutputtedtoaclientitmaycauseacross-sitescriptingattack(XSS)SimilarlyifunsafedataisuseddirectlyasyourapplicationsdatabasequeriesthenyoumaybevulnerabletoSQLinjectionattacksInsections93and94welllookathowtoavoidtheseproblems

Whenusingthird-partydata(whichincludesuser-supplieddata)firstverifytheintegrityofthedatabyfilteringtheinputSection92willdescribehowtofilterinput

UnfortunatelyfilteringinputandescapingoutputdoesnotsolveallsecurityproblemsInsection91wewillexplaincross-siterequestforgery(CSRF)attacksThisisamaliciousexploitwhereunauthorizedcommandsaretransmittedfromauserthatthewebsitetrusts

KeepingconfidentialdataencryptedcanalsohelpyoutosecureyourwebapplicationsInsection95wewilldescribehowtostorepasswordssafelyusingGosencryptionpackage

AgoodhashfunctionmakesithardtofindtwostringsthatwouldproducethesamehashvalueandthisisonewaywithwhichwecanencryptourdataThereisalsotwo-wayencryptionwhereyouuseasecretkeytodecryptencrypteddataInsection96wewilldescribehowtoperformbothone-wayandtwo-wayencryption

LinksDirectoryPreviousChapterChapter8SummaryNextsectionCSRFattacks

Securityandencryption

210

91CSRFattacks

WhatisCSRFCSRFandXSRFbothstandforCross-siterequestforgeryItsalsoknownasaoneclickattackorsessionriding

SohowdoesaCSRFattackworkACSRFattackhappenswhenanattackertricksatrusteduserintoaccessingawebsiteorclickingaURLthattransmitsmaliciousrequests(withouttheuserrsquosconsent)toatargetedwebsiteHeresasimpleexampleusingafewsocialengineeringtricksanattackercouldusetheQQchatsoftwaretofindandsendmaliciouslinkstovictimstargetedattheirusersonlinebankingwebsiteIfthevictimlogsintotheironlinebankaccountanddoesnotexitthenclickingonamaliciouslinksentfromtheattackercouldallowtheattackertostealalloftheusersbankaccountfunds

WhenunderaCSRFattackasingleend-userwithanadministratoraccountcanthreatentheintegrityoftheentirewebapplication

CSRFprincipleThefollowingdiagramprovidesasimpleoverviewofaCSRFattack

Figure91CSRFattackprocess

AscanbeseenfromthefiguretocompleteaCSRFattackthevictimmustcompletethefollowingtwosteps

-1LogintotrustedsiteAandstorealocalCookie-2WithoutgoingthroughexistingsiteAaccessthedangerouslinktositeB

AsareaderyoumaybeaskingIfIdonotmeettheabovetwoconditionsIwillnotbesubjectedtoCSRFattacksYesthisistruehoweveryoucannotguaranteethatthefollowingdoesnotoccur

YoucannotguaranteethatwhenyouareloggedintoasitethesitedidntlaunchanyhiddentabsYoucannotguaranteethatwhenyoucloseyourbrowseryourcookieswillimmediatelyexpireandyourlastsessionwillhaveendedTrustedhightrafficwebsiteswilllikelynothavehiddenvulnerabilitieseasilyexploitablebyCSRFbasedattacks

ThusitcanbedifficultforuserstovisitawebsitethroughalinkandknowthatitwillnotcarryoutunknownoperationsintheformofaCSRFattack

CSRFattacksworkmostlybecauseoftheprocessthroughwhichusersareauthenticatedAlthoughyoucanreasonablyguaranteethatarequestoriginatesfromausersbrowserthereisnoguaranteethattheusergrantedapprovalfortherequest

HowtopreventCSRFattacksYoumightbealittlescaredafterreadingthesectionaboveButfearisagoodthingItwillforceyoutoeducateyourselfonhowtopreventvulnerabilitieslikethisfromhappeningtoyou

PreventativemeasuresagainstCSRFattackscanbetakenonboththeserverandclientsidesofawebapplicationHoweverCSRFattacksaremosteffectivelythwartedontheserverside

TherearemanywaysofpreventingCSRFattacksontheserversideMostapproachesstemfromthefollowingtwoaspects

1 MaintainingproperuseofGETPOSTandcookies

CSRFattacks

211

2 Includingapseudo-randomnumberwithnon-GETrequests

InthepreviouschapteronRESTwesawhowmostwebapplicationsarebasedonGETandPOSTHTTPrequestsandthatcookieswereincludedalongwiththeserequestsWegenerallydesignapplicationsaccordingtothefollowingprinciples

1 GETiscommonlyusedtoviewinformationwithoutalteringanydata

2 POSTisusedinplacingorderschangingthepropertiesofaresourceorperformingothertasks

ImnowgoingtousetheGolanguagetoillustratehowtorestrictaccesstoresourcesmethods

muxGet(useruidgetuser)

muxPost(useruidmodifyuser)

SincewevestipulatedthatmodificationscanonlyusePOSTwhenaGETmethodisissuedinsteadofaPOSTwecanrefusetorespondtotherequestAccordingtothefigureaboveattacksutilizingGETasaCSRFexploitcanbepreventedIsthisenoughtopreventallpossibleCSRFattacksOfcoursenotbecausePOSTscanalsobeforged

Weneedtoimplementasecondstepwhichis(inthecaseofnon-GETrequests)toincreasethelengthofthepseudo-randomnumberincludedwiththerequestThisusuallyinvolvessteps

Foreachusergenerateauniquecookietokenwithapseudo-randomvalueAllformsmustcontainthesamepseudo-randomvalueThisproposalisthesimplestonebecauseintheoryanattackercannotreadthirdpartycookiesAnyformthatanattackermaysubmitwillfailthevalidationprocesswithoutknowingwhattherandomvalueisDifferentformscontaindifferentpseudo-randomvaluesasweveintroducedinsection44HowtopreventmultipleformsubmissionWecanreusetherelevantcodefromthatsectiontomeetourneeds

Generatingarandomnumbertoken

h=md5New()

ioWriteString(hstrconvFormatInt(crutime10))

ioWriteString(hganraomaxxxxxxxxx)

token=fmtSprintf(xhSum(nil))

t_=templateParseFiles(logingtpl)

tExecute(wtoken)

Outputtoken

ltinputtype=hiddenname=tokenvalue=gt

Authenticationtoken

rParseForm()

token=rFormGet(token)

iftoken=

Verificationtokenoflegitimacy

Else

Errortokendoesnotexist

WecanusetheprecedingcodetosecureourPOSTsYoumightbewonderinginaccordancewithourtheorywhethertherecouldbesomewayforamaliciousthirdpartytosomehowfigureoutoursecrettokenvalueInfactcrackingitisbasicallyimpossible-successfullycalculatingthecorrectstringvalueusingbruteforcemethodsneedsabout2tothe11thtime

Summary

CSRFattacks

212

Cross-siterequestforgeryalsoknownasCSRFisaverydangerouswebsecuritythreatItisknowninwebsecuritycirclesasasleepinggiantsecurityissueasyoucantellCSRFattackshavequitethereputationThissectionnotonlyintroducedcross-siterequestforgeryitselfbutfactorsunderlyingthisvulnerabilityItconcludeswithsomesuggestionsandmethodsforpreventingsuchattacksIhopethissectionwillhaveinspiredyouasareadertowritebetterandmoresecurewebapplications

LinksDirectoryPrevioussectionSecurityandencryptionNextsectionFilterinputs

CSRFattacks

213

92FilteringinputsFilteringuserdataisonewaywecanimprovethesecurityofourwebappsusingittoverifythelegitimacyofincomingdataAlloftheinputdataisfilteredinordertoavoidmaliciouscodeordatafrombeingmistakenlyexecutedorstoredMostwebapplicationvulnerabilitiesariseformneglectingtofilterinputdataandnaivelytrustingit

Ourintroductiontofilteringdataisdividedintothreesteps

1 identifyingthedataweneedtofilterthedatatofigureoutwhereitoriginatedfrom2 filteringofthedataitselfweneedtofigureoutwhatkindofdatawehavereceived3 distinguishbetweenfiltered(sanitized)andtainteddataafterthedatahasbeenfilteredwecanbeassuredthatitis

secure

IdentifyingdataIdentifyingthedataisourfirststepbecausemostofthetimeasmentionedwedontknowwhereitoriginatesfromWithoutthisknowledgewewouldbeunabletoproperlyfilteritThedatahereisprovidedinternallyallfromnon-codedataForexamplealldatacomesfromclientshoweverclientsthatareusersarenottheonlyexternalsourcesofdataAdatabaseinterfaceprovidingthirdpartydatacouldalsobeanexternaldatasource

DatathathasbeenenteredbyauserisveryeasytorecognizeinGoWeuserParseFormaftertheuserPOSTsaformtogetallofthedatainsidetherFormOthertypesofinputaremuchhardertoidentifyForexampleinrHeadersmanyoftheelementsareoftenmanipulatedbytheclientItcanoftenbedifficulttoidentifywhichoftheseelementshavebeenmanipulatedbyclientssoitsbesttoconsiderallofthemashavingbeentaintedTherHeaderGet(Accept-Charset)headerfieldforinstanceisalsoconsideredasuserinputalthoughthesearetypicallyonlymanipulatedbybrowsers

FilteringdataIfweknowthesourceofthedatawecanfilteritFilteringisabitofaformaluseofthetermTheprocessisknownbymanyothertermssuchasinputcleaningvalidationandsanitizationDespitethefactthatthesetermsdiffersomewhatintheirmeaningtheyallrefertothesamethingtheprocessofpreventingillegaldatafrommakingitswayintoyourapplications

TherearemanywaystofilterdatasomeofwhicharelesssecurethanothersThebestmethodistocheckwhetherornotthedataitselfmeetsthelegalrequirementsdictatedbyyourapplicationWhenattemptingtodosoitsveryimportantnottomakeanyattemptsatcorrectingtheillegaldatathiscouldallowmalicioususerstomanipulateyourvalidationrulesfortheirownneedsaltogetherdefeatingthepurposeoffilteringthedatainthefirstplaceHistoryhasproventhatattemptingtocorrectinvaliddataoftenleadstosecurityvulnerabilitiesLetstakealookatanoverlysimpleexampleforillustrationpurposesSupposethatabankingsystemasksuserstosupplyasecure6digitpasswordThesystemvalidatesthelengthofallpasswordsOnemightnaivelywriteavalidationrulethatcorrectspasswordsofillegallengthsIfapasswordisshorterthanthelegallengthfillintheremainingdigitswith0sThissimplerulewouldallowattackerstoguessjustthefirstfewdigitsofapasswordtosuccessfullygainaccesstouseraccounts

Wecanuseseverallibrariestohelpustofilterdata

ThestrconvpackagecanhelpustoconvertstringsinputbyusersintospecifictypessincerFormsaremapsofstringvaluesSomecommonstringconversionsprovidedbystrconvareAtoiParseBoolParseFloatandParseIntGosstringspackagecontainssomefilterfunctionslikeTrimToLowerandToTitlewhichcanhelpustoobtaindatainaspecificformatsaccordingtoourneedsGosregexppackagecanbeusedtohandlecaseswhicharemorecomplexinnaturesuchasdeterminingwhetheraninputisanemailaddressabirthdayetc

Filterinputs

214

FilteringincomingdatainadditiontoauthenticationcanbequiteeffectiveLetsaddanothertechniquetoourrepertoirecalledwhitelistingWhitelistingisagoodwayofconfirmingthelegitimacyofincomingdataUsingthismethodifanerroroccursitcanonlymeanthattheincomingdataisillegalandnottheoppositeOfcoursewedontwanttomakeanymistakesinourwhitelistbyfalselylabellinglegitimatedataasillegalbutthisscenarioismuchbetterthanillegaldatabeinglabeledaslegitimateandthusmuchmoresecure

DistinguishingbetweenfilteredandtainteddataIfyouhavecompletedtheabovestepsthejoboffilteringdatahasbasicallybeencompletedHoweverwhenwritingwebapplicationswealsoneedtodistinguishbetweenfilteredandtainteddatabecausedoingsocanguaranteetheintegrityofourdatafilteringprocesswithoutaffectingtheinputdataLetsputallofourfiltereddataintoaglobalmapvariablecalledCleanMapThentwoimportantstepsarerequiredtopreventcontaminationviadatainjection

EachrequestmustinitializeCleanMapasanemptymapPreventvariablesfromexternaldatasourcesnamedCleanMapfrombeingintroducedintotheapp

Nextletsuseanexampleformtoreinforcetheseconcepts

ltformaction=whoamimethod=POSTgt

WhoamI

ltselectname=namegt

ltoptionvalue=astaxiegtastaxieltoptiongt

ltoptionvalue=herrygtherryltoptiongt

ltoptionvalue=marrygtmarryltoptiongt

ltselectgt

ltinputtype=submitgt

ltformgt

IndealingwiththistypeofformitcanbeveryeasytomakethemistakeofthinkingthatuserswillonlybeabletosubmitoneofthethreeselectoptionsInfactPOSToperationscaneasilybesimulatedbyattackersForexamplebysubmittingthesameformwithname=attackamalicioususercouldintroduceillegaldataintooursystemWecanuseasimplewhitelisttocounterthesetypesofattacks

rParseForm()

name=rFormGet(name)

CleanMap=make(map[string]interface0)

ifname==astaxie||name==herry||name==marry

CleanMap[name]=name

TheabovecodeinitializesaCleanMapvariableandanameisonlyassignedaftercheckingitagainstaninternalwhitelistoflegitimatevalues(astaxieherryandmarryinthiscase)WestorethedataintheCleanMapinstancesoyoucanbesurethatCleanMap[name]holdsavalidatedvalueAnycodewishingtoaccessthisvaluecanthenfreelydosoWecanalsoaddanadditionalelsestatementtotheaboveifwhitelistfordealingwithillegaldataapossibilitybeingthattheformwasdisplayedwithanerrorDonottrytobetooaccommodatingthoughoryouruntheriskofaccidentallycontaminatingyourCleanMap

TheabovemethodforfilteringdataagainstasetofknownlegitimatevaluesisveryeffectiveThereisanothermethodforcheckingwhetherornotincomingdataconsistsoflegalcharactersusingregexphoweverthiswouldbeineffectualintheabovecasewherewerequirethatthenamebeanoptionfromtheselectForexampleyoumayrequirethatusernamesonlyconsistoflettersandnumbers

rParseForm()

username=rFormGet(username)

CleanMap=make(map[string]interface0)

ifok_=regexpMatchString(^[a-zA-Z0-9]$username)ok

CleanMap[username]=username

Filterinputs

215

SummaryDatafilteringplaysavitalroleinthesecurityofmodernwebapplicationsMostsecurityvulnerabilitiesaretheresultofimproperlyfilteringdataorneglectingtoproperlyvalidateitBecausetheprevioussectiondealtwithCSRFattacksandthenexttwowillbeintroducingXSSattacksandSQLinjectiontherewasnonaturalsegueintodealingwithatopicasimportantasdatasanitizationsointhissectionwepaidspecialattentiontoit

LinksDirectoryPrevioussectionCSRFattacksNextsectionXSSattacks

Filterinputs

216

93XSSattacksWiththedevelopmentofInternettechnologywebapplicationsareoftenpackedwithdynamiccontenttoimproveuserexperienceDynamiccontentiscontentthatreactsandchangesaccordingtouserrequestsandactionsDynamicsitesareoftensusceptibletocross-sitescriptingattacks(oftenreferredtobysecurityexpertsinitsabbreviatedformXSS)somethingwhichstaticwebsitesarecompletelyunaffectedby

WhatisXSSAsmentionedthetermXSSisanacronymforCross-SiteScriptingwhichisatypeofattackcommononthewebInordernottoconfuseitwithanothercommonwebacronymCSS(CascadingStyleSheets)weuseanXinsteadofaCforthecrossincross-sitescriptingXSSisacommonwebsecurityvulnerabilitywhichallowsattackerstoinjectmaliciouscodeintowebpagesUnlikemosttypesofattackswhichgenerallyinvolveonlyanattackerandavictimXSSinvolvesthreepartiesanattackeraclientandawebapplicationThegoalofanXSSattackistostealcookiesstoredonclientsbywebapplicationsforthepurposeofreadingsensitiveclientinformationOnceanattackergetsaholdofthisinformationtheycanimpersonateusersandinteractwithwebsiteswithouttheirknowledgeorapproval

XSSattackscanusuallybedividedintotwocategoriesoneisastoredXSSattackThisformofattackariseswhenusersareallowedtoinputdataontoapublicpagewhichafterbeingsavedbytheserverwillbereturned(unescaped)tootherusersthathappentobebrowsingitSomeexamplesofthetypesofpagesthatareoftenaffectedincludecommentsreviewsblogpostsandmessageboardsTheprocessoftengoeslikethisanattackerenterssomehtmlfollowedbyahiddenltscriptgttagcontainingsomemaliciouscodethenhitssaveThewebapplicationsavesthistothedatabaseWhenanotheruserrequeststhispagetheapplicationqueriesthistainteddatafromthedatabaseandservesthepagetotheuserTheattackersscriptthenexecutesarbitrarycodeontheclientscomputer

TheothertypeisareflectedXSSattackThemainideaistoembedamaliciousscriptdirectlyintothequeryparametersofaURLaddressAserverthatimmediatelyparsesthisdataintoapageofresultsandreturnsit(totheclientwhomadetherequest)unsanitizedcanunwittinglycausetheclientscomputertoexecutethiscodeAnattackercansendauseralegitimatelookinglinktoatrustedwebsitewiththeencodedpayloadclickingonthislinkcancausetheusersbrowsertoexecutethemaliciousscript

XSSpresentthemainmeansandendsasfollows

TheftofcookiesaccesstosensitiveinformationTheuseofembeddedFlashthroughcrossdomainpermissionscanalsobeusedbyanattackertoobtainhigheruserprivilegesThisalsoappliesforothersimilarattackvectorssuchasJavaandVBScriptTheuseofiframesframesXMLHttpRequestsetccanallowanattackertoassumetheidentityofausertoperformadministrativeactionssuchasmicro-bloggingaddingfriendssendingprivatemessagesandotherroutineoperationsAwhileagotheSinamicrobloggingplatformsufferedfromthistypeofXSSvulnerabilityWhenmanyusersvisitapageaffectedbyanXSSattacktheeffectonsomesmallersitescanbecomparabletothatofaDDoSattack

XSSprinciplesWebapplicationsthatreturnrequesteddatatouserswithoutfirstinspectingandfilteringitcanallowmalicioususerstoinjectscripts(typicallyembeddedinsideHTMLwithinltscriptgttags)ontootherusersbrowsersWhenthismaliciouscodeisrenderedonausersbrowserwithoutfirsthavingbeenescapedfromtheusersbrowserwillinterpretthiscodethisisthedefinitionofanXSSattackandthistypeofmistakeistheleadingcauseofXSSvulnerabilities

LetsgothroughtheprocessofareflectiveXSSattackLetssaytheresawebsitethatoutputsausersnameaccordingtotheURLqueryparametersaccessthefollowingURLhttp127001name=astaxiewillcausetheservertooutputthefollowing

XSSattacks

217

helloastaxie

Letssaywepassthefollowingparameterinsteadaccessingthesameurlhttp127001name=ltscriptgtalert(astaxiexss)ltscriptgtIfthiscausesthebrowsertoproduceanalertpop-upboxwecanconfirmthatthesiteisvulnerabletoXSSattacksSohowdomalicioususersstealcookiesusingthesametypeofattack

JustlikebeforewehaveaURL

http127001

name=amp60scriptamp62documentlocationhref=httpwwwxxxcomcookie+documentcookieamp60scriptamp62

ByclickingonthisURLyoudbesendingthecurrentcookietothespecifiedsitewwwxxxcomYoumightbewonderingwhywouldanybodyclickonsuchastrangelookingURLinthefirstplaceWhileitstruethatthiskindofURLwillmakemostpeopleskepticalifanattackerweretouseoneofthemanypopularURLshorteningservicestoobscureitwouldyoustillbeabletoseeitMostattackerswouldobfuscatetheURLinonewayoranotherandyoudonlyknowthelegitimacyofthelinkafterclickingonitHoweverbythispointcookiedatawillhavealreadybeensenttothe3rdpartywebsitecompromisingyoursensitiveinformationYoucanusetoolslikeWebsleuthtoauditthesecurityofyourwebapplicationsforthesetypesofvulnerabilities

ForamoredetailedanalysisonanXSSattackhavealookatthearticle[SinamicrobloggingXSSeventanalysis](httpwwwrisingcomcnnewsletternews2011-08-189621html)

HowtopreventXSSTheanswerissimplenevertrustuserinputandalwaysfilteroutallspecialcharactersinanyinputdatayoumayreceiveThiswilleliminatethemajorityofXSSattacks

UsethefollowingtechniquestodefendagainstXSSattacks

Filterspecialcharacters

OnewaytoavoidXSSistofilteruser-suppliedcontentTheGolanguageprovidessomeHTMLfilteringfunctionsinitstexttemplatepackgesuchasHTMLEscapeStringandJSEscapeStringtonameafew

SpecifythecontenttypeinyourHTTPheaders

wHeader()Set(Content-Typetextjavascript)

Thisallowsclientbrowserstoparsetheresponseasjavascriptcode(applyingtheneccessaryfilters)insteadofrenderingthecontentinanunspecifiedandpotentiallydangerousmanner

SummaryIntroducingXSSvulnerabilitiesisaveryrealhazardwhendevelopingwebapplicationsItisimportanttoremembertofilteralldataespeciallybeforeoutputtingittoclientsthisisnowawell-establishedmeansofpreventingXSS

LinksDirectoryPrevioussectionFilterinputsNextsectionSQLinjection

XSSattacks

218

94SQLinjection

WhatisSQLinjectionSQLinjectionattacksare(asthenamewouldsuggest)oneofthemanytypesofscriptinjectionattacksInwebdevelopmentthesearethemostcommonformofsecurityvulnerabilitiesAttackerscanuseittoobtainsensitiveinformationfromdatabasesandaspectsofanattackcaninvolveaddinguserstothedatabaseexportingprivatefilesandevenobtainingthehighestsystemprivilegesfortheirownnefariouspurposes

SQLinjectionoccurswhenwebapplicationsdonoteffectivelyfilteroutuserinputleavingthedoorwideopenforattackerstosubmitmaliciousSQLquerycodetotheserverApplicationsoftenreceiveinjectedcodeaspartofanattackersinputwhichaltersthelogicoftheoriginalqueryinsomewayWhentheapplicationattemptstoexecutethequerytheattackersmaliciouscodeisexecutedinstead

SQLinjectionexamplesManywebdevelopersdonotrealizehowSQLqueriescanbetamperedwithandmayholdthemisconceptionthattheyaretrustedcommandsAseveryoneknowsSQLqueriesareabletocircumventaccesscontrolstherebybypassingthestandardauthenticationandauthorizationchecksWhatsmoreitspossibletorunSQLqueriesthroughcommandsatthelevelofthehostsystem

LetshavealookatsomerealexamplestoexplaintheprocessofSQLinjectionindetail

Considerthefollowingsimpleloginform

ltformaction=loginmethod=POSTgt

ltpgtUsernameltinputtype=textname=usernamegtltpgt

ltpgtPasswordltinputtype=passwordname=passwordgtltpgt

ltpgtltinputtype=submitvalue=Logingtltpgt

ltformgt

Ourformprocessingmightlooklikethis

username=rFormGet(username)

password=rFormGet(password)

sql=SELECTFROMuserWHEREusername=+username+ANDpassword=+password+

Iftheuserinputsausernameorpasswordas

myuserorfoo=foo--

ThenourSQLbecomesthefollowing

SELECTFROMuserWHEREusername=myuserorfoo=foo--ANDpassword=xxx

InSQLanythingafter--isacommentThusinsertingthe--astheattackerdidabovealtersthequeryinafatalwayallowinganattackertosuccessfullyloginasauserwithoutavalidpassword

FarmoredangerousexploitsexistforMSSQLSQLinjectionsandsomecanevenperformsystemcommandsThefollowingexampleswilldemonstratehowterribleSQLinjectionscanbeinsomeversionsofMSSQLdatabases

sql=SELECTFROMproductsWHEREnameLIKE+prod+

DbExec(sql)

SQLinjection

219

Ifanattackersubmitsaexecmasterxp_cmdshellnetusertesttestpassADD--astheprodvariablethenthesqlwillbecome

sql=SELECTFROMproductsWHEREnameLIKEaexecmasterxp_cmdshellnetusertesttestpassADD--

TheMSSQLServerexecutestheSQLstatementincludingthecommandsintheusersuppliedprodvariablewhichaddsnewuserstothesystemIfthisprogramisrunasisandtheMSSQLSERVERservicehassufficientprivilegesanattackercanregisterasystemaccounttoaccessthismachine

AlthoughtheexamplesabovearetiedtoaspecificdatabasesystemthisdoesnotmeanthatotherdatabasesystemscannotbesubjectedtosimilartypesofattacksTheprinciplesbehindSQLinjectionattacksremainthesamethoughthemethodwithwhichtheyareperpetratedmayvary

HowtopreventSQLinjectionYoumightbethinkingthatanattackerwouldhavetoknowinformationaboutthetargetdatabasesstructureinordertocarryoutanSQLinjectionattackWhilethisistrueitsdifficulttoguaranteethatanattackerwontbeabletofindthisinformationandoncetheygetitthedatabasecanbecompromisedIfyouareusingopensourcesoftwaretoaccessthedatabasesuchasaforumapplicationintruderscaneasilygettherelatedcodeObviouslywithpoorlydesignedcodethesecurityrisksareevengreaterDiscuzphpwindandphpcmsaresomeexamplesofpopularopensourceprogramsthathavebeenvulnerabletoSQLinjectionattacks

TheseattackshappentosystemswheresafetyprecautionsarenotprioritizedWevesaiditbeforewellsayitagainnevertrustanykindofinputespeciallyuserdataThisincludesdatacomingfromselectionboxeshiddeninputfieldsorcookiesAsourfirstexampleabovehasshownevensupposedlynormalqueriescancausedisasters

SQLinjectionattackscanbedevastating-howcandoweevenbegintodefendagainstthemThefollowingsuggestionsareagoodstartingpointforpreventingSQLinjection

1 Strictlylimitpermissionsfordatabaseoperationssothatusersonlyhavetheminimumsetofpermissionsrequiredtoaccomplishtheirworkthusminimizingtheriskofdatabaseinjectionattacks

2 CheckthatinputdatahastheexpecteddataformatandstrictlylimitthetypesofvariablesthatcanbesubmittedThiscaninvolveregexpmatchingorusingthestrconvpackagetoconvertstringsintootherbasictypesforsanitizationandevaluation

3 Transcodeorescapefrompairsofspecialcharacters(ampetc)beforepersistingthemintothedatabaseGostexttemplatepackagehasaHTMLEscapeStringfunctionthatcanbeusedtoreturnescapedHTML

4 UseyourdatabasesparameterizedqueryinterfaceParameterizedstatementsuseparametersinsteadofconcatenatinguserinputvariablesinembeddedSQLstatementsinotherwordstheydonotdirectlyspliceSQLstatementsForexampleusingthePreparefunctioninGosdatabasesqlpackagewecancreatepreparedstatementsforlaterexecutionwithQueryorExec(querystringargsinterface)

5 BeforereleasingyourapplicationthoroughlytestitusingprofessionaltoolsfordetectingSQLinjectionvulnerabilitiesandtorepairthemiftheyexistTherearemanyonlineopensourcetoolsthatdojustthissuchassqlmapSQLninjatonameafew

6 AvoidprintingoutSQLerrorinformationonpublicwebpagesAttackerscanusetheseerrormessagestocarryoutSQLinjectionattacksExamplesofsucherrorsaretypeerrorsfieldsnotmatchingerrorsoranyerrorscontainingSQLstatements

SummaryThroughtheaboveexampleswevelearnedthatSQLinjectionisaveryrealandverydangerouswebsecurityvulnerabilityWhenwewritewebapplicationweshouldpayattentiontoeverylittledetailandtreatsecurityissueswiththeutmostcareDoingsowillleadtobetterandmoresecurewebapplicationsandcanultimatelybethedetermingfactorinwhetherornotyourapplicationsucceeds

SQLinjection

220

LinksDirectoryPrevioussectionXSSattacksNextsectionPasswordstorage

SQLinjection

221

95PasswordstorageOvertheyearsmanywebsiteshavesufferedfrombreachesinuserpassworddataEventopinternetcompaniessuchasLinkedinandCSDNnethavebeenaffectedTheimpactoftheseeventshasbeenfeltacrosstheentireinternetandcannotbeunderestimatedThisisespeciallythecasefortodaysinternetuserswhooftenadoptthehabitofusingthesamepasswordformanydifferentwebsites

AswebdeveloperswehavemanychoiceswhenitcomestoimplementingapasswordstorageschemeHoweverthisfreedomisoftenadoubleedgedswordSowhatarethecommonpitfallsandhowcanweavoidfallingintothem

BadsolutionCurrentlythemostfrequentlyusedpasswordstorageschemeistoone-wayhashplaintextpasswordsbeforestoringthemThemostimportantcharacteristicofone-wayhashingisthatitisnotfeasibletorecovertheoriginaldatagiventhehasheddata-hencetheone-wayinone-wayhashingCommonlyusedcryptographicone-wayhashalgorithmsincludeSHA-256SHA-1MD5andsoon

YoucaneasilyusethethreeaforementionedhashingalgorithmsinGoasfollows

importcryptosha256

h=sha256New()

ioWriteString(hHismoneyistwicetaintedtaintyoursandtaintmine)

fmtPrintf(xhSum(nil))

importcryptosha1

h=sha1New()

ioWriteString(hHismoneyistwicetaintedtaintyoursandtaintmine)

fmtPrintf(xhSum(nil))

importcryptomd5

h=md5New()

ioWriteString(h需要加密的密码)

fmtPrintf(xhSum(nil))

Therearetwokeyfeaturesofone-wayhashing

1)givenaone-wayhashofapasswordtheresultingsummaryisalwaysuniquelydetermined2)calculationspeedAstechnologyadvancesitonlytakesasecondtocompletebillionsofone-wayhashcalculations

GiventhecombinationoftheabovetwocharacteristicsandtakingintoaccountthefactthatthemajorityofpeopleusesomecombinationofcommonpasswordsanattackercancomputeacombinationofallthecommonpasswordsEventhoughthepasswordsyoustoreinyourdatabasemaybehashvaluesonlyifattackersgainaccesstothisdatabasetheycancomparethestoredhashestotheirprecomputedhashestoobtainthecorrespondingpasswordsThistypeofattackreliesonwhatistypicallycalledarainbowtable

Wecanseethathashinguserdatausingone-wayhashesmaynotbeenoughOnceawebsitesdatabasegetsleakedtheusersoriginalpasswordcouldpotentiallyberevealedtotheworld

GoodsolutionThemethodmentionedabovemayhavebeensecureenoughtothwartmosthackingattemptsafewyearsagosincemostattackerswouldnothavehadthecomputingresourcestocomputelargerainbowtablesHoweverwiththeriseofparallelcomputingcapabilitiesthesetypesofattacksarebecomingmoreandmorefeasible

Passwordstorage

222

HowdowesecurelystoreapasswordsothatitcannotbedecipheredbyathirdpartygivenreallifelimitationsintimeandmemoryresourcesThesolutionistocalculateahashedpasswordtodeliberatelyincreasetheamountofresourcesandtimeitwouldtaketocrackitWewanttodesignahashsuchthatnobodycouldpossiblyhavetheresourcesrequiredtocomputetherequiredrainbowtable

VerysecuresystemsutilizehashalgorithmsthattakeintoaccountthetimeandresourcesitwouldrequiretocomputeagivenpassworddigestThisallowsustocreatepassworddigeststhatarecomputationallyexpensivetoperformonalargescaleThegreatertheintensityofthecalculationthemoredifficultitwillbeforanattackertopre-computerainbowtables-somuchsothatitmayevenbeinfeasibletotry

InGoitsrecommendedthatyouusethebcryptpackage

Thepackagessourcecodecanbefoundatthefollowinglinkhttpsgithubcomgolangcryptoblobmasterbcryptbcryptgo

Hereisanexamplecodesnippetwhichcanbeusedtohashstoreandvalidateuserpasswords

packagemain

import(

fmt

log

golangorgxcryptobcrypt

)

funcmain()

userPassword1=someuser-providedpassword

Generatehashtostorefromuserpassword

hasherr=bcryptGenerateFromPassword([]byte(userPassword1)bcryptDefaultCost)

iferr=nil

TODOProperlyhandleerror

logFatal(err)

fmtPrintln(Hashtostorestring(hash))

Storethishashsomewhereeginyourdatabase

Afterawhiletheuserwantstologinandyouneedtocheckthepasswordheentered

userPassword2=someuser-providedpassword

hashFromDatabase=hash

Comparingthepasswordwiththehash

iferr=bcryptCompareHashAndPassword(hashFromDatabase[]byte(userPassword2))err=nil

TODOProperlyhandleerror

logFatal(err)

fmtPrintln(Passwordwascorrect)

SummaryIfyoureworriedaboutthesecurityofyouronlinelifeyoucantakethefollowingsteps

1)AsaregularinternetuserwerecommendusingLastPassforpasswordstorageandgenerationondifferentsitesusedifferentpasswords

2)AsaGowebdeveloperwestronglysuggestthatyouuseoneoftheprofessionalwelltestedmethodsaboveforstoringuserpasswords

LinksDirectory

Passwordstorage

223

PrevioussectionSQLinjectionNextsectionEncryptanddecryptdata

Passwordstorage

224

96EncryptinganddecryptingdataTheprevioussectiondescribeshowtosecurelystorepasswordsbutsometimesitmightbeneccessarytomodifysomesensitiveencrypteddatathathasalreadybeenstoredintoourdatabaseWhendatadecryptionisrequiredweshoulduseasymmetricencryptionalgorithminsteadoftheone-wayhashingtechniqueswevepreviouslycovered

AdvancedencryptionanddecryptionTheGolanguagesupportssymmetricencryptionalgorithmsinitscryptopackageDonotuseanythingexceptAESinGCMmodeifyoudontknowwhatyouredoing

cryptoaespackageAES(AdvancedEncryptionStandard)alsoknownasRijndaelencryptionmethodisusedbytheUSfederalgovernmentasablockencryptionstandard

InthefollowingexamplewedemonstratehowtoencryptdatausingAESinGCMmode

Encryptanddecryptdata

225

packagemain

import(

cryptoaes

cryptocipher

cryptorand

errors

fmt

io

log

)

funcmain()

text=[]byte(MynameisAstaxie)

key=[]byte(the-key-has-to-be-32-bytes-long)

ciphertexterr=encrypt(textkey)

iferr=nil

TODOProperlyhandleerror

logFatal(err)

fmtPrintf(s=gtxntextciphertext)

plaintexterr=decrypt(ciphertextkey)

iferr=nil

TODOProperlyhandleerror

logFatal(err)

fmtPrintf(x=gtsnciphertextplaintext)

funcencrypt(plaintext[]bytekey[]byte)([]byteerror)

cerr=aesNewCipher(key)

iferr=nil

returnnilerr

gcmerr=cipherNewGCM(c)

iferr=nil

returnnilerr

nonce=make([]bytegcmNonceSize())

if_err=ioReadFull(randReadernonce)err=nil

returnnilerr

returngcmSeal(noncenonceplaintextnil)nil

funcdecrypt(ciphertext[]bytekey[]byte)([]byteerror)

cerr=aesNewCipher(key)

iferr=nil

returnnilerr

gcmerr=cipherNewGCM(c)

iferr=nil

returnnilerr

nonceSize=gcmNonceSize()

iflen(ciphertext)ltnonceSize

returnnilerrorsNew(ciphertexttooshort)

nonceciphertext=ciphertext[nonceSize]ciphertext[nonceSize]

returngcmOpen(nilnonceciphertextnil)

Encryptanddecryptdata

226

CallingtheabovefunctionaesNewCipher(whose[]bytekeyparametermustbe1624or32correspondingtotheAES-128AES-192orAES-256algorithmsrespectively)returnsacipherBlockInterfacethatimplementsthreefunctions

typeBlockinterface

BlockSizereturnstheciphersblocksize

BlockSize()int

Encryptencryptsthefirstblockinsrcintodst

Dstandsrcmaypointatthesamememory

Encrypt(dstsrc[]byte)

Decryptdecryptsthefirstblockinsrcintodst

Dstandsrcmaypointatthesamememory

Decrypt(dstsrc[]byte)

ThesethreefunctionsimplementencryptionanddecryptionoperationsseetheGodocumentationforamoredetailedexplanation

SummaryThissectiondescribesencryptionalgorithmswhichcanbeusedindifferentwaysaccordingtoyourwebapplicationsencryptionanddecryptionneedsForapplicationswithevenbasicsecurityrequirementsitisrecommendedtouseAESinGCMmode

LinksDirectoryPreviousstorepasswordsNextSummary

Encryptanddecryptdata

227

97SummaryInthischapterwevedescribedCSRFXSSandSQLinjectionbasedattacksMostwebapplicationsarevulnerabletothesetypesofattacksduetoalackofadequateinputfilteringonthepartoftheapplicationSoinadditiontointroducingtheprinciplesbehindtheseattackswevealsointroducedafewtechniquesforeffectivelyfilteringuserdataandpreventingtheseattacksfromevertakingplaceWethendiscussedafewmethodsforsecurelystoringuserpasswordsfirstintroducingbasicone-wayhashingforwebapplicationswithloosesecurityrequirementsthenpasswordsaltingandencryptionalgorithmsformoreseriousapplicationsFinallywebrieflydiscussedtwo-wayhashingandtheencryptionanddecryptionofsensitivedataWelearnedthattheGolanguageprovidespackagesforthreesymmetricencryptionalgorithmsbase64AESandDESThepurposeofthischapteristohelpreadersbecomemoreconsciousofthesecurityissuesthatexistinmoderndaywebapplicationsHopefullyitcanhelpdeveloperstoplananddesigntheirwebapplicationsalittlemorecarefullysotheycanwritesystemsthatareabletopreventhackersfromexploitinguserdataTheGolanguagehasalargeandwelldesignedanti-attacktoolkitandeveryGodevelopershouldtakefulladvantageofthesepackagestobettersecuretheirwebapplications

LinksDirectoryPrevioussectionEncryptanddecryptdataNextchapterInternationalizationandlocalization

Summary

228

10InternationalizationandlocalizationInordertoadapttotheincreasingglobalizationoftheinternetasdeveloperswemaysometimesneedtobuildmultilingualinternationalwebapplicationsThismeansthatsomepageswillappearindifferentlanguagesaccordingtouserregionsandperhapstheUIandUXwillalsobeadaptedtoshowdifferenteffectsbasedonlocalholidaysorcultureForexampleatruntimetheapplicationwillbeabletorecognizeandprocessrequestscomingfromdifferentgeographicalregionsandrenderpagesinthelocaldialectordisplaydifferentuserinterfaceAscompetentdeveloperswedontwanttohavetomanuallymodifyourapplicationssourcecodetocatertoeverypossibleregionoutthereWhenanapplicationneedstoaddsupportforanewlanguageweshouldbeabletosimplydropintheappropriatelanguagepackandbedonewithit

Inthissectionwellbetalkingaboutinternationalizationandlocalization(usuallyexpressedasi18nandL10Nrespectively)InternationalizationistheprocessofdesigningapplicationsthatareflexibleenoughtobeservedtomultipleregionsaroundtheworldInsomewayswecanthinkofinternationalizationassomethingthathelpstofacilitatelocalizationwhichistheadaptationofawebapplicationscontentanddesigntosuitthelanguageorculturalneedsofspecificlocales

CurrentlyGosstandardpackagedoesnotprovidei18nsupportbuttherearesomeusefulandrelativelysimplethird-partyimplementationsavailableInthischapterwellbeusingtheopen-sourcego-i18nlibrarytosupportinternationalizationinourexamples

WhenwetalkaboutmakingourwebapplicationsinternationalwemeanthateachwebpageshouldbeconstructedwithlocalespecificinformationandassembledwiththecorrespondinglocalstringstimeandcurrencyformatsetcThisinvolvesthreethings

1 howtodeterminetheuserslocale

2 howtosavestringsorotherinformationassociatedwiththelocale

3 howtoembedstringsandotherinformationaccordingtotheuserslocale

InthefirstsectionwelldescribehowtodetectandsetthecorrectlocaleinordertoallowwebsiteusersaccesstotheirlanguagespecificpagesThesecondsectiondescribeshowtohandleorstorestringscurrenciestimesdatesandotherlocalerelatedinformationFinallythethirdsectionwilldescribehowtointernationalizeyourwebapplicationmorespecificallywelldiscusshowtoreturndifferentpageswithlocaleappropriatecontentThroughthesethreesectionswellbeabletosupportfulli18ninourwebapplications

LinksDirectoryPreviousChapterChapter9SummaryNextsectionSettingthedefaultregion

Internationalizationandlocalization

229

101Settingthedefaultregion

FindingoutthelocaleAlocaleisasetofdescriptorsforaparticulargeographicalregionandcanincludespecificlanguagehabitstextformattingculturalidiomsandamultitudeofothersettingsAlocalesnameisusuallycomposedofthreepartsFirst(andmandatory)isthelocaleslanguageabbreviationsuchasenforEnglishorzhforChineseThesecondpartisanoptionalcountryspecifierandfollowsthefirstwithanminussignThisspecifierallowswebapplicationstodistinguishbetweendifferentcountrieswhichspeakthesamelanguagesuchasen-USforUSEnglishanden-GBforBritishEnglishThelastpartisanotheroptionalspecifierandisaddedtothelocalewithaperiodItspecifieswhichcharactersettouseforinstancezh-CNgb2312specifiesthegb2312charactersetforChinese

GodefaultstotheUTF-8encodingsetsoi18ninGoapplicationsdonotneedtoconsiderthelastparameterThusinourexampleswellonlyusethefirsttwopartsoflocaledescriptionsasourstandardi18nlocalenames

OnLinuxandSolarissystemsyoucanusethelocale-acommandtogetalistofallsupportedregionalnamesYoucanusethislistasexamplesofsomecommonlocalesForBSDandothersystemsthereisnolocalecommandbuttheregionalinformationisstoredinusrsharelocale

SettingthelocaleNowthatwevedefinedwhatalocaleisweneedtobeabletosetitaccordingtovisitingusersinformation(eitherfromtheirpersonalsettingsthevisiteddomainnameetc)Herearesomemethodswecanusetosettheuserslocale

Fromthedomainname

WecansetauserslocaleviathedomainnameitselfwhentheapplicationusesdifferentdomainsfordifferentregionsForexamplewecanusewwwastacomasourdefaultEnglishwebsiteandthedomainnamewwwastacnasitsChinesecounterpartBysettingupseparatedomainsforseparateregionsyoucandetectandservetherequestedlocaleThistypeofsetuphasseveraladvantages

IdentifyingthelocaleviaURLisdistinctiveandunambiguousUsersintuitivelyknowwhichdomainnamestovisitfortheirspecificregionorlanguageImplementingthisschemeinaGoapplicationisverysimpleandconvenientandcanbeachievedthroughamapConducivetosearchenginecrawlerswhichcanimprovethesitesSEO

Wecanusethefollowingcodetoimplementacorrespondingdomainnamelocale

ifrHost==wwwastacom

i18nSetLocale(en)

elseifrHost==wwwastacn

i18nSetLocale(zh-CN)

elseifrHost==wwwastatw

i18nSetLocale(zh-TW)

Alternativelywecouldhavealsosetlocalesthroughtheuseofsub-domainsuchasenastacomforEnglishsitesandcnastacomforChinesesiteThisschemecanberealizedincodeasfollows

Timezone

230

prefix=stringsSplit(rHost)

ifprefix[0]==en

i18nSetLocale(en)

elseifprefix[0]==cn

i18nSetLocale(zh-CN)

elseifprefix[0]==tw

i18nSetLocale(zh-TW)

Settinglocalesfromthedomainnameaswevedoneabovehasitsadvantageshoweverl10nisgenerallynotimplementedinthiswayFirstofallthecostofdomainnames(althoughusuallyquiteaffordableindividually)canquicklyaddupgiventhateachlocalewillneeditsowndomainnameandoftenthenameofthedomainwillnotnecessarilyfitinwiththelocalcontextSecondlywedontwanttohavetoindividuallyconfigureeachwebsiteforeachlocaleRatherweshouldbeabletodothisprogrammaticallyforinstancebyusingURLparametersLetshavealookatthefollowingdescription

FromURLparameters

Themostcommonwayofimplementingl10nistosetthedesiredlocaledirectlyintheURLparameterssuchwwwastacomhellolocale=zhorwwwastacomzhhelloThiswaywecansettheregionlikesoi18nSetLocale(params[locale])

ThissetuphasalmostalltheadvantagesofprependingthelocaleinfrontofthedomainanditsRESTfulsowedontneedtoaddadditionalmethodstoimplementitThedownsidetothisapproachisthatitrequiresacorrespondinglocaleparameterinsideeachlinkwhichcanbequitecumbersomeandmayincreasecomplexityHoweverwecanwriteagenericfunctionthatproducestheselocale-specificURLssothatalllinksaregeneratedthroughitThisfunctionshouldautomaticallyaddalocaleparametertoeachlinksowhenusersclickthemweareabletoparsetheirrequestswitheaselocale=params[locale]

PerhapswewantourURLstolookevenmoreRESTfulForexamplewecouldmapeachofourresourcesunderaspecificlocalelikewwwastacomenbooksforourEnglishsiteandwwwastacomzhbooksfortheChineseoneThisapproachisnotonlymoreconducivetoURLSEObutisalsomorefriendlyforusersAnybodyvisitingthesiteshouldbeabletoaccesslocale-specificwebsiteresourcesdirectlyfromtheURLSuchURLaddressescanthenbepassedthroughtheapplicationrouterinordertoobtaintheproperlocale(refertotheRESTsectionwhichdescribestherouterplug-inimplementation)

muxGet(localebookslistbook)

Fromtheclientsettingsarea

InsomespecialcaseswerequireexplicitclientinformationinordertosetthelocaleratherthanobtainingitfromtheURLorURLparametersThisinformationmaycomedirectlyfromtheclientsbrowsersettingstheusersIPaddressorthelocationsettingsfilledoutbytheuseratthetimeofregistrationThisapproachismoresuitableforweb-basedapplications

Accept-Language

WhenaclientrequestsinformationusinganHTTPheadersetwiththeAccept-LanguagefieldwecanusethefollowingGocodetoparsetheheaderandsettheappropriateregioncode

AL=rHeaderGet(Accept-Language)

ifAL==en

i18nSetLocale(en)

elseifAL==zh-CN

i18nSetLocale(zh-CN)

elseifAL==zh-TW

i18nSetLocale(zh-TW)

Ofcourseinrealworldapplicationswemayrequiremorerigorousprocessesandrulesforsettinguserregions

Timezone

231

IPAddress

AnotherwayofsettingaclientsregionistolookattheusersIPaddressWecanusethepopularGeoIPGeoLiteCountryorCitylibrariestohelpusrelateuserIPaddressestotheircorrespondingregionalareasImplementingthismechanismisverysimpleweonlyneedtolookuptheusersIPaddressinsideourdatabaseandthenreturnlocale-specificcontentaccordingtowhichregionwasreturned

Userprofile

Youcanalsoletusersprovideyouwiththeirlocaleinformationthroughaninputelementsuchasadrop-downmenu(orsomethingsimilar)WhenwereceivethisinformationwecansaveittotheaccountassociatedwiththeusersprofileWhentheuserlogsinagainwewillbeabletocheckandsettheirlocalesettings-thisguaranteesthateverytimetheuseraccessesthewebsitethereturnedcontentwillbebasedontheirpreviouslysetlocale

SummaryInthissectionwevedemonstratedavarietyofwayswithwhichuserspecificlocalescanbedetectedandsetThesemethodsincludedsettingtheuserlocaleviadomainnamesubdomainnameURLparametersanddirectlyfromclientsettingsBycateringtothespecificneedsofspecificregionswecanprovideacomfortablefamiliarandintuitiveenvironmentforuserstoaccesstheservicesthatweprovide

LinksDirectoryPreviousoneInternationalizationandlocalizationNextsectionLocalizedresources

Timezone

232

102LocalizedResourcesTheprevioussectiondescribedhowtosetlocalesAfterthelocalehasbeensetwethenneedtoaddresstheproblemofstoringtheinformationcorrespondingtospecificlocalesThisinformationcanincludetextualcontenttimeanddatecurrencyvaluespicturesspecificfilesandotherviewresourcesInGoallofthiscontextualinformationisstoredinJSONformatonourbackendtobecalleduponandinjectedintoourviewswhenusersfromspecificregionsvisitourwebsiteForexampleEnglishandChinesecontentwouldbestoredinenjsonandzh-CNjsonfilesrespectively

LocalizedtextualcontentPlaintextisthemostcommonwayofrepresentinginformationinwebapplicationsandthebulkofyourlocalizedcontentwilllikelytakethisformThegoalistoprovidetextualcontentthatisbothidiomatictoregionalexpressionsandfeelsnaturalforforeignusersofyoursiteOnesolutionistocreateanestedmapoflocalesnativelanguagestringsandtheirlocalcounterpartsWhenclientsrequestpageswithsometextualcontentwefirstchecktheirdesiredlocalethenretrievethecorrespondingstringsfromtheappropriatemapThefollowingsnippetisasimpleexampleofthisprocess

packagemain

importfmt

varlocalesmap[string]map[string]string

funcmain()

locales=make(map[string]map[string]string2)

en=make(map[string]string10)

en[pea]=pea

en[bean]=bean

locales[en]=en

cn=make(map[string]string10)

cn[pea]=豌豆

cn[bean]=毛豆

locales[zh-CN]=cn

lang=zh-CN

fmtPrintln(msg(langpea))

fmtPrintln(msg(langbean))

funcmsg(localekeystring)string

ifvok=locales[locale]ok

ifv2ok=v[key]ok

returnv2

return

Theaboveexamplesetsupmapsoftranslatedstringsfordifferentlocales(inthiscasetheChineseandEnglishlocales)WemapourcntranslationstothesameEnglishlanguagekeyssothatwecanreconstructourEnglishtextmessageinChineseIfwewantedtoswitchourtexttoanyotherlocalewemayhaveimplementeditdbeasimplematterofsettingonelangvariable

Simplekey-valuesubstitutionscansometimesbeinadequateforourneedsForexampleifwehadaphrasesuchasIam30yearsoldwhere30isavariablehowwouldwelocalizeitIncaseslikethesewecancombineusethefmtPrintffunctiontoachievethedesiredresult

en[howold]=Iamdyearsold

cn[howold]=我今年d岁了

fmtPrintf(msg(langhowold)30)

Localizedresources

233

TheexamplecodeaboveisonlyforthepurposeofdemonstrationactuallocaledataistypicallystoredinJSONformatinourdatabaseallowingustoexecuteasimplejsonUnmarshaltopopulatemaplocaleswithourstringtranslations

LocalizeddateandtimeBecauseofourtimezoneconventionsthetimeinoneregionoftheworldcanbedifferentthanthetimeinanotherregionSimilarlythewayinwhichtimeisrepresentedcanalsovaryfromlocaletolocaleForexampleaChineseenvironmentmayread2012年10月24日星期三23时11分13秒CSTwhileinEnglishitmightbeWedOct24231113CST2012NotonlyaretherevariationsinlanguagebuttherearedifferencesinformattingalsoSowhenitcomestolocalizingdatesandtimesweneedtoaddressthefollowingtwopoints

1 timezones2 formattingissues

The$GOROOTlibtimepackagetimeinfozipdirectorycontainslocalescorrespondingtotimezonedefinitionsInordertoobtainthetimecorrespondingtoauserscurrentlocaleweshouldfirstusetimeLoadLocation(namestring)togetaLocationobjectcorrespondingtoourlocalepassinginastringrepresentingthelocalesuchasAsiaShanghaiorAmericaChicagoWecanthenusethisLocationobjectinconjunctionwithaTimeobject(obtainedbycallingtimeNow)togetthefinaltimeusingtheTimeobjectsInmethodAdetailedlookatthisprocesscanbeseenbelow(thisexampleusessomeofthevariablesfromtheexampleabove)

en[time_zone]=AmericaChicago

cn[time_zone]=AsiaShanghai

loc_=timeLoadLocation(msg(langtime_zone))

t=timeNow()

t=tIn(loc)

fmtPrintln(tFormat(timeRFC3339))

Wecanhandletextformattinginasimilarwaytosolveourtimeformattingproblem

en[date_format]=Y-m-dHMS

cn[date_format]=Y年m月d日H时M分S秒

fmtPrintln(date(msg(langdate_format)t))

funcdate(fomatstringttimeTime)string

yearmonthday=tDate()

hourminsec=tClock()

ParsingthecorrespondingYmdHMSandthenreturningtheinformation

Yreplacedby2012

mreplacedby10

dreplacedby24

LocalizedcurrencyvalueObviouslycurrencydiffersfromregiontoregionalsoWecantreatitthesamewaywetreatedourdates

en[money]=USDd

cn[money]=¥d元

fmtPrintln(date(msg(langdate_format)100))

funcmoney_format(fomatstringmoneyint64)string

returnfmtSprintf(fomatmoney)

Localizedresources

234

LocalizationofviewsandresourcesWecanservecustomizedviewswithdifferentimagescssjsandotherstaticresourcesdependingonthecurrentlocaleOnewaytoaccomplishthisisbyorganizingthesefilesintotheirrespectivelocalesHeresanexample

views

|--enEnglishTemplates

|--imagesstorepictureinformation

|--jsJSfiles

|--cssCSSfiles

indextplUserHome

logintplLogHome

|--zh-CNChineseTemplates

|--images

|--js

|--css

indextpl

logintpl

Withthisdirectorystructurewecanrenderlocale-specificviewslikeso

s1_=templateParseFiles(views+lang+indextpl)

VVLang=lang

s1Execute(osStdoutVV)

Theresourcesreferencedintheindextplfilecanbedealtwithasfollows

jsfile

ltscripttype=textjavascriptsrc=viewsVVLangjsjqueryjquery-180minjsgtltscriptgt

cssfile

ltlinkhref=viewsVVLangcssbootstrap-responsivemincssrel=stylesheetgt

Picturefiles

ltimgsrc=viewsVVLangimagesbtnpnggt

Withdynamicviewsandthewaywevelocalizedourresourceswewillbeabletoaddmorelocaleswithoutmucheffort

SummaryThissectiondescribedhowtouseandstorelocalresourcesWelearnedthatwecanuseconversionfunctionsandstringinterpolationforthisandsawthatmapscanbeaneffectivewayofstoringlocale-specificdataForthelatterwecouldsimplyextractthecorrespondinglocaleinformationwhenneeded-ifitwastextualcontentwedesiredourmappedtranslationsandidiomscouldbepipeddirectlytotheoutputIfitwassomethingmoresophisticatedliketimeorcurrencywesimplyusedthefmtPrintffunctiontoformatitbefore-handLocalizingourviewsandresourceswastheeasiestcaseandsimplyinvolvedorganizingourfilesintotheirrespectivelocalesthenreferencingthemfromtheirlocalerelativepaths

LinksDirectoryPrevioussectionSettingthedefaultregionNextsectionInternationalsites

Localizedresources

235

103InternationalsitesTheprevioussectionexplainedhowtodealwithlocalizedresourcesnamelybyusinglocaleconfigurationfilesSowhatcanwedoifweneedtodealwithmultiplelocalizedresourcesliketexttranslationstimesanddatesnumbersetcThissectionwilladdresstheseissuesonebyone

ManagingmultiplelocalepackagesInthedevelopmentofanapplicationoftenthefirstthingyouneedtodoistodecidewhetherornotyouwanttosupportmorethanonelanguageIfyoudodecidetosupportmultiplelanguagesyoullneedtodevelopanorganizationalstructuretofacilitatetheprocessofaddingmorelanguagesinthefutureOnewaywecandothisistoputallourrelatedlocalefilestogetherinaconfiglocalesdirectoryorsomethingofthelikeLetssupposeyouwanttosupportbothChineseandEnglishInthiscaseyoudbeplacingboththeenjsonandzhjsonlocalefilesintotheaforementionedfolderTheircontentswouldprobablylooksomethinglikethefollowing

zhjson

zh

submit提交

create创建

enjson

en

submitSubmit

createCreate

Wedecidedtousesome3rdpartyGopackagestohelpusinternationalizeourwebapplicationsInthecaseofgo-i18n(Amoreadvancedi18npackagecanbefoundhere)wefirsthavetoregisterourconfiglocalesdirectorytoloadallofourlocalefiles

Tr=i18nNewLocale()

TrLoadPath(configlocales)

ThispackageissimpletouseWecantestthatitworkslikeso

fmtPrintln(TrTranslate(submit))

Outputsubmit

TrSetLocale(zn)

fmtPrintln(TrTranslate(submit))

Outputs递交

AutomaticallyloadlocalpackageWevejustdescribedhowtoautomaticallyloadcustomlanguagepacksInfactthego-i18nlibrarycomespre-loadedwithabunchofdefaultformattinginformationsuchastimeandcurrencyformatsThesedefaultconfigurationscanbeoverriddenandcustomizedbyuserstosuittheirneedsConsiderthefollowingprocess

Internationalsites

236

Loadthedefaultconfigurationfileswhichareplacedbelowin`go-i18nlocales`

Fileshouldbenamedzhjsonen-jsonen-USjsonetcsowecancontinuouslysupportmorelanguages

func(ilIL)loadDefaultTranslations(dirPathstring)error

direrr=osOpen(dirPath)

iferr=nil

returnerr

deferdirClose()

nameserr=dirReaddirnames(-1)

iferr=nil

returnerr

for_name=rangenames

fullPath=pathJoin(dirPathname)

fierr=osStat(fullPath)

iferr=nil

returnerr

iffiIsDir()

iferr=illoadTranslations(fullPath)err=nil

returnerr

elseiflocale=ilmatchingLocaleFromFileName(name)locale=

fileerr=osOpen(fullPath)

iferr=nil

returnerr

deferfileClose()

iferr=illoadTranslation(filelocale)err=nil

returnerr

returnnil

Usingtheabovecodetoloadallofourdefaulttranslationswecanthenusethefollowingcodetoselectandusealocale

fmtPrintln(TrTime(timeNow()))

Output2009年1月08日星期四203758CST

fmtPrintln(TrTime(timeNow()long))

Output2009年1月08日

fmtPrintln(TrMoney(1111))

Outputyen1111

TemplatemapfuncAbovewevepresentedonewayofmanagingandintegratinganumberoflanguagepacksSomeofthefunctionsweveimplementedarebasedonthelogicallayerforexampleTrTranslateTrTimeTrMoneyandsoonInthelogicallayerwecanusethesefunctions(aftersupplyingtherequiredparameters)forapplyingyourtranslationsoutputtingtheresultsdirectlytothetemplatelayeratrendertimeWhatcanwedoifwewanttousethesefunctionsdirectlyinthetemplatelayerIncaseyouveforgottenearlierinthebookwementionedthatGotemplatessupportcustomtemplatefunctionsThefollowingcodeshowshoweasymapfuncistoimplement

1textinformation

Internationalsites

237

AsimpletextconversionfunctionimplementingamapfunccanbeseenbelowItusesTrTranslatetoperformtheappropriatetranslations

funcI18nT(argsinterface)string

ok=false

varsstring

iflen(args)==1

sok=args[0](string)

ifok

s=fmtSprint(args)

returnTrTranslate(s)

Weregisterthefunctionlikeso

tFuncs(templateFuncMapTI18nT)

Thenuseitfromyourtemplate

VSubmit|T

1 Thedateandtime

DatesandtimescalltheTrTimefunctiontoperformtheirtranslationsThemapfuncisimplementedasfollows

funcI18nTimeDate(argsinterface)string

ok=false

varsstring

iflen(args)==1

sok=args[0](string)

ifok

s=fmtSprint(args)

returnTrTime(s)

Registerthefunctionlikeso

tFuncs(templateFuncMapTDI18nTimeDate)

Thenuseitfromyourtemplate

VNow|TD

3CurrencyInformation

CurrenciesusetheTrMoneyfunctiontoconvertmoneyThemapFuncisimplementedasfollows

Internationalsites

238

funcI18nMoney(argsinterface)string

ok=false

varsstring

iflen(args)==1

sok=args[0](string)

ifok

s=fmtSprint(args)

returnTrMoney(s)

Registerthefunctionlikeso

tFuncs(templateFuncMapMI18nMoney)

Thenuseitfromyourtemplate

VMoney|M

SummaryInthissectionwelearnedhowtoimplementmultiplelanguagepacksinourwebapplicationsWesawthatthroughcustomlanguagepackswecannotonlyeasilyinternationalizeourapplicationsbutfacilitatetheadditionofotherlanguagesalso(throughtheuseofaconfigurationfile)Bydefaultthego-i18npackagewillprovidesomecommonconfigurationsfortimecurrencyetcwhichcanbeveryconvenienttouseWelearnedthatthesefunctionscanalsobeuseddirectlyfromourtemplatesusingmappingfunctionseachtranslatedstringcanbepipeddirectlytoourtemplatesThisenablesourwebapplicationstoaccommodatemultiplelanguageswithminimaleffort

LinksDirectoryPrevioussectionLocalizedresourcesNextsectionSummary

Internationalsites

239

104SummaryThroughthisintroductorychapteroni18nyoushouldnowbefamiliarwithsomeofthestepsandprocessesthatarenecessaryforinternationalizingandlocalizingyourwebsitesIvealsointroducedanopensourcesolutionfori18ninGogo-i18nUsingthisopensourcelibrarywecaneasilyimplementmulti-languageversionsofourwebapplicationsThisallowsourapplicationstobeflexibleandresponsivetolocalaudiencesallaroundtheworldIfyoufindanerrorinthisopensourcelibraryoranymissingfeaturespleaseopenanissueorapullrequestLetsstrivetomakeitoneofGosstandardlibraries

LinksDirectoryPrevioussectionInternationalsitesNextchapterErrorhandlingdebuggingandtesting

Summary

240

11ErrorHandlingDebuggingandTestingWeoftenseethemajorityofaprogrammersprogrammingtimespentoncheckingforbugsandworkingonbugfixesWhetheryouarerefactoringcodeorre-configuringsystemsmuchofyourtimewillundoubtedlybespenttroubleshootingandtestingFromtheoutsidepeoplemaythinkthatallwedoasprogrammersisdesignoursystemsandthenwriteourcodeTheymightthinkthatwehavetheidealjobWedoworkthatisveryengagingandimplementsystemsthathaveneverbeendonebeforeWhilethislastpartmaybetruewhattheydontknowisthatwespendthemajorityofourtimecyclingbetweentroubleshootingdebuggingandtestingourcodeOfcourseifyouhavegoodprogramminghabitsandthetechnologicalsolutionstohelpyoutakeonthesetasksthenyoucanminimizethetimespentdoingthesethingsenablingyoutofocusinsteadonmorevaluablethingsliketheapplicationlogic

UnfortunatelymanyprogrammersarenotthoroughinfulfillingtheirerrorhandlingdebuggingandtestingresponsibilitiesbeforehandInexperiencedprogrammerswilloftenonlymakeanefforttofinderrorsandflawsaftertheyhaveoccurredspendinghourslocatingandfixingproblemsaftertheapplicationisalreadyonlineItsgoodpractice(andprobablycommonsense)thatweshoulddesignourapplicationswithpropererrorhandlingtestcasesetcfromthegetgoThiswillmakeyourjobandthejobsofalltheotherdeveloperswhomaybeworkingonyourapplicationsomedaymucheasierwhentheyinevitablyneedtomodifythecodeorupgradethesystem

IntheprocessofdevelopingwebapplicationsyouwillinevitablyencounterunforeseenerrorsWhatsthemostefficientwayoffindingthecausesoftheseerrorsandsolvingthemSection111describeshowtohandleerrorsintheGolanguageaswellashowtodesignyourownerrorhandlingpackageandfunctionsSection112describeshowtouseGDBtodebugprogramsunderdynamicoperatingconditionsdependingonavarietyofvariableinformationWethendiscussapplicationmonitoringanddebuggingoperations

Section113willexplainunittestinginGoandfeaturesomein-depthdiscussionsandexamplesonhowtowriteunittestsaswellasdefiningGosunittestingrulesWellseehowfollowingtheseruleswillensurethatwhenupgradingormodifyingyourapplicationthetestcodewillbeabletorunsmoothly

ManyprogrammersavoidspendingtimetolearnandcultivategooddebuggingandtestinghabitsThischaptertakesontheseissueshead-onsoyouwonthavetorunawayfromthesetasksanylongerSinceyourejustlearninghowtobuildwebapplicationsinGoletsusethisopportunitytoestablishthesegoodhabitsfromtheverybeginning

LinksDirectoryPreviouschapterChapter10summaryNextsectionErrorhandling

Errorhandlingdebuggingandtesting

241

111ErrorhandlingGosmajordesignconsiderationsarerootedinthefollowingideasasimpleclearandconcisesyntax(similartoC)andstatementswhichareexplicitanddontcontainanyhiddenorunexpectedthingsGoserrorhandlingschemereflectsalloftheseprinciplesinthewaythatitsimplementedIfyourefamiliarwiththeClanguageyoullknowthatitscommontoreturn-1orNULLvaluestoindicatethatanerrorhasoccurredHoweveruserswhoarenotfamiliarwithCsAPIwillnotknowexactlywhatthesereturnvaluesmeanInCitsnotexplicitwhetheravalueof0indicatessuccessoffailureOntheotherhandGoexplicitlydefinesatypecallederrorforthesolepurposeofexpressingerrorsWheneverafunctionreturnswechecktoseewhethertheerrorvariableisnilornottodetermineiftheoperationwassuccessfulForexampletheosOpenfunctionfailsitwillreturnanon-nilerrorvariable

funcOpen(namestring)(fileFileerrerror)

HeresanexampleofhowwedhandleanerrorinosOpenFirstweattempttoopenafileWhenthefunctionreturnswechecktoseewhetheritsucceededornotbycomparingtheerrorreturnvaluewithnilcallinglogFataltooutputanerrormessageifitsanon-nilvalue

ferr=osOpen(filenameext)

iferr=nil

logFatal(err)

SimilartotheosOpenfunctionthefunctionsinGosstandardpackagesallreturnerrorvariablestofacilitateerrorhandlingThissectionwillgointodetailaboutthedesignoferrortypesanddiscusshowtoproperlyhandleerrorsinwebapplications

Errortypeerrorisaninterfacetypewiththefollowingdefinition

typeerrorinterface

Error()string

errorisabuilt-ininterfacetypeWecanfinditsdefinitioninthebuiltinpackagebelowWealsohavealotofinternalpackageswhichuseerrorinaprivatestructurecallederrorStringwhichimplementstheerrorinterface

errorStringisatrivialimplementationoferror

typeerrorStringstruct

sstring

func(eerrorString)Error()string

returnes

YoucanconvertaregularstringtoanerrorStringthrougherrorsNewinordertogetanobjectthatsatisfiestheerrorinterfaceItsinternalimplementationisasfollows

Newreturnsanerrorthatformatsasthegiventext

funcNew(textstring)error

returnamperrorStringtext

Errorhandling

242

ThefollowingexampledemonstrateshowtouseerrorsNew

funcSqrt(ffloat64)(float64error)

ifflt0

return0errorsNew(mathsquarerootofnegativenumber)

implementation

InthefollowingexamplewepassanegativenumbertoourSqrtfunctionCheckingtheerrvariablewecheckwhethertheerrorobjectisnon-nilusingasimplenilcomparisonTheresultofthecomparisonistruesofmtPrintln(thefmtpackagecallstheerrormethodwhendealingwitherrorcalls)iscalledtooutputanerror

ferr=Sqrt(-1)

iferr=nil

fmtPrintln(err)

CustomErrorsThroughtheabovedescriptionweknowthatagoErrorisaninterfaceBydefiningastructthatimplementsthisinterfacewecanimplementtheirerrordefinitionsHeresanexamplefromtheJSONpackage

typeSyntaxErrorstruct

msgstringerrordescription

Offsetint64wheretheerroroccurred

func(eSyntaxError)Error()stringreturnemsg

TheerrorsOffsetfieldwillnotbeprintedatruntimewhensyntaxerrorsoccurbutusingatypeassertionerrortypeyoucanprintthedesirederrormessage

iferr=decDecode(ampval)err=nil

ifserrok=err(jsonSyntaxError)ok

linecol=findLine(fserrOffset)

returnfmtErrorf(sddvfName()linecolerr)

returnerr

ItshouldbenotedthatwhenthefunctionreturnsacustomerrorthereturnvalueissettotherecommendedtypeoferrorratherthanacustomerrortypeBecarefulnottopre-declarevariablesofcustomerrortypesForexample

funcDecode()SyntaxError

errorwhichmayleadtothecallerserr=nilcomparisontoalwaysbetrue

varerrSyntaxErrorpre-declareerrorvariable

ifanerrorcondition

err=ampSyntaxError

returnerrerrorerralwaysequalnon-nilcausescallerserr=nilcomparisontoalwaysbetrue

Seehttpgolangorgdocfaqnil_errorforanindepthexplanation

TheaboveexampleshowshowtoimplementasimplecustomErrortypeButwhatifweneedmoresophisticatederrorhandlingInthiscasewehavetorefertothenetpackageapproach

Errorhandling

243

packagenet

typeErrorinterface

error

Timeout()boolIstheerroratimeout

Temporary()boolIstheerrortemporary

UsingtypeassertionwecancheckwhetherornotourerrorisoftypenetErrorasshowninthefollowingexampleThisallowsustorefineourerrorhandling-ifatemporaryerroroccursonthenetworkitwillsleepfor1secondthenretrytheoperation

ifnerrok=err(netError)okampampnerrTemporary()

timeSleep(1e9)

continue

iferr=nil

logFatal(err)

ErrorhandlingGohandleserrorsandchecksthereturnvaluesoffunctionsinaC-likefashionwhichisdifferenttohowmostoftheothermajorlanguagesdoThismakesthecodemoreexplicitandpredictablebutalsomoreverboseToreducetheredundancyofourerror-handlingcodewecanuseabstracterrorhandlingfunctionsthatallowustoimplementsimilarerrorhandlingbehaviour

funcinit()

httpHandleFunc(viewviewRecord)

funcviewRecord(whttpResponseWriterrhttpRequest)

c=appengineNewContext(r)

key=datastoreNewKey(cRecordrFormValue(id)0nil)

record=new(Record)

iferr=datastoreGet(ckeyrecord)err=nil

httpError(werrError()500)

return

iferr=viewTemplateExecute(wrecord)err=nil

httpError(werrError()500)

TheaboveexampledemonstratehowthedataaccessandtemplatecallhasdetectedanerrorWhenanerroroccursacalltounifiedhandlerhttpErrorreturnsa500errorcodetotheclientanddisplaysthecorrespondingerrordataButwhenmoreandmoreHandleFunccallsaremadesoerror-handlinglogiccodewillincreaseWecancustomizetheroutertoreducecode(refertothethirdchapterofHTTPformoredetail)

typeappHandlerfunc(httpResponseWriterhttpRequest)error

func(fnappHandler)ServeHTTP(whttpResponseWriterrhttpRequest)

iferr=fn(wr)err=nil

httpError(werrError()500)

AbovewevedefinedacustomrouterWecanthenregisterourhandlerasusual

Errorhandling

244

funcinit()

httpHandle(viewappHandler(viewRecord))

Theviewhandlercanthenbehandledbythefollowingcodeitisalotsimplerthanouroriginalimplementationisntit

funcviewRecord(whttpResponseWriterrhttpRequest)error

c=appengineNewContext(r)

key=datastoreNewKey(cRecordrFormValue(id)0nil)

record=new(Record)

iferr=datastoreGet(ckeyrecord)err=nil

returnerr

returnviewTemplateExecute(wrecord)

Theerrorhandlerexampleabovewillreturnthe500InternalErrorcodetouserswhenanyerrorsoccurinadditiontoprintingoutthecorrespondingerrorcodeInfactwecancustomizethetypeoferrorreturnedtooutputamoredeveloperfriendlyerrormessagewithinformationthatisusefulfordebugginglikeso

typeappErrorstruct

Errorerror

Messagestring

Codeint

Ourcustomroutercanbechangedaccordingly

typeappHandlerfunc(httpResponseWriterhttpRequest)appError

func(fnappHandler)ServeHTTP(whttpResponseWriterrhttpRequest)

ife=fn(wr)e=nileisappErrornotosError

c=appengineNewContext(r)

cErrorf(veError)

httpError(weMessageeCode)

Afterwevefinishedmodifyingourcustomerrorourlogiccanbechangedasfollows

funcviewRecord(whttpResponseWriterrhttpRequest)appError

c=appengineNewContext(r)

key=datastoreNewKey(cRecordrFormValue(id)0nil)

record=new(Record)

iferr=datastoreGet(ckeyrecord)err=nil

returnampappErrorerrRecordnotfound404

iferr=viewTemplateExecute(wrecord)err=nil

returnampappErrorerrCantdisplayrecord500

returnnil

AsshownabovewecanreturndifferenterrorcodesanderrormessagesinourviewsdependingonthesituationAlthoughthisversionofourcodefunctionssimilarlytothepreviousversionitsmoreexplicitanditserrormessagepromptsaremorecomprehensibleAllofthesefactorscanhelptomakeyourapplicationmorescalableascomplexityincreases

Summary

Errorhandling

245

FaulttoleranceisaveryimportantaspectofanyprogramminglanguageInGoitisachievedthrougherrorhandlingAlthoughErrorisonlyoneinterfaceitcanhavemanyvariationsinthewaythatitsimplementedandwecancustomizeitaccordingtoourneedsonacasebycasebasisByintroducingthesevariouserrorhandlingconceptswehopethatyouwillhavegainedsomeinsightonhowtoimplementbettererrorhandlingschemesinyourownwebapplications

LinksDirectoryPrevioussectionErrorhandlingdebuggingandtestingNextsectionDebuggingbyusingGDB

Errorhandling

246

112DebuggingwithGDBDuringthedevelopmentprocessofanyapplicationdeveloperswillalwaysneedtoperformsomekindofcodedebuggingPHPPythonandmostoftheotherdynamiclanguagesareabletobemodifiedatruntimeaslongasthemodificationsdonotexplicitlyneedtobecompiledWecaneasilyprintdataindynamicoperatingenvironmentsoutputtingourchangesandprintingvariableinformationdirectlyInGoyoucanofcoursespeckleyourcodewithPrintlnsbefore-handtodisplayvariableinformationfordebuggingpurposesbutanychangestoyourcodeneedtoberecompiledeverytimeThiscanquicklybecomecumbersomeIfyouveprogrammedinPythonorJavascriptyoullknowthattheformerprovidestoolssuchaspdbandipdbfordebuggingandthelatterhassimilartoolsthatareabletodynamicallydisplayvariableinformationandfacilitatesingle-stepdebuggingFortunatelyGohasnativesupportforasimilartoolwhichprovidessuchdebuggingfeaturesGDBThissectionservesasabriefintroductionintodebuggingGoapplicationsusingGDB

GDBdebuggingprofileGDBisapowerfuldebuggingtooltargetingUNIX-likesystemsreleasedbytheFSF(FreeSoftwareFoundation)GDBallowsustodothefollowingthings

1 Initialsettingscanbecustomizeaccordingtothespecificrequirementsofyourapplication2 Canbesetsothattheprogrambeingdebuggedinthedevelopersconsolestopsattheprescribedbreakpoints

(breakpointscanbeconditionalexpressions)3 Whentheprogramhasbeenstoppedyoucancheckitscurrentstatetoseewhathappened4 Dynamicallychangethecurrentprogramsexecutionenvironment

TodebugyourGoapplicationsusingGDBtheversionofGDByouusemustbegreaterthan71

WhencompilingGoprogramsthefollowingpointsrequireparticularattention

1 Using-ldflags-swillpreventthestandarddebugginginformationfrombeingprinted2 Using-gcflags-N-lwillpreventGofromperformingsomeofitsautomatedoptimizations-optimizationsof

aggregatevariablesfunctionsetcTheseoptimizationscanmakeitverydifficultforGDBtodoitsjobsoitsbesttodisablethematcompiletimeusingtheseflags

SomeofGDBsmostcommonlyusedcommandsareasfollows

list

AlsousedinitsabbreviatedformllistisusedtodisplaythesourcecodeBydefaultitdisplaystenlinesofcodeandyoucanspecifythelineyouwishtodisplayForexamplethecommandlist15displaystenlinesofcodecenteredaroundline15asshownbelow

10timeSleep(2timeSecond)

11clt-i

12

13close(c)

14

15

16funcmain()

17msg=Startingmain

18fmtPrintln(msg)

19bus=make(chanint)

break

AlsousedinitsabbreviatedformbbreakisusedtosetbreakpointsandtakesasanargumentthatdefineswhichpointtosetthebreakpointatForexampleb10setsabreakpointatthetenthrow

delete

DebuggingbyusingGDB

247

AlsousedinitsabbreviatedformddeleteisusedtodeletebreakpointsThebreakpointissetfollowedbytheserialnumberTheserialnumbercanbeobtainedthroughtheinfobreakpointscommandBreakpointssetwiththeircorrespondingserialnumbersaredisplayedasfollowstosetabreakpointnumber

NumTypeDispEnbAddressWhat

2breakpointkeepy0x0000000000400dc3inmainmainathomexiemengjungdbgo23

breakpointalreadyhit1time

backtrace

Abbreviatedasbtthiscommandisusedtoprinttheexecutionofthecodeforinstance

0mainmain()athomexiemengjungdbgo23

10x000000000040d61einruntimemain()athomexiemengjungosrcpkgruntimeprocc244

20x000000000040d6c1inschedunlock()athomexiemengjungosrcpkgruntimeprocc267

30x0000000000000000in()

info

TheinfocommandcanbeusedinconjunctionwithseveralparameterstodisplayinformationThefollowingparametersarecommonlyused

infolocals

Displaysthecurrentlyexecutingprogramsvariablevalues

infobreakpoints

Displaysalistofcurrentlysetbreakpoints

infogoroutines

Displaysthecurrentlistofrunninggoroutinesasshowninthefollowingcodewiththeindicatingthecurrentexecution

1runningruntimegosched

2syscallruntimeentersyscall

3waitingruntimegosched

4runnableruntimegosched

print

AbbreviatedaspthiscommandisusedtoprintvariablesorotherinformationIttakesasargumentsthevariablenamestobeprintedandofcoursetherearesomeveryusefulfunctionssuchas$len()and$cap()thatcanbeusedtoreturnthelengthorcapacityofthecurrentstringsslicesormaps

whatis

whatisisusedtodisplaythecurrentvariabletypefollowedbythevariablenameForinstancewhatismsgwilloutputthefollowing

type=structstring

next

Abbreviatedasnnextisusedinsingle-stepdebuggingtoskiptothenextstepWhenthereisabreakpointyoucanenterntojumptothenextsteptocontinue

continue

AbbreviatedasccontinueisusedtojumpoutofthecurrentbreakpointandcanbefollowedbyaparameterNwhichspecifiesthenumberoftimestoskipthebreakpoint

setvariable

DebuggingbyusingGDB

248

ThiscommandisusedtochangethevalueofavariableintheprocessItcanbeusedlikesosetvariableltvargt=ltvaluegt

ThedebuggingprocessNowletstakealookatthefollowingcodetoseehowGDBistypicallyusedtodebugGoprograms

packagemain

import(

fmt

time

)

funccounting(cchanlt-int)

fori=0ilt10i++

timeSleep(2timeSecond)

clt-i

close(c)

funcmain()

msg=Startingmain

fmtPrintln(msg)

bus=make(chanint)

msg=startingagofunc

gocounting(bus)

forcount=rangebus

fmtPrintln(countcount)

Nowwecompilethefilecreatinganexecutablefilecalledgdbfile

gobuild-gcflags-N-lgdbfilego

UsetheGDBcommandtostartdebugging

gdbgdbfile

AfterfirststartingGDByoullhavetoentertheruncommandtoseeyourprogramrunningYouwillthenseetheprogramoutputthefollowingexecutingtheprogramdirectlyfromthecommandlinewilloutputexactlythesamething

(gdb)run

Startingprogramhomexiemengjungdbfile

Startingmain

count0

count1

count2

count3

count4

count5

count6

count7

count8

count9

[LWP2771exited]

[Inferior1(process2771)exitednormally]

Oknowthatweknowhowtogettheprogramupandrunningletstakealookatsettingbreakpoints

DebuggingbyusingGDB

249

(gdb)b23

Breakpoint1at0x400d8dfilehomexiemengjungdbfilegoline23

(gdb)run

Startingprogramhomexiemengjungdbfile

Startingmain

[NewLWP3284]

[SwitchingtoLWP3284]

Breakpoint1mainmain()athomexiemengjungdbfilego23

23fmtPrintln(countcount)

Intheaboveexampleweusetheb23commandtosetabreakpointonline23ofourcodethenenterruntostarttheprogramWhenourprogramstopsatourbreakpointwetypicallyneedtolookatthecorrespondingsourcecodecontextEnteringthelistcommandintoourGDBsessionwecanseethefivelinesofcodeprecedingourbreakpoint

(gdb)list

18fmtPrintln(msg)

19bus=make(chanint)

20msg=startingagofunc

21gocounting(bus)

22forcount=rangebus

23fmtPrintln(countcount)

24

25

NowthatGDBisrunningthecurrentprogramenvironmentwehaveaccesstosomeusefuldebugginginformationthatwecanprintoutToseethecorrespondingvariabletypesandvaluestypeinfolocals

(gdb)infolocals

count=0

bus=0xf840001a50

(gdb)pcount

$1=0

(gdb)pbus

$2=(chanint)0xf840001a50

(gdb)whatisbus

type=chanint

Tolettheprogramcontinueitsexecutionuntilthenextbreakpointentertheccommand

(gdb)c

Continuing

count0

[NewLWP3303]

[SwitchingtoLWP3303]

Breakpoint1mainmain()athomexiemengjungdbfilego23

23fmtPrintln(countcount)

(gdb)c

Continuing

count1

[SwitchingtoLWP3302]

Breakpoint1mainmain()athomexiemengjungdbfilego23

23fmtPrintln(countcount)

AftereachcthecodewillexecuteoncethenjumptothenextiterationoftheforloopItwillofcoursecontinuetoprintouttheappropriateinformation

LetssaythatyouneedtochangethecontextvariablesinthecurrentexecutionenvironmentskiptheprocessthencontinuetothenextstepYoucandosobyfirstusinginfolocalstogetthevariablestatesthenthesetvariablecommandtomodifythem

DebuggingbyusingGDB

250

(gdb)infolocals

count=2

bus=0xf840001a50

(gdb)setvariablecount=9

(gdb)infolocals

count=9

bus=0xf840001a50

(gdb)c

Continuing

count9

[SwitchingtoLWP3302]

Breakpoint1mainmain()athomexiemengjungdbfilego23

23fmtPrintln(countcount)

FinallywhilerunningtheprogramcreatesanumberofgoroutinesWecanseewhateachgoroutineisdoingusinginfogoroutines

(gdb)infogoroutines

1runningruntimegosched

2syscallruntimeentersyscall

3waitingruntimegosched

4runnableruntimegosched

(gdb)goroutine1bt

00x000000000040e33binruntimegosched()athomexiemengjungosrcpkgruntimeprocc927

10x0000000000403091inruntimechanrecv(c=voidep=voidselected=voidreceived=void)

athomexiemengjungosrcpkgruntimechanc327

20x000000000040316finruntimechanrecv2(t=voidc=void)

athomexiemengjungosrcpkgruntimechanc420

30x0000000000400d6finmainmain()athomexiemengjungdbfilego22

40x000000000040d0c7inruntimemain()athomexiemengjungosrcpkgruntimeprocc244

50x000000000040d16ainschedunlock()athomexiemengjungosrcpkgruntimeprocc267

60x0000000000000000in()

FromthegoroutinescommandwecanhaveabetterpictureofwhatGosruntimesystemisdoinginternallythecallingsequenceforeachfunctionisplainlydisplayed

SummaryInthissectionweintroducedsomebasiccommandsfromtheGDBdebuggerthatyoucanusetodebugyourGoapplicationsTheseincludedtherunprintinfosetvariablecontinuelistandbreakcommandsamongothersFromthebriefexamplesaboveIhopethatyouwillhaveabetterunderstandingofhowthedebuggingprocessworksinGousingtheGDBdebuggerIfyouwanttogetmoredebuggingtipspleaserefertotheGDBmanualonitsofficialwebsite

LinksDirectoryPrevioussectionErrorhandlingNextsectionWritetestcases

DebuggingbyusingGDB

251

113WritingtestcasesInthecourseofdevelopmentaveryimportantstepistotestourcodetoensureitsqualityandintegrityWeneedtomakesurethateveryfunctionreturnstheexpectedresultandthatourcodeperformsoptimallyWealreadyknowthatthefocusofunittestsistofindlogicalerrorsinthedesignorimplementationofprogramsTheyareusedtodetectandexposeproblemsincodeearlyonsothatwecanmoreeasilyfixthembeforetheygetoutofhandWealsoknowthatperformancetestsareconductedforthepurposeofoptimizingourcodesothatitisstableunderloadandcanmaintainahighlevelofconcurrencyInthissectionwelltakealookatsomecommonlyaskedquestionsabouthowunitandperformancetestsareimplementedinGo

TheGolanguagecomeswithalightweighttestingframeworkcalledtestingandwecanusethegotestcommandtoexecuteunitandperformancetestsGostestingframeworkworkssimilarlytotestingframeworksinotherlanguagesYoucandevelopallsortsoftestsuiteswiththemwhichmayincludetestsforunittestesbenchmarkingstresstestsetcLetslearnabouttestinginGostepbystep

HowtowritetestcasesSincethegotestcommandcanonlybeexecutedinadirectorycontainingallcorrespondingfileswearegoingtocreateanewprojectdirectorygotestsothatallofourcodeandtestcodeareinthesamedirectory

Letsgoaheadandcreatetwofilesinthedirectorycalledgotestgoandgotest_testgo

1 GotestgoThisfiledeclaresourpackagenameandhasafunctionthatperformsadivisionoperation

packagegotest

import(

errors

)

funcDivision(abfloat64)(float64error)

ifb==0

return0errorsNew(Divisorcannotbe0)

returnabnil

2 Gotest_testgoThisisourunittestfileKeepinmindthefollowingprinciplesfortestfiles

3 Filenamesmustendin_testgosothatgotestcanfindandexecutetheappropriatecode

4 Youhavetoimportthetestingpackage5 AlltestcasefunctionsbeginwithTest6 Testcasesfollowthesourcecodeorder7 TestfunctionsoftheformTestXxx()takeatestingTargumentwecanusethistypetorecorderrorsortogetthe

testingstatus8 InfunctionsoftheformfuncTestXxx(ttestingT)theXxxsectioncanbeanyalphanumericcombinationbutthe

firstlettercannotbealowercaseletter[az]ForexampleTestintdivwouldbeaninvalidfunctionname9 BycallingoneoftheErrorErrorfFailNowFatalorFatalIfmethodsoftestingTonourtestingfunctions

wecanfailthetestInadditionwecancalltheLogmethodoftestingTtorecordtheinformationintheerrorlog

Hereisourtestcode

Writetestcases

252

packagegotest

import(

testing

)

funcTest_Division_1(ttestingT)

tryaunittestonfunction

ifie=Division(62)i=3||e=nil

Ifitisnotasexpectedthenthetesthasfailed

tError(divisionfunctiontestsdonotpass)

else

recordtheexpectedinformation

tLog(firsttestpassed)

funcTest_Division_2(ttestingT)

tError(justdoesnotpass)

Whenexecutinggotestintheprojectdirectoryitwilldisplaythefollowinginformation

---FAILTest_Division_2(000seconds)

gotest_testgo16isnotpassed

FAIL

exitstatus1

FAILgotest0013s

Wecanseefromthisresultthatthesecondtestfunctiondoesnotpasssincewewroteinadead-endusingtErrorButwhatabouttheperformanceofourfirsttestfunctionBydefaultexecutinggotestdoesnotdisplaytestresultsWeneedtosupplytheverboseargument-vlikegotest-vtodisplaythefollowingoutput

===RUNTest_Division_1

---PASSTest_Division_1(000seconds)

gotest_testgo11firsttestpassed

===RUNTest_Division_2

---FAILTest_Division_2(000seconds)

gotest_testgo16isnotpassed

FAIL

exitstatus1

FAILgotest0012s

TheaboveoutputshowsindetailtheresultsofourtestWeseethatthetestfunction1Test_Division_1passesandthetestfunction2Test_Division_2failsfinallyconcludingthatourtestsuitedoesnotpassNextwemodifythetestfunction2withthefollowingcode

funcTest_Division_2(ttestingT)

tryaunittestonfunction

if_e=Division(60)e==nil

Ifitisnotasexpectedthentheerror

tError(Divisiondidnotworkasexpected)

else

recordsomeoftheinformationyouexpecttorecord

tLog(onetestpassede)

Weexecutegotest-vonceagainThefollowinginformationshouldnowbedisplayed-thetestsuitehaspassed~

Writetestcases

253

===RUNTest_Division_1

---PASSTest_Division_1(000seconds)

gotest_testgo11firsttestpassed

===RUNTest_Division_2

---PASSTest_Division_2(000seconds)

gotest_testgo20onetestpasseddivisorcannotbe0

PASS

okgotest0013s

HowtowritestresstestsStresstestingisusedtodetectfunctionperformanceandbearssomeresemblancetounittesting(whichwewillnotgetintohere)howeverweneedtopayattentiontothefollowingpoints

StresstestsmustfollowthefollowingformatwhereXXXcanbeanyalphanumericcombinationanditsfirstlettercannotbealowercaseletter

funcBenchmarkXXX(btestingB)

BydefaultGotestdoesnotperformfunctionstresstestsIfyouwanttoperformstresstestsyouneedtosettheflag-testbenchwiththeformat-testbench=test_name_regexForinstancetorunallstresstestsinyoursuiteyouwouldrungotest-testbench=

InyourstresstestspleaseremembertousetestingBNanyloopbodiessothatthetestscanberunproperlyAsbeforetestfilenamesmustendin_testgo

Herewecreateastresstestfilecalledwebbench_testgo

packagegotest

import(

testing

)

funcBenchmark_Division(btestingB)

fori=0iltbNi++usebNforlooping

Division(45)

funcBenchmark_TimeConsumingFunction(btestingB)

bStopTimer()callthefunctiontostopthestresstesttimecount

Dosomeinitializationworksuchasreadingfiledatadatabaseconnectionsandthelike

Sothatourbenchmarksreflecttheperformanceofthefunctionitself

bStartTimer()re-starttime

fori=0iltbNi++

Division(45)

Wethenexecutethegotest-filewebbench_testgo-testbench=commandwhichoutputsthefollowingresults

PASS

Benchmark_Division500000000776nsop

Benchmark_TimeConsumingFunction500000000780nsop

okgotest9364s

TheaboveresultsshowthatwedidnotperformanyofourTestXXXunittestfunctionsandinsteadonlyperformedourBenchmarkXXXtests(whichisexactlyasexpected)ThefirstBenchmark_DivisiontestshowsthatourDivision()functionexecuted500milliontimeswithanaverageexecutiontimeof776nsThesecondBenchmark_TimeConsumingFunctionshows

Writetestcases

254

thatourTmeConsumingFunctionexecuted500milliontimeswithanaverageexecutiontimeof780nsFinallyitoutputsthetotalexecutiontimeofourtestsuite

SummaryFromourbriefencounterwithunitandstresstestinginGowecanseethatthetestingpackageisverylightweightyetpackedwithusefulutilitiesWesawthatwritingunitandstresstestscanbeverysimpleandrunningthemcanbeeveneasierwithGosbuilt-ingotestcommandEverytimewemodifyourcodewecansimplyrungotesttobeginregressiontesting

LinksDirectoryPrevioussectionDebuggingusingGDBNextsectionSummary

Writetestcases

255

114SummaryOverthecourseofthelastthreesectionsweveintroducedhowtohandleerrorsinGofirstlookingatgooderrorhandlingpracticesanddesignthenlearninghowtousetheGDBdebuggereffectivelyWesawthatwithGDBwecanperformsingle-stepdebuggingviewandmodifyourprogramvariablesduringexecutionandprintouttherelevantprocessinformationFinallywedescribedhowtouseGosbuilt-intestingframeworktowriteunitandstresstestsProperlyusingthisframeworkallowsustoeasilymakeanyfuturechangestoourcodeandperformthenecessaryregressiontestingGoodwebapplicationsmusthavegooderrorhandlingandpartofthatishavingreadableerrorsanderrorhandlingmechanismswhichcanscaleinapredictablemannerUsingthetoolsmentionedaboveaswellaswritinghighqualityandthoroughunitandstresstestswecanhavepeaceofmindknowingthatonceourapplicationsarelivetheycanmaintainoptimalperformanceandrunasexpected

LinksDirectoryPrevioussectionWritetestcasesNextchapterDeploymentandmaintenance

Summary

256

12DeploymentandmaintenanceSofarwevecoveredthebasicsofdevelopingdebuggingandtestingwebapplicationsinGoAsisoftensaidhoweverthelast10ofdevelopmenttakes90ofthetimeInthischapterwewillbeemphasizingthislast10ofapplicationdevelopmentinordertotrulycraftreliableandhighqualitywebapplicationsInthefirstsectionwewillexaminehowproductionservicesgeneratelogsandtheprocessofloggingitselfThesecondsectionwilldescribedealingwithruntimeerrorsandhowtomanagethemwhentheyoccursothattheimpactonendusersisminimizedInthethirdsectionwetacklethesubjectofdeployingstandaloneGoprogramswhichcanbetrickyatfirstAsyoumightknowGoprogramscannotbewrittenwithdaemonslikeyouwouldwithalanguagesuchasCWelldiscusshowbackgroundprocessesaretypicallymanagedinGoFinallyourfourthandlastsectionwilladdresstheprocessofbackingupandrecoveringapplicationdatainGoWelltakealookatsometechniquesforensuringthatintheeventofacrashwewillbeabletomaintaintheintegrityofourdata

LinksDirectoryPreviouschapterChapter11summaryNextsectionLogs

Deploymentandmaintenance

257

121LogsWewanttobuildwebapplicationsthatcankeeptrackofeventswhichhaveoccurredthroughoutexecutioncombiningthemallintooneplaceforeasyaccesslateronwhenweinevitablyneedtoperformdebuggingoroptimizationtasksGoprovidesasimplelogpackagewhichwecanusetohelpusimplementsimpleloggingfunctionalityLogscanbeprintedusingGosfmtpackagecalledinsideerrorhandlingfunctionsforgeneralerrorloggingGosstandardpackageonlycontainsbasicfunctionalityforlogginghoweverTherearemanythirdpartyloggingtoolsthatwecanusetosupplementitifyourneedsaremoresophisticated(toolssimilartolog4jandlog4cppifyouveeverhadtodealwithlogginginJavaorC++)Apopularandfullyfeaturedopen-sourceloggingtoolinGoistheseelogloggingframeworkLetstakealookathowwecanuseseelogtoperformlogginginourGoapplications

IntroductiontoseelogSeelogisaloggingframeworkforGothatprovidessomesimplefunctionalityforimplementingloggingtaskssuchasfilteringandformattingItsmainfeaturesareasfollows

DynamicconfigurationviaXMLyoucanloadconfigurationparametersdynamicallywithoutrecompilingyourprogramSupportshotupdatestheabilitytodynamicallychangetheconfigurationwithouttheneedtorestarttheapplicationSupportsmulti-outputstreamsthatcansimultaneouslypipelogoutputtomultiplestreamssuchasafilestreamnetworkflowetcSupportfordifferentlogoutputs

CommandlineoutputFileOutputCachedoutputSupportlogrotateSMTPMail

TheaboveisonlyapartiallistofseelogsfeaturesTofullytakeadvantageofallofseelogsfunctionalityhavealookatitsofficialwikiwhichthoroughlydocumentswhatyoucandowithitLetsseehowweduseseeloginourprojects

Firstinstallseelog

goget-ugithubcomcihubseelog

Thenletswriteasimpleexample

packagemain

importloggithubcomcihubseelog

funcmain()

deferlogFlush()

logInfo(HellofromSeelog)

CompileandruntheprogramIfyouseeaHellofromseeloginyourapplicationlogseeloghasbeensuccessfullyinstalledandisrunningoperatingnormally

CustomlogprocessingwithseelogSeelogsupportscustomlogprocessingThefollowingcodesnippetisbasedontheitscustomlogprocessingpartofitspackage

Logs

258

packagelogs

import(

errors

fmt

seeloggithubcomcihubseelog

io

)

varLoggerseelogLoggerInterface

funcloadAppConfig()

appConfig=`

ltseelogminlevel=warngt

ltoutputsformatid=commongt

ltrollingfiletype=sizefilename=datalogsrolllogmaxsize=100000maxrolls=5gt

ltfilterlevels=criticalgt

ltfilepath=datalogscriticallogformatid=criticalgt

ltsmtpformatid=criticalemailsenderaddress=astaxiegmailcomsendername=ShortUrlAPIhostname=smtp

gmailcomhostport=587username=mailusernamepassword=mailpasswordgt

ltrecipientaddress=xiemengjungmailcomgt

ltsmtpgt

ltfiltergt

ltoutputsgt

ltformatsgt

ltformatid=commonformat=DateTime[LEV]Msgngt

ltformatid=criticalformat=FileFullPathFuncMsgngt

ltformatid=criticalemailformat=CriticalerroronourservernTimeDateRelFileFuncMsgnSent

bySeeloggt

ltformatsgt

ltseeloggt

`

loggererr=seelogLoggerFromConfigAsBytes([]byte(appConfig))

iferr=nil

fmtPrintln(err)

return

UseLogger(logger)

funcinit()

DisableLog()

loadAppConfig()

DisableLogdisablesalllibrarylogoutput

funcDisableLog()

Logger=seelogDisabled

UseLoggerusesaspecifiedseelogLoggerInterfacetooutputlibrarylog

UsethisfuncifyouareusingSeelogloggingsysteminyourapp

funcUseLogger(newLoggerseelogLoggerInterface)

Logger=newLogger

Theaboveimplementsthethreemainfunctions

DisableLog

InitializesaglobalvariableLoggerwithseelogdisabledmainlyinordertopreventtheloggerfrombeingrepeatedlyinitialized

LoadAppConfig

InitializestheconfigurationsettingsofseelogaccordingtoaconfigurationfileInourexamplewearereadingtheconfigurationfromanin-memorystringbutofcourseyoucanreaditfromanXMLfilealsoInsidetheconfigurationwesetupthefollowingparameters

Logs

259

Seelog

TheminlevelparameterisoptionalIfconfiguredlogginglevelswhicharegreaterthanorequaltothespecifiedlevelwillberecordedTheoptionalmaxlevelparameterissimilarlyusedtoconfigurethemaximumloggingleveldesired

Outputs

ConfigurestheoutputdestinationInourparticularcasewechannelourloggingdataintotwooutputdestinationsThefirstisarollinglogfilewherewecontinuouslysavethemostrecentwindowofloggingdataTheseconddestinationisafilteredlogwhichrecordsonlycriticallevelerrorsWeadditionallyconfigureittoalertusviaemailwhenthesetypesoferrorsoccur

Formats

DefinesthevariousloggingformatsYoucanusecustomformattingorpredefinedformatting-afulllistofpredefinedformatscanbefoundonseelogswiki

UseLogger

Setthecurrentloggerasourlogprocessor

AbovewevedefinedandconfiguredacustomlogprocessingpackageThefollowingcodedemonstrateshowweduseit

packagemain

import(

nethttp

projectlogs

projectconfigs

projectroutes

)

funcmain()

addr_=configsMainConfigString(serveraddr)

logsLoggerInfo(Startserveratvaddr)

err=httpListenAndServe(addrroutesNewMux())

logsLoggerCritical(Servererrverr)

EmailnotificationsTheaboveexampleexplainshowtosetupemailnotificationswithseelogAsyoucanseeweusedthefollowingsmtpconfiguration

ltsmtpformatid=criticalemailsenderaddress=astaxiegmailcomsendername=ShortUrlAPIhostname=smtpgmailcom

hostport=587username=mailusernamepassword=mailpasswordgt

ltrecipientaddress=xiemengjungmailcomgt

ltsmtpgt

WesettheformatofouralertmessagesthroughthecriticalemailconfigurationprovidingourmailserverparameterstobeabletoreceivethemWecanalsoconfigureournotifiertosendoutalertstoadditionalusersusingtherecipientconfigurationItsasimplematterofaddingonelineforeachadditionalrecipient

Totestwhetherornotthiscodeisworkingproperlyyoucanaddafakecriticalmessagetoyourapplicationlikeso

logsLoggerCritical(testCriticalmessage)

Dontforgettodeleteitonceyouredonetestingorwhenyourapplicationgoesliveyourinboxmaybefloodedwithemailnotifications

NowwheneverourapplicationlogsacriticalmessagewhileonlineyouandyourspecifiedrecipientswillreceiveanotificationemailYouandyourteamcanthenprocessandremedythesituationinatimelymanner

Logs

260

UsingapplicationlogsWhenitcomestologseachapplicationsuse-casemayvaryForexamplesomepeopleuselogsfordataanalysispurposesothersforperformanceoptimizationSomelogsareusedtoanalyzeuserbehaviorandhowpeopleinteractwithyourwebsiteOfcoursetherearelogswhicharesimplyusedtorecordapplicationeventsasauxiliarydataforfindingproblems

AsanexampleletssayweneedtotrackuserattemptsatloggingintooursystemThisinvolvesrecordingbothsuccessfulandunsuccessfulloginattemptsintoourlogWedtypicallyusetheInfologleveltorecordthesetypesofeventsratherthansomethingmoreseriouslikewarnIfyoureusingalinux-typesystemyoucanconvenientlyviewallunsuccessfulloginattemptsfromthelogusingthegrepcommandlikeso

catdatalogsrolllog|grepfailedlogin

2012-12-11111200WARNfailedloginattemptfrom11223344usernamepassword

ThiswaywecaneasilyfindtheappropriateinformationinourapplicationlogwhichcanhelpustoperformstatisticalanalysisifneededInadditionwealsoneedtoconsiderthesizeoflogsgeneratedbyhigh-trafficwebapplicationsTheselogscansometimesgrowunpredictablyToresolvethisissuewecansetseelogupwiththelogrotateconfigurationtoensurethatsinglelogfilesdonotconsumeexcessivediskspace

SummaryInthissectionwevelearnedthebasicsofseelogandhowtobuildacustomloggingsystemwithitWesawthatwecaneasilyconfigureseelogintoaspowerfulalogprocessingsystemasweneedusingittosupplyuswithreliablesourcesofdataforanalysisThroughloganalysiswecanoptimizeoursystemandeasilylocatethesourcesofproblemswhentheyariseInadditionseelogshipswithvariousdefaultloglevelsWecanusetheminlevelconfigurationinconjunctionwithalogleveltoeasilysetuptestsorsendautomatednotificationmessages

LinksDirectoryPrevioussectionDeploymentandmaintenanceNextsectionErrorsandcrashes

Logs

261

122ErrorsandcrashesOnceourwebapplicationsgoliveitslikelythattherewillbesomeunforeseenerrorsAfewexampleofcommonerrorsthatmayoccurinthecourseofyourapplicationsdailyoperationsarelistedbelow

DatabaseErrorserrorsrelatedtoaccessingthedatabaseserverorstoreddataThefollowingaresomedatabaseerrorswhichyoumayencounter

ConnectionErrorsindicatesthataconnectiontothenetworkdatabaseservercouldnotbeestablishedasuppliedusernameorpasswordisincorrectorthatthedatabasedoesnotexist

QueryErrorstheillegalorincorrectuseofanSQLquerycanraiseanerrorsuchasthisThesetypesoferrorscanbeavoidedthroughrigoroustestingDataErrorsdatabaseconstraintviolationsuchasattemptingtoinsertafieldwithaduplicateprimarykeyThesetypesoferrorscanalsobeavoidedthroughrigoroustestingbeforedeployingyourapplicationintoaproductionenvironmentApplicationRuntimeErrorsThesetypesoferrorsvarygreatlycoveringalmostallerrorcodeswhichmayappearduringruntimePossibleapplicationerrorsareasfollows

FilesystemandpermissionerrorswhentheapplicationattemptstoreadafilewhichdoesnotexistordoesnothavepermissiontoreadorwhenitattemptstowritetoafilewhichitisnotallowedtowritetoerrorsofthiscategorywilloccurAfilesystemerrorwillalsooccurifanapplicationreadsafilewithanunexpectedformatforinstanceaconfigurationfilethatshouldbeintheINIformatbutisinsteadstructuredasJSON

Third-partyapplicationerrorsTheseerrorsoccurinapplicationswhichinterfacewithotherthird-partyapplicationsorservicesForinstanceifanapplicationpublishestweetsaftermakingcallstoTwittersAPIitsobviousthatTwittersservicesmustbeupandrunninginorderforourapplicationtocompleteitstaskWemustalsoensurethatwesupplythesethird-partyinterfaceswiththeappropriateparametersinourcallsorelsetheywillalsoreturnerrors

HTTPerrorsTheseerrorsvarygreatlyandarebasedonuserrequestsThemostcommonisthe404NotFounderrorwhichariseswhenusersattempttoaccessnon-existentresourcesinyourapplicationAnothercommonHTTPerroristhe401Unauthorizederror(authenticationisrequiredtoaccesstherequestedresource)403Forbiddenerror(usersarealtogetherrefusedaccesstothisresource)and503ServiceUnavailableerrors(indicativeofaninternalprogramerror)

OperatingsystemerrorsThesesortsoferrorsoccurattheoperatingsystemlayerandcanhappenwhenoperatingsystemresourcesareover-allocatedleadingtocrashesandsysteminstabilityAnothercommonoccurrenceatthisleveliswhentheoperatingsystemdiskgetsfilledtocapacitymakingitimpossibletowritetoThisnaturallyproducesinmanyerrorsNetworkerrorsnetworkerrorstypicallycomeintwoflavorsoneiswhenusersissuerequeststotheapplicationandthenetworkdisconnectsthusdisruptingitsprocessingandresponsephaseTheseerrorsdonotcausetheapplicationtocrashbutcanaffectuseraccesstothewebsitetheotheriswhenapplicationsattemptstoreaddatafromdisconnectednetworkscausingreadfailuresJudicioustestingisparticularlyimportantwhenmakingnetworkcallstoavoidsuchproblemswhichcancauseyourapplicationtocrash

ErrorhandlinggoalsBeforeimplementingerrorhandlingwemustbeclearaboutwhatgoalswearetryingtoachieveIngeneralerrorhandlingsystemsshouldaccomplishthefollowing

UsererrornotificationswhensystemorusererrorsoccurcausingcurrentuserrequeststofailtocompleteaffectedusersshouldbenotifiedoftheproblemForexampleforerrorscausebyuserrequestsweshowaunifiederrorpage(404html)Whenasystemerroroccursweuseacustomerrorpagetoprovidefeedbackforusersastowhathappened-forinstancethatthesystemistemporarilyunavailable(errorhtml)Logerrorswhensystemerrorsoccur(ingeneralwhenfunctionsreturnnon-nilerrorvariables)aloggingsystemsuch

Errorsandcrashes

262

astheonedescribedearliershouldbeusedtorecordtheeventintoalogfilefileIfitisafatalerrorthesystemadministratorshouldalsobenotifiedviae-mailIngeneralhowevermost404errorsdonotwarrantthesendingofemailnotificationsrecordingtheeventintoalogforlaterscrutinyisoftenadequateRollbackthecurrentrequestoperationIfauserrequestcausesaservererrorthenweneedtobeabletorollbackthecurrentoperationLetslookatanexampleasystemsavesauser-submittedformtoitsdatabasethensubmitsthisdatatoathird-partyserverHoweverthethird-partyserverdisconnectsandweareunabletoestablishaconnectionwithitwhichresultsinanerrorInthiscasethepreviouslystoredformdatashouldbedeletedfromthedatabase(voidshouldbeinformed)andtheapplicationshouldinformtheuserofthesystemerrorEnsurethattheapplicationcanrecoverfromerrorsweknowthatitsdifficultforanyprogramtoguarantee100uptimesoweneedtomakeprovisionforscenarioswhereourprogramsfailForinstanceifourprogramcrasheswefirstneedtologtheerrornotifytherelevantpartiesinvolvedthenimmediatelygettheprogramupandrunningagainThiswayourapplicationcancontinuetoprovideserviceswhileasystemadministratorinvestigatesandfixesthecauseoftheproblem

HowtohandleerrorsInchapter11weaddressedtheprocessoferrorhandlinganddesignusingsomeexamplesLetsgointotheseexamplesinabitmoredetailandseesomeothererrorhandlingscenarios

Notifytheuseroferrors

Whenanerroroccurswecanpresenttheuseraccessingthepagewithtwokindsoferrorspages404htmlanderrorhtmlHereisanexampleofwhatthesourcecodeofanerrorpagemightlooklike

lthtmllang=engt

ltheadgt

ltmetahttp-equiv=Content-Typecontent=texthtmlcharset=utf-8gt

lttitlegtPageNotFound

lttitlegt

ltmetaname=viewportcontent=width=device-widthinitial-scale=10gt

ltheadgt

ltbodygt

ltdivclass=containergt

ltdivclass=rowgt

ltdivclass=span10gt

ltdivclass=hero-unitgt

lth1gt404lth1gt

ltpgtErrorInfoltpgt

ltdivgt

ltdivgt

lt--span--gt

ltdivgt

ltdivgt

ltbodygt

lthtmlgt

Anotherexample

Errorsandcrashes

263

lthtmllang=engt

ltheadgt

ltmetahttp-equiv=Content-Typecontent=texthtmlcharset=utf-8gt

lttitlegtsystemerrorpage

lttitlegt

ltmetaname=viewportcontent=width=device-widthinitial-scale=10gt

ltheadgt

ltbodygt

ltdivclass=containergt

ltdivclass=rowgt

ltdivclass=span10gt

ltdivclass=hero-unitgt

lth1gtsystemistemporarilyunavailablelth1gt

ltpgtErrorInfoltpgt

ltdivgt

ltdivgt

lt--span--gt

ltdivgt

ltdivgt

ltbodygt

lthtmlgt

404error-handlinglogicintheoccurrenceofasystemerror

func(pMyMux)ServeHTTP(whttpResponseWriterrhttpRequest)

ifrURLPath==

sayhelloName(wr)

return

NotFound404(wr)

return

funcNotFound404(whttpResponseWriterrhttpRequest)

logError(pagenotfound)errorlogging

t_=tParseFiles(tmpl404htmlnil)parsethetemplatefile

ErrorInfo=FilenotfoundGetthecurrentuserinformation

tExecute(wErrorInfo)executethetemplatemergeroperation

funcSystemError(whttpResponseWriterrhttpRequest)

logCritical(SystemError)systemerrortriggeredCriticalthenloggingwillnotonly

sendamessage

t_=tParseFiles(tmplerrorhtmlnil)parsethetemplatefile

ErrorInfo=systemistemporarilyunavailableGetthecurrentuserinformation

tExecute(wErrorInfo)executethetemplatemergeroperation

HowtohandleexceptionsWeknowthatmanyotherlanguageshavetrycatchkeywordsusedtocapturetheunusualcircumstancesbutinfactmanyerrorscanbeexpectedtooccurwithouttheneedforexceptionhandlingandcanbeinsteadtreatedasanerrorsItsforthisreasonthatGofunctionsreturnerrorsbydesignForexampleifafileisnotfoundorifosOpenreturnsanerrorthesefunctionswillnotpanicasanotherexampleifanetworkconnectiongetsdisconnectedduringadatawriteoperationthenetConnfamilyofWritefunctionswillreturnerrorsinsteadofpanickingTheseerrorstatesaretobeexpectedinmostapplicationsandGoparticularlymakesitexplicitwhenoperationsmightfailbyreturningerrorvariablesLookingattheexampleabovewecanclearlyseetheerrorsthatcanbeexpectedtooccur

Errorsandcrashes

264

TherearehowevercaseswherepanicshouldbeusedForinstanceinoperationswherefailureisalmostimpossibleorincertainsituationswherethereisnowaytoreturnanerrorandtheoperationcannotcontinuepanicshouldbeusedTakeforexampleaprogramthattriestoobtainthevalueofanarrayatx[j]buttheindexjisoutofboundsThispartofthecodewillcausetheprogramtopanicaswillothercriticalunexpectederrorsofthisnatureBydefaultpanickingwillkillofftheoffendingprocess(goroutine)allowingthecodewhichdispatchedthegoroutineanopportunitytorecoverfromtheerrorThiswaythefunctioninwhichtheerroroccurredaswellasallsubsequentcodeafteritwillnotcontinuetoexecuteGospanicwasdeliberatelydesignedwiththisbehaviorinmindwhichisdifferentthantypicalerrorhandlingpanicisreallyjustexceptionhandlingIntheexamplebelowweexpectthatUser[UID]willreturnausernamefromtheUserarraybuttheUIDthatweuseisoutofboundsandthrowsanexceptionIfwedonothavearecoverymechanismtodealwiththisimmediatelytheprocesswillbekilledandthepanicwillpropagateupthestackuntilourprogramfinallycrashesInorderforourapplicationtoberobustandresilienttothesekindsofruntimeerrorsweneedtoimplementrecoverymechanismsincertainplaces

funcGetUser(uidint)(usernamestring)

deferfunc()

ifx=recover()x=nil

username=

()

username=User[uid]

return

TheabovedescribesthedifferencesbetweenerrorsandexceptionsSowhenitcomesdowntodevelopingourGoapplicationswhendoweuseoneortheotherTherulesaresimpleifyoudefineafunctionthatyouanticipatemightfailthenreturnanerrorvariableWhencallinganotherpackagesfunctionifitisimplementedwellthereshouldbenoneedtoworrythatitwillpanicunlessatrueexceptionhasoccurred(whetherrecoverylogichasbeenimplementedornot)PanicandrecovershouldonlybeusedinternallyinsidepackagestodealwithspecialcaseswherethestateoftheprogramcannotbeguaranteedorwhenaprogrammerserrorhasoccurredExternallyfacingAPIsshouldexplicitlyreturnerrorvalues

SummaryThisissectionsummarizeshowwebapplicationsshouldhandlevariouserrorssuchasnetworkdatabaseandoperatingsystemerrorsamongothersWeveoutlineseveraltechniquestoeffectivelydealwithruntimeerrorssuchasdisplayinguser-friendlyerrornotificationsrollingbackactionsloggingandalertingsystemadministratorsFinallyweexplainedhowtocorrectlyhandleerrorsandexceptionsTheconceptofanerrorisoftenconfusedwiththatofanexceptionhoweverinGothereisacleardistinctionbetweenthetwoForthisreasonwevediscussedtheprinciplesofprocessingbotherrorsandexceptionsinwebapplications

LinksDirectoryPrevioussectionLogsNextsectionDeployment

Errorsandcrashes

265

123DeploymentWhenourwebapplicationisfinallyproductionreadywhatarethestepsnecessarytogetitdeployedInGoanexecutablefileencapsulatingourapplicationiscreatedafterwecompileourprogramsProgramswritteninCcanrunperfectlyasbackgrounddaemonprocesseshoweverGodoesnotyethavenativesupportfordaemonsThegoodnewsisthatwecanusethirdpartytoolstohelpusmanagethedeploymentofourGoapplicationsexamplesofwhichareSupervisordupstartanddaemontoolsamongothersThissectionwillintroduceyoutosomebasicsoftheSupervisordprocesscontrolsystem

DaemonsCurrentlyGoprogramscannotberunasdaemonprocesses(foradditionalinformationseetheopenissueongithubhere)ItsdifficulttoforkexistingthreadsinGobecausethereisnowayofensuringaconsistentstateinallthreadsthathavebeenused

Wecanhoweverseemanyattemptsatimplementingdaemonsonlinesuchasinthetwofollowingways

MarGooneimplementationoftheconceptofusingCommandtodeployapplicationsIfyoureallywanttodaemonizeyourapplicationsitisrecommendedtousecodesimilartothefollowing

d=flagBool(dfalseWhetherornottolaunchinthebackground(likea

daemon))

ifd

cmd=execCommand(osArgs[0]

-close-fds

-addraddr

-callcall

)

serrerr=cmdStderrPipe()

iferr=nil

logFatalln(err)

err=cmdStart()

iferr=nil

logFatalln(err)

serr=ioutilReadAll(serr)

s=bytesTrimSpace(s)

ifbytesHasPrefix(s[]byte(addr))

fmtPrintln(string(s))

cmdProcessRelease()

else

logPrintf(unexpectedresponsefromMarGo`s`error`v`nserr)

cmdProcessKill()

Anothersolutionistousesyscallbutthissolutionisnotperfect

Deployment

266

packagemain

import(

log

os

syscall

)

funcdaemon(nochdirnocloseint)int

varretret2uintptr

varerruintptr

darwin=syscallOS==darwin

alreadyadaemon

ifsyscallGetppid()==1

return0

forkofftheparentprocess

retret2err=syscallRawSyscall(syscallSYS_FORK000)

iferr=0

return-1

failure

ifret2lt0

osExit(-1)

handleexceptionfordarwin

ifdarwinampampret2==1

ret=0

ifwegotagoodPIDthenwecallexittheparentprocess

ifretgt0

osExit(0)

Changethefilemodemask

_=syscallUmask(0)

createanewSIDforthechildprocess

s_rets_errno=syscallSetsid()

ifs_errno=0

logPrintf(ErrorsyscallSetsiderrnods_errno)

ifs_retlt0

return-1

ifnochdir==0

osChdir()

ifnoclose==0

fe=osOpenFile(devnullosO_RDWR0)

ife==nil

fd=fFd()

syscallDup2(fdosStdinFd())

syscallDup2(fdosStdoutFd())

syscallDup2(fdosStderrFd())

return0

Deployment

267

WhilethetwosolutionsaboveimplementdaemonizationinGoIstillcannotrecommendthatyouuseeithermethodssincethereisnoofficialsupportfordaemonsinGoNotwithstandingthisfactthefirstoptionisthemorefeasibleoneandiscurrentlybeingusedbysomewell-knownopensourceprojectslikeskynetforimplementingdaemons

SupervisordAbovewevelookedattwoschemesthatarecommonlyusedtoimplementdaemonsinGohoweverbothmethodslackofficialsupportSoitsrecommendedthatyouuseathird-partytooltomanageapplicationdeploymentHerewetakealookattheSupervisordprojectimplementedinPythonwhichprovidesextensivetoolsforprocessmanagementSupervisordwillhelpyoutodaemonizeyourGoapplicationsalsoallowingyoutodothingslikestartshutdownandrestartyourapplicationswithsomesimplecommandsamongmanyotheractionsInadditionSupervisordmanagedprocessescanautomaticallyrestartprocesseswhichhavecrashedensuringthatprogramscanrecoverfromanyinterruptions

AsanasideIrecentlyfellintoacommonpitfallwhiletryingtodeployanapplicationusingSupervisordAllapplicationsdeployedusingSupervisordarebornoutoftheSupervisordparentprocessWhenyouchangeanoperatingsystemfiledescriptordontforgettocompletelyrestartSupervisord-simplyrestartingtheapplicationitismanagingwillnotsufficeWhenIfirstdeployedanapplicationwithSupervisordImodifiedthedefaultfiledescriptorfieldchangingthedefaultnumberfrom1024to100000andthenrestartingmyapplicationInrealitySupervisordcontinuedusingonly1024filedescriptorstomanageallofmyapplicationsprocessesUpondeployingmyapplicationtheloggerbeganreportingalackoffiledescriptorsItwasalongprocessfindingandfixingthismistakesobeware

InstallingSupervisord

Supervisordcaneasilybeinstalledusingsudoeasy_installsupervisorOfcoursethereisalsotheoptionofdirectlydownloadingitfromitsofficialwebsiteuncompressingitgoingintothefolderthenrunningsetuppyinstalltoinstallitmanually

Ifyouregoingtheeasy_installroutethenyouneedtofirstinstallsetuptools

GotohttppypipythonorgpypisetuptoolsfilesanddownloadtheappropriatefiledependingonyoursystemspythonversionEnterthedirectoryandexecuteshsetuptoolsxxxxeggWhenthenscriptisdoneyoullbeabletousetheeasy_installcommandtoinstallSupervisord

ConfiguringSupervisord

SupervisordsdefaultconfigurationfilepathisetcsupervisordconfandcanbemodifiedusingatexteditorThefollowingiswhatatypicalconfigurationfilemaylooklike

Deployment

268

etcsupervisordconf

[unix_http_server]

file=varrunsupervisordsock

chmod=0777

chown=rootroot

[inet_http_server]

Webmanagementinterfacesettings

port=9001

username=admin

password=yourpassword

[supervisorctl]

Mustunix_http_servermatchthesettingsinside

serverurl=unixvarrunsupervisordsock

[supervisord]

logfile=varlogsupervisordsupervisordlog(mainlogfiledefault$CWDsupervisordlog)

logfile_maxbytes=50MB(maxmainlogfilebytesb4rotationdefault50MB)

logfile_backups=10(numofmainlogfilerotationbackupsdefault10)

loglevel=info(logleveldefaultinfoothersdebugwarntrace)

pidfile=varrunsupervisordpid(supervisordpidfiledefaultsupervisordpid)

nodaemon=true(startinforegroundiftruedefaultfalse)

minfds=1024(minavailstartupfiledescriptorsdefault1024)

minprocs=200(minavailprocessdescriptorsdefault200)

user=root(defaultiscurrentuserrequiredifroot)

childlogdir=varlogsupervisord(AUTOchildlogdirdefault$TEMP)

[rpcinterfacesupervisor]

supervisorrpcinterface_factory=supervisorrpcinterfacemake_main_rpcinterface

Managetheconfigurationofasingleprocessyoucanaddmultipleprogram

[programblogdemon]

command=datablogblogdemon

autostart=true

startsecs=5

user=root

redirect_stderr=true

stdout_logfile=varlogsupervisordblogdemonlog

SupervisordmanagementAfterinstallationiscompletetwoSupervisordcommandsbecomeavailabletoyouonthecommandlinesupervisorandsupervisorctlThecommandsareasfollows

supervisordinitialstartuplaunchandprocessconfigurationmanagementsupervisorctlstopprogramxxxstoptheprogramxxxprocesswhereprogramxxxisavalueconfiguredinyoursupervisordconffileForinstanceifyouhavesomethinglike[programblogdemon]configuredyouwouldusethesupervisorctlstopblogdemoncommandtokilltheprocesssupervisorctlstartprogramxxxstarttheprogramxxxprocesssupervisorctlrestartprogramxxxrestarttheprogramxxxprocesssupervisorctlstopallstopallprocessesnotestartrestartstopwillnotloadthelatestconfigurationfilessupervisorctlreloadloadthelatestconfigurationfilelaunchthemandmanageallprocesseswiththenewconfiguration

SummaryInthissectionwedescribedhowtoimplementdaemonsinGoWelearnedthatGodoesnotnativelysupportdaemonsandthatweneedtousethird-partytoolstohelpusmanagethemOnesuchtoolistheSupervisordprocesscontrolsystemwhichwecanusetoeasilydeployandmanageourGoprograms

Links

Deployment

269

DirectoryPrevioussectionErrorsandcrashesNextsectionBackupandrecovery

Deployment

270

124BackupandrecoveryInthissectionwelldiscussanotheraspectofapplicationmanagementdatabackupandrecoveryonproductionserversWeoftenencountersituationswhereproductionserversdontbehaveasweexpectthemtoServernetworkoutagesharddrivemalfunctionsoperatingsystemcrashesandothersimilareventscancausedatabasestobecomeunavailableTheneedtorecoverfromthesetypesofeventshasledtotheemergenceofmanycoldstandbyhotstandbytoolsthatcanhelptofacilitatedisasterrecoveryremotelyInthissectionwellexplainhowtobackupdeployedapplicationsinadditiontobackingupandrestoringanyMySQLandRedisdatabasesyoumightbeusing

ApplicationBackupInmostclusterenvironmentswebapplicationsdonotneedtobebackedupsincetheyareactuallycopiesofcodefromourlocaldevelopmentenvironmentorfromaversioncontrolsystemInmanycaseshoweverweneedtobackupdatawhichhasbeensuppliedbytheusersofoursiteForinstancewhensitesrequireuserstouploadfilesweneedtobeabletobackupanyfilesthathavebeenuploadedbyuserstoourwebsiteThecurrentapproachforprovidingthiskindofredundancyistoutilizeso-calledcloudstoragewhereuserfilesandotherrelatedresourcesarepersistedintoahighlyavailablenetworkofserversIfoursystemcrashesaslongasuserdatahasbeenpersistedontothecloudwecanatleastbesurethatnodatawillbelost

ButwhataboutthecaseswherewedidnotbackupourdatatoacloudserviceorwherecloudstoragewasnotanoptionHowdowebackupdatafromourwebapplicationsthenHerewedescribeatoolcalledrsyncwhichcanbecommonlyfoundonunix-likesystemsRsyncisatoolwhichcanbeusedtosynchronizefilesresidingondifferentsystemsandaperfectuse-caseforthisfunctionalityistokeepourwebsitebackedup

NoteCwrsyncisanimplementationofrsyncfortheWindowsenvironment

RsyncinstallationYoucanfindthelatestversionofrsyncfromitsofficialwebsiteOfcoursebecausersyncisveryusefulsoftwaremanyLinuxdistributionswillalreadyhaveitinstalledbydefault

PackageInstallation

sudoapt-getinstallrsyncNotedebianubuntuandotheronlineinstallationmethods

yuminstallrsyncNoteFedoraRedhatCentOSandotheronlineinstallationmethods

rpm-ivhrsyncNoteFedoraRedhatCentOSandotherrpmpackageinstallationmethods

FortheotherLinuxdistributionspleaseusetheappropriatepackagemanagementmethodstoinstallitAlternativelyyoucanbuildityourselffromthesource

tarxvfrsync-xxxtargz

cdrsync-xxx

configure-prefix=usrmakemakeinstall

NoteIfwanttocompileandinstallthersyncfromitssourceyouhavetoinstallgcccompilertoolssuchasjob

NoteBeforeusingsourcepackagescompiledandinstalledyouhavetoinstallgcccompilertoolssuchasjob

RsyncConfiguration

Rsynccanbeconfiguredfromthreemainconfigurationfilesrsyncdconfwhichisthemainconfigurationfilersyncdsecretswhichholdspasswordsandrsyncdmotdwhichcontainsserverinformation

Backupandrecovery

271

Youcanrefertotheofficialdocumentationonrsyncswebsiteformoredetailedexplanationsbutherewewillsimplyintroducethebasicsofsettinguprsync

Startinganrsyncdaemonserver-side

usrbinrsync--daemon--config=etcrsyncdconf

the--daemonparameterisforrunningrsyncinservermodeMakethisthedefaultboot-timesettingbyjoiningittotherclocalfile

echorsync--daemongtgtetcrcdrclocal

SetupanrsyncusernameandpasswordmakingsurethatitsownedonlybyrootsothatlocalunauthorizedusersorexploitsdonothaveaccesstoitIfthesepermissionsarenotsetcorrectlyrsyncmaynotboot

echoYourUsernameYourPasswordgtetcrsyncdsecrets

chmod600etcrsyncdsecrets

Clientsynchronization

Clientscansynchronizeserverfileswiththefollowingcommand

rsync-avzP--delete--password-file=rsyncdsecretsusername1921681455wwwvarrsyncbackup

Letsbreakthisdownintoafewkeypoints

1 -avzParesomecommonoptionsUsersync--helptoreviewwhatthesedo2 --deletedeletesextraneousfilesonthereceivingsideForexampleiffilesaredeletedonthesendingsidethenext

timethetwomachinesaresynchronizedthereceivingsideswillautomaticallydeletethecorrespondingfiles3 --password-filespecifiesapasswordfileforaccessinganrsyncdaemonOntheclientsidethisistypicallythe

clientetcrsyncdsecretsfileandontheserversideitsetcrsyncdsecretsWhenusingsomethinglikeCrontoautomatersyncyouwontneedtomanuallyenterapassword

4 usernamespecifiestheusernametobeusedinconjunctionwiththeserver-sideetcrsyncdsecretspassword5 1921681455istheIPaddressoftheserver6 www(notethedoublecolons)specifiescontactinganrsyncdaemondirectlyviaTCPforsynchronizingthewww

moduleaccordingtotheserver-sideconfigurationslocatedinetcrsyncdconfWhenonlyasinglecolonisusedthersyncdaemonisnotcontacteddirectlyinsteadaremote-shellprogramsuchassshisusedasthetransport

InordertoperiodicallysynchronizefilesyoucansetupacrontabfilethatwillrunrsynccommandsasoftenasneededOfcourseuserscanvarythefrequencyofsynchronizationaccordingtohowcriticalitistokeepcertaindirectoriesorfilesuptodate

MySQLbackupMySQLdatabasesarestillthemainstreamgo-tosolutionformostwebapplicationsThetwomostcommonmethodsofbackingupMySQLdatabasesarehotbackupsandcoldbackupsHotbackupsareusuallyusedwithsystemssetupinamasterslaveconfigurationtobackuplivedata(themasterslavesynchronizationmodeistypicallyusedforseparatingdatabasereadwriteoperationsbutcanalsobeusedforbackinguplivedata)ThereisalotofinformationavailableonlinedetailingthevariouswaysonecanimplementthistypeofschemeForcoldbackupsincomingdataisnotbackedupinreal-timeasisthecasewithhotbackupsInsteaddatabackupsareperformedperiodicallyThiswayifthesystemfailstheintegrityofdatabeforeacertainperiodoftimecanstillbeguaranteedForinstanceincaseswhereasystemmalfunctioncausesdatatobelostandthemasterslavemodelisunabletoretrieveitcoldbackupscanbeusedforapartialrestoration

Ashellscriptisgenerallyusedtoimplementregularcoldbackupsofdatabasesexecutingsynchronizationtasksusingrsyncinanon-localmode

Backupandrecovery

272

ThefollowingisanexampleofabackupscriptthatperformsscheduledbackupsforaMySQLdatabaseWeusethemysqldumpprogramwhichallowsustoexportthedatabasetoafile

binbash

Configurationinformationmodifyitasneeded

mysql_user=USERMySQLbackupuser

mysql_password=PASSWORDMySQLbackupuserspassword

mysql_host=localhost

mysql_port=3306

mysql_charset=utf8MySQLencoding

backup_db_arr=(db1db2)Nameofthedatabasetobebackedupseparatingmultipledatabaseswihspaces(DB1

DB2db3)

backup_location=varwwwmysqlBackupdatastoragelocationpleasedonotendwithaandleaveitatitsdefau

ltfortheprogramtoautomaticallycreateafolder

expire_backup_delete=ONWhethertodeleteoutdatedbackupsornot

expire_days=3Settheexpirationtimeofbackupsindays(defaultstothreedays)thisisonlyvalidwhenthe`ex

pire_backup_delete`optionisON

Wedonotneedtomodifythefollowinginitialsettingsbelow

backup_time=`date+YmdHM`Definethebackuptimeformat

backup_Ymd=`date+Y-m-d`Definethebackupdirectorydatetime

backup_3ago=`date-d3daysago+Y-m-d`3daysbeforethedate

backup_dir=$backup_location$backup_YmdFullpathtothebackupfolder

welcome_msg=WelcometouseMySQLbackuptoolsGreeting

DeterminewhethertoMySQLisrunningifnotthenabortthebackup

mysql_ps=`ps-ef|grepmysql|wc-l`

mysql_listen=`netstat-an|grepLISTEN|grep$mysql_port|wc-l`

if[[$mysql_ps==0]-o[$mysql_listen==0]]then

echoERRORMySQLisnotrunningbackupaborted

exit

else

echo$welcome_msg

fi

Connecttothemysqldatabaseifaconnectioncannotbemadeabortthebackup

mysql-h$mysql_host-P$mysql_port-u$mysql_user-p$mysql_passwordltltend

usemysql

selecthostuserfromuserwhereuser=rootandhost=localhost

exit

end

flag=`echo$`

if[$flag=0]then

echoERRORCantconnectmysqlserverbackupaborted

exit

else

echoMySQLconnectokPleasewait

DeterminewhetherabackupdatabaseisdefinedornotIfsobeginthebackupifnotthenabort

if[$backup_db_arr=]then

dbnames=$(cut-d-f1-5$backup_database)

echoarris($backup_db_arr[])

fordbnamein$backup_db_arr[]

do

echodatabase$dbnamebackupstart

`mkdir-p$backup_dir`

`mysqldump-h$mysql_host-P$mysql_port-u$mysql_user-p$mysql_password$dbname-default-character-set=

$mysql_charset|gzipgt$backup_dir$dbname-$backup_timesqlgz`

flag=`echo$`

if[$flag==0]then

echodatabase$dbnamesuccessfullybackedupto$backup_dir$dbname-$backup_timesqlgz

else

echodatabase$dbnamebackuphasfailed

fi

done

else

echoERRORNodatabasetobackupbackupaborted

exit

fi

Ifdeletingexpiredbackupsisenableddeleteallexpiredbackups

Backupandrecovery

273

if[$expire_backup_delete==ON-a$backup_location=]then

`find$backup_location-typed-o-typef-ctime+$expire_days-execrm-rf`

`find$backup_location-typed-mtime+$expire_days|xargsrm-rf`

echoExpiredbackupdatadeletecomplete

fi

echoAlldatabaseshavebeensuccessfullybackedupThankyou

exit

fi

Modifythepropertiesoftheshellscriptlikeso

chmod600rootmysql_backupsh

chmod+xrootmysql_backupsh

Thenaddthecrontabcommand

0000rootmysql_backupsh

Thissetsupregularbackupsofyourdatabasestothevarwwwmysqldirectoryeverydayat0000whichcanthenbesynchronizedusingrsync

MySQLRecoveryWevejustdescribedsomecommonlyusedbackuptechniquesforMySQLnamelyhotbackupsandcoldbackupsTorecapthemaingoalofahotbackupistobeabletorecoverdatainreal-timeafteranapplicationhasfailedinsomewaysuchasinthecaseofaserverhard-diskmalfunctionWelearnedthatthistypeofschemecanbeimplementedbymodifyingdatabaseconfigurationfilessothatdatabasesarereplicatedontoaslaveminimizinginterruptiontoservices

ButsometimesweneedtoperformacoldbackupoftheSQLdatarecoveryaswithdatabasebackupyoucanimportthroughthecommandHotbackupsarehoweversometimesinadequateTherearecertainsituationswherecoldbackupsarerequiredtoperformdatarecoveryevenifitsonlyapartialoneWhenyouhaveacoldbackupofyourdatabaseyoucanusethefollowingMySQLcommandtoimportit

mysql-uusername-pdatabseltbackupsql

AsyoucanseeimportingandexportingdatabaseisafairlysimplematterIfyouneedtomanageadministrativeprivilegesordealwithdifferentcharactersetsthisprocessmaybecomealittlemorecomplicatedthoughthereareanumberofcommandswhichwillhelpyoutodothis

RedisbackupRedisisoneofthemostpopularNoSQLdatabasesandbothhotandcoldbackuptechniquescanalsobeusedinsystemswhichuseitLikeMySQLRedisalsosupportsmasterslavemodewhichisidealforimplementinghotbackups(refertoRedisofficialdocumentationtolearnhowtoconfigurethistheprocessisverystraightforward)AsforcoldbackupsRedisroutinelysavescacheddatainmemorytothedatabasefileon-diskWecansimplyusethersyncbackupmethoddescribedabovetosynchronizeitwithanon-localmachine

RedisrecoverySimilarlyRedisrecoverycanbedividedintohotandcoldbackuprecoveryThemethodsandobjectivesofrecoveringdatafromahotbackupofaRedisdatabasearethesameasthosementionedaboveforMySQLaslongastheRedisapplicationisusingtheappropriatedatabaseconnection

Backupandrecovery

274

ARediscoldbackuprecoverysimplyinvolvescopyingbacked-updatabasefilesintotheworkingdirectorythenstartingRedisonitThedatabasefilesareautomaticallyloadedintomemoryatboottimethespeedwithwhichRedisbootswilldependonthesizeofthedatabasefiles

SummaryInthissectionwelookedatsometechniquesforbackingupdataaswellasrecoveringfromdisasterswhichmayoccurafterdeployingourapplicationsWealsointroducedrsyncatoolwhichcanbeusedtosynchronizefilesondifferentsystemsUsingrsyncwecaneasilyperformbackupandrestorationproceduresforbothMySQLandRedisdatabasesamongothersWehopethatbybeingintroducedtosomeoftheseconceptsyouwillbeabletodevelopdisasterrecoveryprocedurestobetterprotectthedatainyourwebapplications

LinksDirectoryPrevioussectionDeploymentNextsectionSummary

Backupandrecovery

275

125SummaryInthischapterwediscussedhowtodeployandmaintainourGowebapplicationsWealsolookedatsomecloselyrelatedtopicswhichcanhelpustokeepthemrunningsmoothlywithminimalmaintenance

Specificallywelookedat

CreatingarobustloggingsystemcapableofrecordingerrorsandnotifyingsystemadministratorsHandlingruntimeerrorsthatmayoccurincludingloggingthemandhowtorelaythisinformationinauser-friendlymannerthatthereisaproblemHandling404errorsandnotifyingusersthattherequestedpagecannotbefoundDeployingapplicationstoaproductionenvironment(includinghowtodeployupdates)HowtodeployhighlyavailableapplicationsBackingupandrestoringfilesanddatabases

Afterreadingthecontentsofthischapterthosethinkingaboutdevelopingawebapplicationfromscratchshouldalreadyhavethefullpictureonhowtodosothischapterprovidedanintroductiononhowtomanagedeploymentenvironmentswhilepreviouschaptershavefocusedonthedevelopmentofcode

LinksDirectoryPrevioussectionBackupandrecoveryNextchapterBuildingawebframework

Summary

276

13BuildingawebframeworkThePrecedingtwelvechaptersdescribehowtodevelopwebapplicationsinGointroducingalotofbasicknowledgedevelopmenttoolsandtechniquesInthischapterwewillbeusingthisknowledgetoimplementasimplewebframeworkThefirstsectionofthischapterwilltakeyouthroughtheplanninganddesignstageofbuildingawebframeworkWelllookatleveragingtheMVCpatternaswellasdesigningprogramexecutionflowamongotherthingsThesecondsectionwilldescribethefirstfeatureofourframeworkRoutingnamelyhowtomapURLstoprocessinglogicTheninthethirdsectionwedescribetheprocessinglogicitselfwhichinvolvesdesigninggenericcontrollersandhowtohandlerequestsandreturnresponsesafterinheritingfromanobjecthandlerNextwedescribesomeoftheauxiliaryfunctionalitycommontomostwebframeworkssuchaslogprocessinginformationconfigurationetcFinallywellimplementasimplebloggingsystemontopofourframeworkwhichwilldemonstratetheapplicationlogicnecessaryforpublishingmodifyingdeletinganddisplayinglistsofblogposts

Byseeingfirst-handhowtoimplementsuchacompleteprojectfromscratchyouwillhopefullyhaveabetterunderstandingoftheinnerworkingsofGowebapplicationsYoullbecomfortablebuildingyourownprojectdirectorystructuresimplementingURLroutersandutilizingMVCamongotheraspectsofwebdevelopmentAmongtheframeworksprevalenttodayMVCisnolongeramythItsnotuncommontohearprogrammersarguingaboutwhichframeworksaregoodandwhicharebadwhichisoftentooshallowofanapproachFrameworksareonlytoolsandsometoolsaremoresuitableforcertainapplicationsthanothersTherearenouniversallygoodorbadtoolsThusbyteachingyourselfhowtowriteaframeworkfromscratchyouwillbeabletotailor-maketheperfecttooltobestrealizeyourideas

LinksDirectoryPreviouschapterChapter12summaryNextsectionProjectprogram

Buildawebframework

277

131ProjectplanningAnythingyouintendtodowellmustfirstbeplannedwellInourcaseourintentionistodevelopabloggingsystemsothefirststepweshouldtakeistodesigntheflowoftheapplicationinitsentiretyWhenwehaveaclearunderstandingoftheourapplicationsprocessofexecutionthesubsequentdesignandcodingstepsbecomemucheasier

GOPATHandprojectsettingsLetsproceedbyassumingthatourGOPATHpointstoafolderwithanordinarydirectoryname(ifnotwecaneasilysetupasuitabledirectoryandsetitspathastheGOPATH)AswevedescribeearlieraGOPATHcancontainmorethanonedirectoryinWindowswecansetthisasanenvironmentvariableinlinuxOSXsystemsGOPATHcanbesetusingexportieexportgopath=pathtoyourdirectoryaslongasthedirectorywhichGOPATHpointstocontainsthethreesub-directoriespkgbinandsrcBelowweveplacedthesourcecodeofournewprojectinthesrcdirectorywiththetentativenamebeelogHerearesomescreenshotsoftheWindowsenvironmentvariablesaswellasofthedirectorystructure

Figure131SettingtheGOPATHenvironmentvariable

Figure132Theworkingdirectoryunder$gopathsrc

ApplicationflowchartOurbloggingsystemwillbebasedonthemodel-view-controllerdesignpatternMVCistheseparationoftheapplicationlogicfromthepresentationlayerInpracticewhenwekeepthepresentationlayerseparatedwecandrasticallyreducetheamountofcodeneededonourwebpages

ModelsrepresentdataaswellastherulesandlogicgoverningitInGeneralamodelclasswillcontainfunctionsforremovinginsertingandupdatingdatabaseinformationViewsarearepresentationofthestateofamodelAviewisusuallyapagebutinGoaviewcanalsobeafragmentofapagesuchasaheaderorfooterItcanalsobeanRSSfeedoranyothertypeofpageGostemplatepackageprovidesverygoodsupportforviewlayerfunctionalityControllersarethegluelogicbetweenthemodelandviewlayersandencompassesalltheintermediarylogicnecessaryforhandlingHTTPrequestsandgeneratingWebpages

Thefollowingfigureisanoverviewoftheprojectframeworkanddemonstrateshowdatawillflowthroughthesystem

Figure133frameworkdataflow

1 Maingoistheapplicationsentrypointandinitializessomebasicresourcesrequiredtoruntheblogsuchasconfigurationinformationlisteningportsetc

2 RoutingchecksallincomingHTTPrequestsandaccordingtothemethodURLandparametersmatchesitwiththecorrespondingcontrolleraction

3 Iftherequestedresourcehasalreadybeencachedtheapplicationwillbypasstheusualexecutionprocessandreturnaresponsedirectlytotheusersbrowser

4 SecuritydetectionTheapplicationwillfilterincomingHTTPrequestsandanyotherusersubmitteddatabeforehandingitofftothecontroller

5 ControllerloadsmodelscorelibrariesandanyotherresourcesrequiredtoprocessspecificrequestsThecontrollerisprimarilyresponsibleforhandlingbusinesslogic

Projectprogram

278

6 OutputtherenderedviewtobesenttotheclientswebbrowserIfcachinghasbeenenabledthefirstviewiscachedforfuturerequeststothesameresource

DirectorystructureAccordingtotheframeworkflowwevedesignedaboveourblogprojectsdirectorystructureshouldlooksomethinglikethefollowing

|mdashmdashmaingoimportdocuments

|mdashmdashconfconfigurationfilesandprocessingmodule

|mdashmdashcontrollerscontrollerentry

|mdashmdashmodelsdatabaseprocessingmodule

|mdashmdashutilsusefulfunctionlibrary

|mdashmdashstaticstaticfiledirectory

|mdashmdashviewsviewgallery

FrameworkdesignInordertoquicklybuildourblogweneedtodevelopaminimalframeworkbasedontheapplicationwevedesignedaboveTheframeworkshouldincluderoutingcapabilitiessupportforRESTfulcontrollersautomatedtemplaterenderingaloggingsystemconfigurationmanagementandmore

SummaryThissectiondescribestheinitialdesignofourbloggingsystemfromsettingupourGOPATHtobrieflyintroducingtheMVCpatternWealsolookedattheflowofdataandtheexecutionsequenceofourbloggingsystemFinallywedesignedthestructureofourprojectdirectoryAtthispointwevebasicallycompletedthegroundworkrequiredforassemblingourframeworkInthenextfewsectionswewillimplementeachofthecomponentswevediscussedonebyone

LinksDirectoryPrevioussectionBuildingawebframeworkNextsectionCustomizingrouters

Projectprogram

279

132Customizingrouters

HTTProutingTheHTTProutingcomponentisresponsibleformappingHTTPrequeststoacorrespondingfunctionorstructmethodTheroutertakestwokeypiecesofinformationfromincomingrequests

-Theuserrequestedpath(forexampleuser123article123)andanyquerystringsorparametersthatcomewithit(forexampleid=11)-TheHTTPrequestmethod(GETPOSTPUTandDELETEPATCHetc)

Therouterthenforwardstherequesttothehandlerfunction(controllerlayer)thathasbeenregisteredwiththatparticularHTTPmethodandpath

DefaultroutingimplementationInsection34weintroducedGoshttppackageindetailwhichincludedhowtodesignandimplementroutingHerewetakeanotherlookatanexamplethatillustratestheroutingprocess

funcfooHandler(whttpResponseWriterrhttpRequest)

fmtFprintf(wHelloqhtmlEscapeString(rURLPath))

httpHandle(foofooHandler)

httpHandleFunc(barfunc(whttpResponseWriterrhttpRequest)

fmtFprintf(wHelloqhtmlEscapeString(rURLPath))

)

logFatal(httpListenAndServe(8080nil))

TheexampleabovecallshttpsdefaultmuxcalledDefaultServeMuximplicitlyspecifiedbythenilparameterinthecalltohttpListenAndServeThehttpHandlefunctiontakestwoparametersthefirstparameteristheresourceyouwantuserstoaccessspecifiedbyitsURLpath(whichisstoredinrURLPath)andthesecondargumentbindsahandlerfunctionwiththispathTheRouterhastwomainjobs

ToaddandstoreroutinginformationToforwardrequeststoahandlerfunctionforprocessing

BydefaultGoroutesarehandledwithhttpHandleandhttpHandleFunctypesregisteredbydefaultthroughtheunderlyingDefaultServeMuxHandle(patternstringhandlerHandler)functionThisfunctionmapsresourcepathstohandlersandstorestheminamap[string]muxEntrymapThisisthefirstjobthatwementionedabove

WhentheapplicationisrunningtheGoserverlistenstoaportWhenitreceivesatcpconnectionitusesaHandlertoprocessitAsaforementionedsincetheHandlerintheexampleaboveisnilthedefaultrouterhttpDefaultServeMuxisusedUsingthemapofpreviouslystoredroutesDefaultServeMuxServeHTTPwilldispatchtherequesttothefirsthandlerwithamatchingpathThisistherouterssecondjob

forkv=rangemuxm

ifpathMatch(kpath)

continue

ifh==nil||len(k)gtn

n=len(k)

h=vh

Customizedrouters

280

RoutingwithBeegoAtpresentmostGowebapplicationsbasetheirroutingonhttpsdefaultrouterhoweverthishasseverallimitations

DoesnotsupportdynamicrouteswithparameterssuchastheuserUIDDoesnothavegoodsupportforRESTTheaccessmethodscannotberestrictedforinstanceintheaboveexamplewhenusersaccessfootheycanusetheGETPOSTDELETEandHEADHTTPmethodsamongothersInlargeappsroutingrulescanbecomerepetitiveandcumbersomePersonallyIvedevelopedsimplewebAPIscomposedofnearlythirtyroutingruleswheninfacttheserulescouldhavebeenfurthersimplifiedusingmethodstructs

TheBeegoframeworksrouterisdesignedtoovercometheselimitationstakingtheRESTparadigmintoconsiderationandsimplifyingthestoringandforwardingofroutesandrequests

Storingroutes

ToaddressthefirstlimitationofthedefaultrouterweneedtobeabletosupportdynamicURLparametersForthesecondandthirdpointsweadoptanalternativeapproachmappingRESTmethodstostructmethodsandroutingrequeststothisstructinsteadoftohandlerfunctionsThiswayaforwardedrequestcanbehandledaccordingtoitsHTTPmethod

BasedontheaboveideaswevedesignedtwodatatypescontrollerInfowhichsavesthepathandthecorrespondingcontrollerTypestructasareflectTypetypeandControllerRegistorwhichsavesroutinginformationforthespecifiedBeegoapplication

typecontrollerInfostruct

regexregexpRegexp

paramsmap[int]string

controllerTypereflectType

typeControllerRegistorstruct

routers[]controllerInfo

ApplicationApp

ControllerRegistorsexternalinterfacecontainsthefollowingmethod

func(pControllerRegistor)Add(patternstringcControllerInterface)

Itsdetailedimplementationisasfollows

Customizedrouters

281

func(pControllerRegistor)Add(patternstringcControllerInterface)

parts=stringsSplit(pattern)

j=0

params=make(map[int]string)

foripart=rangeparts

ifstringsHasPrefix(part)

expr=([^]+)

ausermaychoosetooverridethedefaultexpression

similartoexpressjslsquouserid([0-9]+)rsquo

ifindex=stringsIndex(part()index=-1

expr=part[index]

part=part[index]

params[j]=part

parts[i]=expr

j++

recreatetheurlpatternwithparametersreplaced

byregularexpressionsThencompiletheregex

pattern=stringsJoin(parts)

regexregexErr=regexpCompile(pattern)

ifregexErr=nil

TODOadderrorhandlingheretoavoidpanic

panic(regexErr)

return

nowcreatetheRoute

t=reflectIndirect(reflectValueOf(c))Type()

route=ampcontrollerInfo

routeregex=regex

routeparams=params

routecontrollerType=t

prouters=append(proutersroute)

StaticroutingWeveimplementeddynamicroutinginourexampleaboveBydefaultGoshttppackagesupportsservingstaticfileswithhttpFileServerwhichreturnsaHandlerSincewehaveimplementedacustomrouterwewillalsoneedawayofhandlingstaticfilesBeegosstaticfolderpathissavedinaglobalvariablecalledStaticDirwhichmapstheURLtocorrespondingpathsTheSetStaticPathsimplementationcanbeseenbelow

func(appApp)SetStaticPath(urlstringpathstring)App

StaticDir[url]=path

returnapp

Theapplicationsstaticroutescanbesetlikeso

beegoSetStaticPath(imgstaticimg)

Forwardingroutes

Customizedrouters

282

WecanforwardroutesbasedontheforwardinginformationcontainedwithinControllerRegistorThedetailedimplementationcanbeseeninthefollowingcodesnippet

AutoRoute

func(pControllerRegistor)ServeHTTP(whttpResponseWriterrhttpRequest)

deferfunc()

iferr=recover()err=nil

ifRecoverPanic

gobacktopanic

panic(err)

else

Critical(Handlercrashedwitherrorerr)

fori=1i+=1

_filelineok=runtimeCaller(i)

ifok

break

Critical(fileline)

()

varstartedbool

forprefixstaticDir=rangeStaticDir

ifstringsHasPrefix(rURLPathprefix)

file=staticDir+rURLPath[len(prefix)]

httpServeFile(wrfile)

started=true

return

requestPath=rURLPath

findamatchingRoute

for_route=rangeprouters

checkifRoutepatternmatchesurl

ifrouteregexMatchString(requestPath)

continue

getsubmatches(params)

matches=routeregexFindStringSubmatch(requestPath)

doublecheckthattheRoutematchestheURLpattern

iflen(matches[0])=len(requestPath)

continue

params=make(map[string]string)

iflen(routeparams)gt0

addurlparameterstothequeryparammap

values=rURLQuery()

forimatch=rangematches[1]

valuesAdd(routeparams[i]match)

params[routeparams[i]]=match

reassemblequeryparamsandaddtoRawQuery

rURLRawQuery=urlValues(values)Encode()+amp+rURLRawQuery

rURLRawQuery=urlValues(values)Encode()

Invoketherequesthandler

vc=reflectNew(routecontrollerType)

init=vcMethodByName(Init)

in=make([]reflectValue2)

ct=ampContextResponseWriterwRequestrParamsparams

in[0]=reflectValueOf(ct)

in[1]=reflectValueOf(routecontrollerTypeName())

initCall(in)

in=make([]reflectValue0)

Customizedrouters

283

method=vcMethodByName(Prepare)

methodCall(in)

ifrMethod==GET

method=vcMethodByName(Get)

methodCall(in)

elseifrMethod==POST

method=vcMethodByName(Post)

methodCall(in)

elseifrMethod==HEAD

method=vcMethodByName(Head)

methodCall(in)

elseifrMethod==DELETE

method=vcMethodByName(Delete)

methodCall(in)

elseifrMethod==PUT

method=vcMethodByName(Put)

methodCall(in)

elseifrMethod==PATCH

method=vcMethodByName(Patch)

methodCall(in)

elseifrMethod==OPTIONS

method=vcMethodByName(Options)

methodCall(in)

ifAutoRender

method=vcMethodByName(Render)

methodCall(in)

method=vcMethodByName(Finish)

methodCall(in)

started=true

break

ifnomatchestourlthrowanotfoundexception

ifstarted==false

httpNotFound(wr)

GettingstartedUsingourrouterdesignwecansolvethethreelimitationsmentionedearlierThethreemainuse-casesare

Registeringroutehandlers

beegoBeeAppRegisterController(ampcontrollersMainController)

Handlingdynamicparameters

beegoBeeAppRegisterController(paramampcontrollersUserController)

Regexmatching

beegoBeeAppRegisterController(usersuid([0-9]+)ampcontrollersUserController)

LinksDirectoryPrevioussectionProjectplanningNextsectionDesigningcontrollers

Customizedrouters

284

Customizedrouters

285

133DesigningcontrollersMosttraditionalMVCframeworksarebasedonsuffixactionmappingNowadaystheRESTstylewebarchitectureisbecomingincreasinglypopularOnecanimplementREST-styleURLsbyfilteringorrewritingthembutwhynotjustdesignanewREST-styleMVCframeworkinsteadThissectionisbasedonthisideaandfocusesondesigningandimplementingacontrollerbasedREST-styleMVCframeworkfromscratchOurgoalistosimplifythedevelopmentofwebapplicationsperhapsevenallowingustowriteasinglelineofcodecapableofservingHelloworld

ThecontrollersroleTheMVCdesignpatterniscurrentlythemostusedframeworkmodelforwebapplicationsBykeepingModelsViewsandControllersseparatedwecankeepourwebapplicationsmodularmaintainabletestableandextensibleAmodelencapsulatesdataandanyofthebusinesslogicthatgovernsthatdatasuchasaccessibilityrulespersistencevalidationetcViewsserveasthedatasrepresentationandinthecaseofwebapplicationstheyusuallyliveastemplateswhicharethenrenderedintoHTMLandservedControllersserveasthegluelogicbetweenModelsandViewsandtypicallyhavemethodsforhandlingdifferentURLsAsdescribedintheprevioussectionwhenaURLrequestisforwardedtoacontrollerbytherouterthecontrollerdelegatescommandstotheModeltoperformsomeactionthennotifiestheViewofanychangesIncertaincasesthereisnoneedformodelstoperformanykindoflogicalordataprocessingorforanyviewstoberenderedForinstanceinthecaseofanHTTP302redirectnoviewneedstoberenderedandnoprocessingneedstobeperformedbytheModelhowevertheControllersjobisstillessential

RESTfuldesigninBeegoTheprevioussectiondescribesregisteringroutehandlerswithRESTfulstructsNowweneedtodesignthebaseclassforalogiccontrollerthatwillbecomposedoftwopartsastructandinterfacetype

typeControllerstruct

CtContext

TpltemplateTemplate

Datamap[interface]interface

ChildNamestring

TplNamesstring

Layout[]string

TplExtstring

typeControllerInterfaceinterface

Init(ctContextcnstring)Initializethecontextandsubclassname

Prepare()someprocessingbeforeexecutionbegins

Get()method=GETprocessing

Post()method=POSTprocessing

Delete()method=DELETEprocessing

Put()method=PUThandling

Head()method=HEADprocessing

Patch()method=PATCHtreatment

Options()method=OPTIONSprocessing

Finish()executedaftercompletionoftreatment

Render()errormethodexecutedafterthecorrespondingmethodtorenderthepage

ThenaddtheroutehandlingfunctiondescribedearlierinthischapterWhenarouteisdefinedtobeaControllerInterfacetypesolongaswecanimplementthisinterfacewecanhaveaccesstothefollowingmethodsofourbaseclasscontroller

func(cController)Init(ctContextcnstring)

cData=make(map[interface]interface)

cLayout=make([]string0)

Designcontrollers

286

cTplNames=

cChildName=cn

cCt=ct

cTplExt=tpl

func(cController)Prepare()

func(cController)Finish()

func(cController)Get()

httpError(cCtResponseWriterMethodNotAllowed405)

func(cController)Post()

httpError(cCtResponseWriterMethodNotAllowed405)

func(cController)Delete()

httpError(cCtResponseWriterMethodNotAllowed405)

func(cController)Put()

httpError(cCtResponseWriterMethodNotAllowed405)

func(cController)Head()

httpError(cCtResponseWriterMethodNotAllowed405)

func(cController)Patch()

httpError(cCtResponseWriterMethodNotAllowed405)

func(cController)Options()

httpError(cCtResponseWriterMethodNotAllowed405)

func(cController)Render()error

iflen(cLayout)gt0

varfilenames[]string

for_file=rangecLayout

filenames=append(filenamespathJoin(ViewsPathfile))

terr=templateParseFiles(filenames)

iferr=nil

Trace(templateParseFileserrerr)

err=tExecuteTemplate(cCtResponseWritercTplNamescData)

iferr=nil

Trace(templateExecuteerrerr)

else

ifcTplNames==

cTplNames=cChildName++cCtRequestMethod++cTplExt

terr=templateParseFiles(pathJoin(ViewsPathcTplNames))

iferr=nil

Trace(templateParseFileserrerr)

err=tExecute(cCtResponseWritercData)

iferr=nil

Trace(templateExecuteerrerr)

returnnil

Designcontrollers

287

func(cController)Redirect(urlstringcodeint)

cCtRedirect(codeurl)

AbovethecontrollerbaseclassalreadyimplementsthefunctionsdefinedintheinterfaceThroughourroutingrulestherequestwillberoutedtotheappropriatecontrollerwhichwillinturnexecutethefollowingmethods

Init()initializationroutine

Prepare()pre-initializationroutineeachinheritingsubclassmayimplementthisfunction

method()dependingontherequestmethodperformdifferentfunctionsGETPOSTPUTHEADetcSubclassesshouldi

mplementthesefunctionsifnotimplementedthenthedefaultis403

Render()optionalmethodDeterminewhetherornottoexecuteaccordingtotheglobalvariableAutoRender

Finish()isexecutedaftertheactionbeencompletedEachinheritingsubclassmayimplementthisfunction

ApplicationguideAbovewevejustfinisheddiscussingBeegosimplementationofthebasecontrollerclassWecannowusethisinformationtodesignourrequesthandlinginheritingfromthebaseclassandimplementingthenecessarymethodsinourowncontroller

packagecontrollers

import(

githubcomastaxiebeego

)

typeMainControllerstruct

beegoController

func(thisMainController)Get()

thisData[Username]=astaxie

thisData[Email]=astaxiegmailcom

thisTplNames=indextpl

InthecodeaboveweveimplementedasubclassofControllercalledMainControllerwhichonlyimplementstheGet()methodIfausertriestoaccesstheresourceusinganyoftheotherHTTPmethods(POSTHEADetc)a403ForbiddenwillbereturnedHoweverifausersubmitsaGETrequesttotheresourceandwehavetheAutoRendervariablesettotruetheresourcescontrollerwillautomaticallycallitsRender()functionrenderingthecorrespondingtemplateandrespondingwiththefollowing

Theindextplcodecanbeseenbelowasyoucanseeparsingmodeldataintoatemplateisquitesimple

ltDOCTYPEhtmlgt

lthtmlgt

ltheadgt

lttitlegtbeegowelcometemplatelttitlegt

ltheadgt

ltbodygt

lth1gtHelloworldUsernameEmaillth1gt

ltbodygt

lthtmlgt

LinksDirectory

Designcontrollers

288

PrevioussectionCustomizingroutersNextsectionLogsandconfigurations

Designcontrollers

289

134Loggingandconfiguration

TheimportanceofloggingandconfigurationPreviouslyinthebookwesawthateventloggingplaysaveryimportantroleinapplicationdevelopmentWithadequateloggingwecanrecordcrucialinformationthatcanlaterbedissectedfordebuggingandoptimizationpurposesInthesectionwherewelookedattheseelogloggingutilitywesawthatithadsettingsforvariousloglevelgradationswhichcanbeessentialforprogramdevelopmentanddeploymentwecansetthelogginglevellowerinadevelopmentenvironmentwhilesettingithighinproductionsothatwecanmaskextraneousinformationwhenwearetryingtodebugourapplication

SettinguptheserverconfigurationmodulefordeployinganapplicationinvolvesanumberofdifferentserversettingsForexamplewetypicallyneedtoprovideinformationregardingdatabaseconfigurationlisteningportsetcviatheconfigurationfileSettingupacentralizedconfigurationfileallowsustheflexibilityofdeployingtheapplicationtodifferentmachinesandconnectingtoremotedatabasesifneeded

TheBeegologgingsystemTheBeegologgersdesignborrowsideasfromseelogandprovidessimilarfunctionalityintermsofsettinglogginglevelsBeegossystemishowevermorelightweightandmakesuseoftheGoslogLoggerinterfaceBydefaultlogsareoutputtoosStdoutbutuserscanimplementthisinterfacethroughbeegoSetLoggertocustomizethisAdetailedexampleofanimplementedinterfacecanbeseenbelow

Loglevelsforcontrollingtheloggingoutput

const(

LevelTrace=iota

LevelDebug

LevelInfo

LevelWarning

LevelError

LevelCritical

)

logLevelcontrolsthegloballoglevelusedbythelogger

varlevel=LevelTrace

LogLevelreturnsthegloballoglevelandcanbeusedin

acustomimplementationsoftheloggerinterface

funcLevel()int

returnlevel

SetLogLevelsetsthegloballoglevelusedbythesimple

logger

funcSetLevel(lint)

level=l

ThissectionimplementstheaboveloggradingsystemThedefaultlevelissettoTraceanduserscancustomizegradinglevelsusingSetLevel

Logsandconfigurations

290

loggerreferencestheusedapplicationlogger

varBeeLogger=logNew(osStdoutlogLdate|logLtime)

SetLoggersetsanewlogger

funcSetLogger(llogLogger)

BeeLogger=l

Tracelogsamessageattracelevel

funcTrace(vinterface)

iflevellt=LevelTrace

BeeLoggerPrintf([T]vnv)

Debuglogsamessageatdebuglevel

funcDebug(vinterface)

iflevellt=LevelDebug

BeeLoggerPrintf([D]vnv)

Infologsamessageatinfolevel

funcInfo(vinterface)

iflevellt=LevelInfo

BeeLoggerPrintf([I]vnv)

Warninglogsamessageatwarninglevel

funcWarn(vinterface)

iflevellt=LevelWarning

BeeLoggerPrintf([W]vnv)

Errorlogsamessageaterrorlevel

funcError(vinterface)

iflevellt=LevelError

BeeLoggerPrintf([E]vnv)

Criticallogsamessageatcriticallevel

funcCritical(vinterface)

iflevellt=LevelCritical

BeeLoggerPrintf([C]vnv)

ThecodesnippetaboveinitializesaBeeLoggerobjectbydefaultoutputtinglogstoosStdoutAsmentioneduserscanimplementbeegoSetLoggertocustomizetheloggersoutputBeeLoggerimplementssixfunctions

Trace(recordgeneralinformationforexample)EnteredparsefunctionvalidationblockValidationenteredsecondifDictionaryDictisemptyUsingdefaultvalue

Debug(debugginginformationforexample)WebpagerequestedhttpsomesitecomParams=ResponsegeneratedResponsesize10000SendingNewfilereceivedTypePNGSize20000

Info(printinggeneralinformationforexample)WebserverrestartedHourlystatisticsRequestedpages12345Errors123ServicepausedWaitingforresumecall

Logsandconfigurations

291

Warn(warningmessagesforexample)Cachecorruptedforfile=testfileReadingfromback-endDatabase19216807DBnotrespondingUsingbackup19216808DBNoresponsefromstatisticsserverStatisticsnotsent

Error(errormessagesforexample)InternalerrorCannotprocessrequest12345ErrorCannotperformlogincredentialsDBnotresponding

Critical(fatalerrorsforexample)CriticalpanicreceivedShuttingdownFatalerrorAppisshuttingdowntopreventdatacorruptionorloss

YoucanseethateachoftheselevelshasaspecificpurposeForinstanceifwesettheloggingleveltoWarn(level=LevelWarning)atthetimeofdeploymentallofthelowerlevellogs(TraceDebugInfo)willnotoutputanything

BeegoconfigurationdesignForprocessingconfigurationinformationBeegoimplementsakey=valuefileparserwhichreadsinformationformattedsimilarlytoiniconfigurationfilesTheparserreadstheconfigurationdataandsavesittoamapFinallyitcallsseveralfunctionsforretrievingthevaluesdatatype(intstringetc)Thedetailedimplementationcanbeseenbelow

Definesomeglobalconstantsfortheiniconfigurationfile

var(

bComment=[]byte

bEmpty=[]byte

bEqual=[]byte=

bDQuote=[]byte

)

Definestheformatoftheconfigurationfile

AConfigrepresentstheconfiguration

typeConfigstruct

filenamestring

commentmap[int][]stringid[]commentkeyid1isformaincomment

datamap[string]stringkeyvalue

offsetmap[string]int64keyoffsetforediting

syncRWMutex

DefinesafunctionforparsingthefileTheprocessbeginsbyopeningthefilethenreadingitlinebylineandparsingcommentsblanklinesandkey=valuedata

Logsandconfigurations

292

ParseFilecreatesanewConfigandparsesthefileconfigurationfromthe

namedfile

funcLoadConfig(namestring)(Configerror)

fileerr=osOpen(name)

iferr=nil

returnnilerr

cfg=ampConfig

fileName()

make(map[int][]string)

make(map[string]string)

make(map[string]int64)

syncRWMutex

cfgLock()

defercfgUnlock()

deferfileClose()

varcommentbytesBuffer

buf=bufioNewReader(file)

fornCommentoff=0int64(1)

line_err=bufReadLine()

iferr==ioEOF

break

ifbytesEqual(linebEmpty)

continue

off+=int64(len(line))

ifbytesHasPrefix(linebComment)

line=bytesTrimLeft(line)

line=bytesTrimLeftFunc(lineunicodeIsSpace)

commentWrite(line)

commentWriteByte(n)

continue

ifcommentLen()=0

cfgcomment[nComment]=[]stringcommentString()

commentReset()

nComment++

val=bytesSplitN(linebEqual2)

ifbytesHasPrefix(val[1]bDQuote)

val[1]=bytesTrim(val[1]``)

key=stringsTrimSpace(string(val[0]))

cfgcomment[nComment-1]=append(cfgcomment[nComment-1]key)

cfgdata[key]=stringsTrimSpace(string(val[1]))

cfgoffset[key]=off

returncfgnil

BelowareanumberoffunctionstheparserusesforreadingtheconfigurationfileThereturnvalueisdeterminedaseitheraboolintfloat64orstring

Logsandconfigurations

293

Boolreturnsthebooleanvalueforagivenkey

func(cConfig)Bool(keystring)(boolerror)

returnstrconvParseBool(cdata[key])

Intreturnstheintegervalueforagivenkey

func(cConfig)Int(keystring)(interror)

returnstrconvAtoi(cdata[key])

Floatreturnsthefloatvalueforagivenkey

func(cConfig)Float(keystring)(float64error)

returnstrconvParseFloat(cdata[key]64)

Stringreturnsthestringvalueforagivenkey

func(cConfig)String(keystring)string

returncdata[key]

ApplicationguideThefollowingfunctionisanexampleofanapplicationIusedtofetchjsondatafromaremoteurladdress

funcGetJson()

resperr=httpGet(beegoAppConfigString(url))

iferr=nil

beegoCritical(httpgetinfoerror)

return

deferrespBodyClose()

bodyerr=ioutilReadAll(respBody)

err=jsonUnmarshal(bodyampAllInfo)

iferr=nil

beegoCritical(errorerr)

BeegosCritical()loggingfunctioniscalledtoreportanyerrorswhichmayoccurintheGetJson()functionbeegoAppConfigString(url)isusedtoobtaininformationfromaconfigurationfile(typicallyappconf)whichmightlooksomethinglikethefollowing

appname=hs

url=httpwwwapicomapihtml

LinksDirectoryPrevioussectionDesigningcontrollersNextsectionAddingdeletingandupdatingblogs

Logsandconfigurations

294

135AddingdeletingandupdatingblogsWevealreadyintroducedtheentireconceptbehindtheBeegoframeworkthroughexamplesandpseudo-codeThissectionwilldescribehowtoimplementabloggingsystemusingBeegoincludingtheabilitytobrowseaddmodifyanddeleteblogposts

BlogdirectoryOurblogsdirectorystructurecanbeseenbelow

maingo

views

viewtpl

newtpl

layouttpl

indextpl

edittpl

modelsmodelgo

controllers

indexgo

viewgo

newgo

deletego

editgo

BlogroutingOurblogsmainroutingrulesareasfollows

ShowblogHome

beegoRegisterController(ampcontrollersIndexController)

Viewblogdetails

beegoRegisterController(viewid([0-9]+)ampcontrollersViewController)

CreateblogBowen

beegoRegisterController(newampcontrollersNewController)

DeleteBowen

beegoRegisterController(deleteid([0-9]+)ampcontrollersDeleteController)

EditBowen

beegoRegisterController(editid([0-9]+)ampcontrollersEditController)

DatabasestructureAtrivialdatabasetabletostorebasicbloginformation

CREATETABLEentries(

idINTAUTO_INCREMENT

titleTEXT

contentTEXT

createdDATETIME

primarykey(id)

)

ControllerIndexController

Adddeleteandupdateblogs

295

typeIndexControllerstruct

beegoController

func(thisIndexController)Get()

thisData[blogs]=modelsGetAll()

thisLayout=layouttpl

thisTplNames=indextpl

ViewController

typeViewControllerstruct

beegoController

func(thisViewController)Get()

inputs=thisInput()

id_=strconvAtoi(thisCtxParams[id])

thisData[Post]=modelsGetBlog(id)

thisLayout=layouttpl

thisTplNames=viewtpl

NewController

typeNewControllerstruct

beegoController

func(thisNewController)Get()

thisLayout=layouttpl

thisTplNames=newtpl

func(thisNewController)Post()

inputs=thisInput()

varblogmodelsBlog

blogTitle=inputsGet(title)

blogContent=inputsGet(content)

blogCreated=timeNow()

modelsSaveBlog(blog)

thisCtxRedirect(302)

EditController

Adddeleteandupdateblogs

296

typeEditControllerstruct

beegoController

func(thisEditController)Get()

inputs=thisInput()

id_=strconvAtoi(thisCtxParams[id])

thisData[Post]=modelsGetBlog(id)

thisLayout=layouttpl

thisTplNames=edittpl

func(thisEditController)Post()

inputs=thisInput()

varblogmodelsBlog

blogId_=strconvAtoi(inputsGet(id))

blogTitle=inputsGet(title)

blogContent=inputsGet(content)

blogCreated=timeNow()

modelsSaveBlog(blog)

thisCtxRedirect(302)

DeleteController

typeDeleteControllerstruct

beegoController

func(thisDeleteController)Get()

id_=strconvAtoi(thisCtxInputParams[id])

blog=modelsGetBlog(id)

thisData[Post]=blog

modelsDelBlog(blog)

thisCtxRedirect(302)

Modellayer

Adddeleteandupdateblogs

297

packagemodels

import(

databasesql

githubcomastaxiebeedb

_githubcomziutekmymysqlgodrv

time

)

typeBlogstruct

Idint`PK`

Titlestring

Contentstring

CreatedtimeTime

funcGetLink()beedbModel

dberr=sqlOpen(mymysqlblogastaxie123456)

iferr=nil

panic(err)

orm=beedbNew(db)

returnorm

funcGetAll()(blogs[]Blog)

db=GetLink()

dbFindAll(ampblogs)

return

funcGetBlog(idint)(blogBlog)

db=GetLink()

dbWhere(id=id)Find(ampblog)

return

funcSaveBlog(blogBlog)(bgBlog)

db=GetLink()

dbSave(ampblog)

returnbg

funcDelBlog(blogBlog)

db=GetLink()

dbDelete(ampblog)

return

Viewlayerlayouttpl

Adddeleteandupdateblogs

298

lthtmlgt

ltheadgt

lttitlegtMyBloglttitlegt

ltstylegt

menu

width200px

floatright

ltstylegt

ltheadgt

ltbodygt

ltulid=menugt

ltligtltahref=gtHomeltagtltligt

ltligtltahref=newgtNewPostltagtltligt

ltulgt

LayoutContent

ltbodygt

lthtmlgt

indextpl

lth1gtBlogpostslth1gt

ltulgt

rangeblogs

ltligt

ltahref=viewIdgtTitleltagt

fromCreated

ltahref=editIdgtEditltagt

ltahref=deleteIdgtDeleteltagt

ltligt

end

ltulgt

viewtpl

lth1gtPostTitlelth1gt

PostCreatedltbrgt

PostContent

newtpl

lth1gtNewBlogPostlth1gt

ltformaction=method=postgt

Titleltinputtype=textname=titlegtltbrgt

Contentlttextareaname=contentcolspan=3rowspan=10gtlttextareagt

ltinputtype=submitgt

ltformgt

edittpl

lth1gtEditPostTitlelth1gt

lth1gtNewBlogPostlth1gt

ltformaction=method=postgt

Titleltinputtype=textname=titlevalue=PostTitlegtltbrgt

Contentlttextareaname=contentcolspan=3rowspan=10gtPostContentlttextareagt

ltinputtype=hiddenname=idvalue=PostIdgt

ltinputtype=submitgt

ltformgt

Adddeleteandupdateblogs

299

LinksDirectoryPrevioussectionLogsandconfigurationsNextsectionSummary

Adddeleteandupdateblogs

300

136SummaryInthischapterwedescribedhowtoimplementthemajorcomponentsofaGowebframeworkWefirstdesignedaroutertomakeupforsomeofshortcomingsinGosbuilt-inhttppackagecreatingaroutercapableofdynamicroutingandRESTsupportWealsodesignedourownRESTfulControllerclassinaccordwiththeprinciplesofMVCborrowingideasfromframeworkssuchasTornadoNextwedesignedandimplementedatemplatelayoutandautomatedrenderingsystemmainlyusingGosbuilt-intemplatingengineWethenimplementedacustomloggerandtalkedaboutframeworkconfigurationtoallowforflexibleapplicationdeploymentThroughthisprocesswehaveimplementedabasicwebframeworkcalledBeegowhichatpresenthasbeenopen-sourcedonGithubLastlyweimplementedasimplebloggingapplicationontopofBeegoAfterhavinggonethroughalloftheseexamplesyouwillhopefullyhavelearnedhowtoquicklydevelopwebsitesinGo

LinksDirectoryPrevioussectionAdddeleteandupdateblogsNextchapterDevelopwebframework

Summary

301

14DevelopingawebframeworkChapter13describedhowtodevelopawebframeworkinGoWeintroducedtheMVCarchitecturearoutingandloggingsystemandwealsolookedatsimpleserverconfigurationThesearethebasicbuildingblocksofmostframeworksanditsagoodstartHoweverformoresophisticatedneedssomeauxiliarytoolsareneededtofacilitaterapidwebsitedevelopmentInthischapterwewillprovidesomequicktipsandtoolsforspeedingupdevelopmentThefirstsectionwillcoverthehow-toshowprocessingstaticfilesandwewillbeusingTwittersopensourceCSSandJavascriptframeworkcalledBootstrapforbeautifyingourwebsiteThesecondsectiondescribeshowtousethepreviouslydescribedsessionsforuserloginprocessingNextthethirdsectiondescribeshowtogenerateformsandhowtoprocesstheseformsforvaliddataWewillalsotalkabouthowtobindmodelsforCRUDoperationsInsection4welldescribehowtoperformsomeuserauthenticationincludingbasicHTTPauthenticationandHTTPdigestauthenticationFinallythelastsectionwilltalkaboutimplementingthepreviouslydescribedi18ntosupportmulti-lingualwebapplications

ByextendingBeegointhischapterwewillbeabletorapidlydevelopfullstackwebapplicationsOfcoursewellgothroughthefeaturesoftheseextensionsstep-by-stepapplyingthemtothebloggingsystemwedevelopedinChapter13ThroughthedevelopmentofacompleteandbeautifulbloggingsystemuserswillhopefullybeabletoseehowBeegocanhelptoboostdeveloperproductivity

LinksDirectoryPreviouschapterChapter13summaryNextsectionStaticfiles

Developwebframework

302

141StaticfilesWevealreadytalkedabouthowtodealwithstaticfilesinprevioussectionsNowletslookathowtosetupandusestaticfilesinsideofBeegoThenthroughintroducingTwittersopensourceHTMLandCSSframeworkBootstrapwellbeablequicklycreatebeautifullookingwebsiteswithouthavingtodotoomuchdesignwork

BeegostaticfilesandsettingsGosnethttppackageprovidesastaticfileserverwithfunctionssuchasServeFileandFileServerBeegosstaticfilehandlingisbasedonthislayeranditsspecificimplementationisasfollow

staticfileserver

forprefixstaticDir=rangeStaticDir

ifstringsHasPrefix(rURLPathprefix)

file=staticDir+rURLPath[len(prefix)]

httpServeFile(wrfile)

wstarted=true

return

StaticDirstorestheURLwhichcorrespondstoastaticfiledirectorysowhenhandlingrequestswesimplyneedtodeterminewhetherornottheURLbeginswithastaticfilepathIfsowecansimplyrespondusinghttpServeFile

Thefollowingisanexample

beegoStaticDir[asset]=static

ThenarequestwithaURLsuchashttpwwwbeegomeassetbootstrapcsswillresultinstaticbootstrapcssbeingservedtotheclient

BootstrapintegrationBootstrapisanopensourceToolkitforfront-enddevelopmentlaunchedbyTwitterFordevelopersBootstrapisoneofthebestfrontendkitsforrapidWebapplicationdevelopmentItisacollectionofHTMLCSSandjavascriptcomponentsusingthelatestHTML5standardsTheseincludearesponsivegridformsbuttonstablesandmanyotherusefulthings

ComponentsBootstrapcontainsawealthofWebcomponentsUsingthesecomponentsyoucanquicklybuildabeautifulfullyfunctionalwebsitewhichincludesthefollowingcomponentsPull-downmenusbuttongroupsbuttondrop-downmenusnavigationnavigationbarsbreadcrumbspaginationlayoutthumbnailswarningdialogsprogressbarsandothermediaobjectsJavaScriptpluginsBootstrapcomeswith13jQueryplug-insforBootstrapcomponentswhichgivesthemlifeTheseincludeModaldialogstabsscrollbarspop-upboxesandsoonBootstrapframeworkcustomizationAllBootstrapcssvariablescanbemodifiedaccordingtoyourneeds

Figure141abootstrapwebsite

NextletsseehowwecanuseBootstrapinsideourBeegoapplicationtoquicklycreateabeautifulwebsite

1 Firstletsdownloadthebootstrapdirectoryintoourprojectsstaticdirectoryasshowninthefollowingscreenshot

Staticfiles

303

Figure142Projectstaticfiledirectorystructure

2 BecauseBeegosetsadefaultvalueforStaticDirifyourstaticfilesdirectoryisstaticthenyouneednotgoanyfurther

StaticDir[static]=static

3 Ourtemplatesusethefollowingassetpaths

cssfile

ltlinkhref=staticcssbootstrapcssrel=stylesheetgt

jsfile

ltscriptsrc=staticjsbootstrap-transitionjsgtltscriptgt

Picturefiles

ltimgsrc=staticimglogopnggt

WiththeabovecodeweareintegratingBootstrapintoourBeegoapplicationThefigurebelowdemonstratestherenderedpage

Figure143websiteintegratedwithBootstrap

ThesetemplatesandformatsallcomeshippedwithBootstrapsowewontrepeatthecompletecodeherehoweveryoucantakealookattheprojectsofficialpagetolearnhowtowriteyourowntemplates

LinksDirectoryPrevioussectionDevelopingawebframeworkNextsectionSessions

Staticfiles

304

142SessionsInchapter6weintroducedsomebasicconceptspertainingtosessionsinGoandweimplementedasessionmanagerTheBeegoframeworkusesthissessionmanagertoimplementsomeconvenientsession-handlingfunctionality

IntegratingsessionsBeegohandlessessionsmainlyaccordingtothefollowingglobalvariables

relatedtosession

SessionOnboolwhetherornottoopenthesessionmoduleDefaultstofalse

SessionProviderstringthedesiredsessionbackendprocessingmoduleDefaultstoanin-memorysessionManager

SessionNamestringthenameoftheclientsavedcookies

SessionGCMaxLifetimeint64cookievalidity

GlobalSessionssessionManagerglobalsessioncontroller

OfcoursethevaluesofthesevariablesshownaboveneedtobeinitializedYoucanalsousethevaluesfromthefollowingconfigurationfilecodetosetthesevalues

ifarerr=AppConfigBool(sessionon)err=nil

SessionOn=false

else

SessionOn=ar

ifar=AppConfigString(sessionprovider)ar==

SessionProvider=memory

else

SessionProvider=ar

ifar=AppConfigString(sessionname)ar==

SessionName=beegosessionID

else

SessionName=ar

ifarerr=AppConfigInt(sessiongcmaxlifetime)err=nilampampar=0

int64val_=strconvParseInt(strconvItoa(ar)1064)

SessionGCMaxLifetime=int64val

else

SessionGCMaxLifetime=3600

AddthefollowingcodeinthebeegoRunfunction

ifSessionOn

GlobalSessions_=sessionNewManager(SessionProviderSessionNameSessionGCMaxLifetime)

goGlobalSessionsGC()

AslongasSessionOnissettotrueitwillopenthesessionbydefaultwithanindependentgoroutinesessionhandler

InordertofacilitateourcustomControllerquicklyusingsessiontheauthorbeegoControllerprovidesthefollowingmethods

ToassistusinquicklyusingsessionsinacustomControllerbeegoControllerprovidesthefollowingmethod

Session

305

func(cController)StartSession()(sesssessionSession)

sess=GlobalSessionsSessionStart(cCtxResponseWritercCtxRequest)

return

UsingsessionsFromthecodeabovewecanseethattheBeegoframeworksimplyinheritsitssessionfunctionalitySohowdoweuseitinourprojects

Firstofallweneedtoopenthesessionattheentrypointofourapplication

beegoSessionOn=true

Wecanthenusethecorrespondingsessionmethodinsideourcontrollerlikeso

func(thisMainController)Get()

varintcountint

sess=thisStartSession()

count=sessGet(count)

ifcount==nil

intcount=0

else

intcount=count(int)

intcount=intcount+1

sessSet(countintcount)

thisData[Username]=astaxie

thisData[Email]=astaxiegmailcom

thisData[Count]=intcount

thisTplNames=indextpl

ThecodeaboveshowshowtousesessionsinthecontrollerlogicTheprocesscanbedividedintotwosteps

1 Gettingsessionobject

GettheobjectsimilarinPHPsession_start()

sess=thisStartSession()

2 Usingthesessionforgeneraloperations

GetthesessionvaluessimilarinPHP$_SESSION[count]

sessGet(count)

Setthesessionvalue

sessSet(countintcount)

AsyoucanseeapplicationsbasedontheBeegoframeworkcaneasilyimplementsessionsTheprocessisverysimilartocallingsession_start()inPHPapplications

LinksDirectoryPrevioussectionStaticfilesNextsectionForms

Session

306

Session

307

143FormsInwebdevelopmentthefollowingworkflowwillprobablylookquitefamiliar

OpenawebpageshowingaformUsersfilloutandsubmittheformIfausersubmitssomeinvalidinformationorhasneglectedtofilloutarequiredfieldtheformwillbereturnedtotheuser(alongwiththefilledindata)withsomedescriptiveinformationabouttheproblemUsersre-filltheinvalidfieldsandcontinueattemptingtosubmittheformuntilitsaccepted

Atthereceivingendthescriptmust

ChecktheusersubmittedformdataVerifywhetherthedataisthecorrecttypeandoftheappropriatestandardForexampleifausernameissubmitteditmustverifythatitcontainsonlyvalidcharactersOtherexampleswouldbecheckingforminimumandmaximumlengthsusernameuniquenessandsoonFilteringdataandcleaningupunsafecharacterstoguaranteethatourapplicationonlyprocessesdatawhichissafeIfnecessarypre-formatthedata(ordatagapsneedtobeclearedthroughtheHTMLcodingandsoon)Preparethedataforinsertionintothedatabase

AlthoughtheprocedureisnotverycomplexitusuallyrequiresalotofboilerplateInadditionwebapplicationsoftenuseavarietyofdifferentcontrolstructurestodisplayerrormessagesonreturnedpagesImplementingformvalidationisasimplebutboringtask

FormsandvalidationFordevelopersthegeneraldevelopmentprocesscanbequitecomplexbutitsmostlyrepetitiveworkSupposeascenarioariseswhereyousuddenlyneedtoaddaformtoyourprojectcausingyoutorewriteallofthelocalcodetiedinwiththeformWeknowthatstructsareaverycommonlyuseddatastructureinGoandBeegousesthemtoitsadvantageforprocessingforminformation

FirstwedefineastructwithfieldscorrespondingtothefieldsinourformelementWecanusestructtagswhichmaptotheformelementasshownbelow

WhendevelopingWebapplicationsfirstdefineastructthatmatchesafieldtoacorrespondingformelementdefinedbyusingastructtagcorrespondingtotheelementinformationandauthenticationinformationasshownbelow

FordevelopersthegeneraldevelopmentprocessisverycomplexandmostlyconsistsofrepeatingthesameworkprocessAssumingascenarioforaprojectwherebyaneedarisestoadddatatoaformthenthelocalcodeoftheentireprocessneedstobemodifiedWeknowinGoastructisacommondatastructuresobeegousesaformstructtoprocessforminformation

Firstdefineastructwithfieldscorrespondingtoourformelementusingstructtagstodefinethecorrespondingformelementandauthenticationinformationlikeso

typeUserstruct

Usernamestring`formtextvalidrequired`

Nicknamestring`formtextvalidrequired`

Ageint`formtextvalidrequired|numeric`

Emailstring`formtextvalidrequired|valid_email`

Introducestring`formtextarea`

Afterdefiningourstructwecanaddthisactioninourcontroller

Form

308

func(thisAddController)Get()

thisData[form]=beegoForm(ampUser)

thisLayout=adminlayouthtml

thisTplNames=adminaddtpl

Theformisdisplayedinourtemplatelikeso

lth1gtNewBlogPostlth1gt

ltformaction=method=postgt

formrender()

ltformgt

AbovewevedefinedtheentirefirststepofdisplayingaformmappedtoastructThenextstepisforuserstofillintheirinformationandsubmittheformafterwhichtheserverwillreceivethedataandverifyitFinallytherecordwillbeinsertedintothedatabase

func(thisAddController)Post()

varuserUser

form=thisGetInput(ampuser)

ifformValidates()

return

modelsUserInsert(ampuser)

thisCtxRedirect(302adminindex)

FormtypeThefollowingtableliststhecorrespondingformelementinformation

lttablecellpadding=0cellspacing=1border=0style=width100class=tablebordergt

lttbodygt

lttrgt

ltthgtNameltthgt

ltthgtparameterltthgt

ltthgtDescriptionltthgt

lttrgt

lttrgt

lttdclass=tdgtltstronggttextltstronggt

lttdgt

lttdclass=tdgtNolttdgt

lttdclass=tdgttextboxinputboxlttdgt

lttrgt

lttrgt

lttdclass=tdgtltstronggtbuttonltstronggt

lttdgt

lttdclass=tdgtNolttdgt

lttdclass=tdgtbuttonlttdgt

lttrgt

lttrgt

lttdclass=tdgtltstronggtcheckboxltstronggt

lttdgt

lttdclass=tdgtNolttdgt

lttdclass=tdgtmulti-selectboxlttdgt

lttrgt

lttrgt

lttdclass=tdgtltstronggtdropdownltstronggt

lttdgt

lttdclass=tdgtNolttdgt

lttdclass=tdgtdrop-downselectionboxlttdgt

Form

309

lttrgt

lttrgt

lttdclass=tdgtltstronggtfileltstronggt

lttdgt

lttdclass=tdgtNolttdgt

lttdclass=tdgtfileuploadlttdgt

lttrgt

lttrgt

lttdclass=tdgtltstronggthiddenltstronggt

lttdgt

lttdclass=tdgtNolttdgt

lttdclass=tdgthiddenelementslttdgt

lttrgt

lttrgt

lttdclass=tdgtltstronggtpasswordltstronggt

lttdgt

lttdclass=tdgtNolttdgt

lttdclass=tdgtpasswordinputboxlttdgt

lttrgt

lttrgt

lttdclass=tdgtltstronggtradioltstronggt

lttdgt

lttdclass=tdgtNolttdgt

lttdclass=tdgtsingleboxlttdgt

lttrgt

lttrgt

lttdclass=tdgtltstronggttextarealtstronggt

lttdgt

lttdclass=tdgtNolttdgt

lttdclass=tdgttextinputboxlttdgt

lttrgt

lttbodygt

lttablegt

FormvalidationThefollowingtablelistssomeformvalidationrulesnativetoBeegothatcanbeused

lttablecellpadding=0cellspacing=1border=0style=width100class=tablebordergt

lttbodygt

lttrgt

ltthgtrulesltthgt

ltthgtparameterltthgt

ltthgtDescriptionltthgt

ltthgtExampleltthgt

lttrgt

lttrgt

lttdclass=tdgtltstronggtrequiredltstronggt

lttdgt

lttdclass=tdgtNolttdgt

lttdclass=tdgtIftheelementisemptyitreturnsFALSElttdgt

lttdclass=tdgtlttdgt

lttrgt

lttrgt

lttdclass=tdgtltstronggtmatchesltstronggt

lttdgt

lttdclass=tdgtYeslttdgt

lttdclass=tdgtiftheformelementsvaluewiththecorrespondingformfieldparametervaluesarenotequalth

enreturn

FALSElttdgt

lttdclass=tdgtmatches[form_item]lttdgt

lttrgt

Form

310

lttrgt

lttdclass=tdgtltstronggtis_uniqueltstronggt

lttdgt

lttdclass=tdgtYeslttdgt

lttdclass=tdgtiftheformelementsvaluewiththespecifiedfieldinatablehasduplicatedataitreturnsF

alse(Translators

NoteForexampleis_unique[UserEmail]thenthevalidationclasswilllookfortheUsertableinthe

Emailfieldthereisnoformelementswiththesamevaluesuchasdepositrepeatitreturnsfalseso

developersdonothavetowriteanotherCallbackverificationcode)lttdgt

lttdclass=tdgtis_unique[tablefield]lttdgt

lttrgt

lttrgt

lttdclass=tdgtltstronggtmin_lengthltstronggt

lttdgt

lttdclass=tdgtYeslttdgt

lttdclass=tdgtformelementvaluesifthecharacterlengthislessthanthenumberofdefinedparametersitre

turnsFALSElttdgt

lttdclass=tdgtmin_length[6]lttdgt

lttrgt

lttrgt

lttdclass=tdgtltstronggtmax_lengthltstronggt

lttdgt

lttdclass=tdgtYeslttdgt

lttdclass=tdgtiftheformelementsvalueisgreaterthanthelengthofthecharacterdefinednumericargument

itreturns

FALSElttdgt

lttdclass=tdgtmax_length[12]lttdgt

lttrgt

lttrgt

lttdclass=tdgtltstronggtexact_lengthltstronggt

lttdgt

lttdclass=tdgtYeslttdgt

lttdclass=tdgtiftheformelementvaluesandparametersdefinedcharacterlengthnumberdoesnotmatchitret

urnsFALSElttdgt

lttdclass=tdgtexact_length[8]lttdgt

lttrgt

lttrgt

lttdclass=tdgtltstronggtgreater_thanltstronggt

lttdgt

lttdclass=tdgtYeslttdgt

lttdclass=tdgtIftheformelementvaluesnon-numerictypesorlessthanthevaluedefinedparametersitret

urnsFALSElttdgt

lttdclass=tdgtgreater_than[8]lttdgt

lttrgt

lttrgt

lttdclass=tdgtltstronggtless_thanltstronggt

lttdgt

lttdclass=tdgtYeslttdgt

lttdclass=tdgtIftheformelementvaluesnon-numerictypesorgreaterthanthevaluedefinedparametersit

returnsFALSElttdgt

lttdclass=tdgtless_than[8]lttdgt

Form

311

lttrgt

lttrgt

lttdclass=tdgtltstronggtalphaltstronggt

lttdgt

lttdclass=tdgtNolttdgt

lttdclass=tdgtIftheformelementvaluecontainscharactersotherthanlettersbesidesitreturnsFALSElttdgt

lttdclass=tdgtlttdgt

lttrgt

lttrgt

lttdclass=tdgtltstronggtalpha_numericltstronggt

lttdgt

lttdclass=tdgtNolttdgt

lttdclass=tdgtIftheformelementvaluescontainedinadditiontolettersandothercharactersotherthannumb

ersitreturns

FALSElttdgt

lttdclass=tdgtlttdgt

lttrgt

lttrgt

lttdclass=tdgtltstronggtalpha_dashltstronggt

lttdgt

lttdclass=tdgtNolttdgt

lttdclass=tdgtIftheformelementvaluecontainsinadditiontotheletternumberunderlinecharactersothe

rthandash

returnsFALSElttdgt

lttdclass=tdgtlttdgt

lttrgt

lttrgt

lttdclass=tdgtltstronggtnumericltstronggt

lttdgt

lttdclass=tdgtNolttdgt

lttdclass=tdgtIftheformelementvaluecontainscharactersotherthannumbersinadditionitreturnsFALSElt

tdgt

lttdclass=tdgtlttdgt

lttrgt

lttrgt

lttdclass=tdgtltstronggtintegerltstronggt

lttdgt

lttdclass=tdgtNolttdgt

lttdclass=tdgtexceptiftheformelementcontainscharactersotherthananintegeritreturnsFALSElttdgt

lttdclass=tdgtlttdgt

lttrgt

lttrgt

lttdclass=tdgtltstronggtdecimalltstronggt

lttdgt

lttdclass=tdgtYeslttdgt

lttdclass=tdgtIftheformelementtype(non-decimal)isnotcompleteitreturnsFALSElttdgt

lttdclass=tdgtlttdgt

lttrgt

lttrgt

lttdclass=tdgtltstronggtis_naturalltstronggt

lttdgt

lttdclass=tdgtNolttdgt

lttdclass=tdgtvalueiftheformelementcontainsanumberofotherunnaturalvalues(othervaluesexcludingz

ero)it

returnsFALSENaturalnumberslikethis0123andsoonlttdgt

lttdclass=tdgtlttdgt

lttrgt

lttrgt

lttdclass=tdgtltstronggtis_natural_no_zeroltstronggt

Form

312

lttdgt

lttdclass=tdgtNolttdgt

lttdclass=tdgtvalueiftheformelementcontainsanumberofotherunnaturalvalues(othervaluesincludingz

ero)it

returnsFALSENonzeronaturalnumbers123andsoonlttdgt

lttdclass=tdgtlttdgt

lttrgt

lttrgt

lttdclass=tdgtltstronggtvalid_emailltstronggt

lttdgt

lttdclass=tdgtNolttdgt

lttdclass=tdgtIftheformelementvaluecontainsinvalidemailaddressitreturnsFALSElttdgt

lttdclass=tdgtlttdgt

lttrgt

lttrgt

lttdclass=tdgtltstronggtvalid_emailsltstronggt

lttdgt

lttdclass=tdgtNolttdgt

lttdclass=tdgtformelementvaluesifanyonevaluecontainsinvalidemailaddress(addressesseparatedbycomm

asinEnglish

)itreturnsFALSElttdgt

lttdclass=tdgtlttdgt

lttrgt

lttrgt

lttdclass=tdgtltstronggtvalid_ipltstronggt

lttdgt

lttdclass=tdgtNolttdgt

lttdclass=tdgtiftheformelementsvalueisnotavalidIPaddressitreturnsFALSElttdgt

lttdclass=tdgtlttdgt

lttrgt

lttrgt

lttdclass=tdgtltstronggtvalid_base64ltstronggt

lttdgt

lttdclass=tdgtNolttdgt

lttdclass=tdgtiftheformelementsvaluecontainsthebase64-encodedcharactersinadditiontootherthanthe

characters

returnsFALSElttdgt

lttdclass=tdgtlttdgt

lttrgt

lttbodygt

lttablegt

LinksDirectoryPrevioussectionSessionsNextsectionUservalidation

Form

313

144UservalidationIntheprocessofdevelopingwebapplicationsuserauthenticationisaproblemwhichdevelopersfrequentlyencounterUserloginregistrationandlogoutamongotheroperationsaswellasgeneralauthenticationcanbedividedintothreeparts

HTTPBasicandHTTPDigestAuthenticationThirdPartyAuthenticationIntegrationQQmicro-bloggingwatercressOPENIDGoogleGitHubFacebookandtwitteretcCustomuserloginregistrationlogoutaregenerallybasedonsessionsandcookieauthentication

BeegodoesnotnativelyprovidesupportforanyofthesethreethingshoweveryoucaneasilymakeuseofexistingthirdpartyopensourcelibrariestoimplementthemThefirsttwoauthenticationsolutionsareonBeegosroadmaptoeventuallybeintegrated

HTTPbasicanddigestauthenticationBothHTTPbasicanddigestauthenticationarerelativelysimpletechniquescommonlyusedbywebapplicationsTherearealreadymanyopensourcethird-partylibrarieswhichsupportthesetwoauthenticationmethodssuchas

githubcomabbotgo-http-auth

ThefollowingcodedemonstrateshowtousethislibrarytoimplementauthenticationinaBeegoapplication

packagecontrollers

import(

githubcomabbotgo-http-auth

githubcomastaxiebeego

)

funcSecret(userrealmstring)string

ifuser==john

passwordishello

return$1$dlPL2MqE$oQmn16q49SqdmhenQuNgs1

return

typeMainControllerstruct

beegoController

func(thisMainController)Prepare()

a=authNewBasicAuthenticator(examplecomSecret)

ifusername=aCheckAuth(thisCtxRequest)username==

aRequireAuth(thisCtxResponseWriterthisCtxRequest)

func(thisMainController)Get()

thisData[Username]=astaxie

thisData[Email]=astaxiegmailcom

thisTplNames=indextpl

TheabovecodetakesadvantageofBeegosprepare()functiontoperformauthenticationbeforeallowingthenormalflowofexecutiontoproceedasyoucanseeitsverysimpletoimplementHTTPauthenticationDigestauthenticationcanbeimplementedinmuchthesameway

Uservalidation

314

OAuthandOAuth2authenticationOAuthandOAuth2arecurrentlytwoofthemostpopularauthenticationmethodsFortunatelytherearethird-partylibrarieswhichimplementthistypeofauthenticationsuchasthegoauthpackageavailableongithub

githubcombradrydzewskigoauth

ThecodebelowdemonstrateshowtousethislibrarytoimplementOAuthauthenticationinBeegousingourGithubcredentials

1 Letsaddsomeroutes

beegoRegisterController(authloginampcontrollersGithubController)

beegoRegisterController(mainpageampcontrollersPageController)

2 ThenwedealwiththeGithubControllerlandingpage

packagecontrollers

import(

githubcomastaxiebeego

githubcombradrydzewskigoauth

)

const(

githubClientKey=a0864ea791ce7e7bd0df

githubSecretKey=a0ec09a647a688a64a28f6190b5a0d2705df56ca

)

typeGithubControllerstruct

beegoController

func(thisGithubController)Get()

settheauthparameters

authConfigCookieSecret=[]byte(7H9xiimk2QdTdYI7rDddfJeV)

authConfigLoginSuccessRedirect=mainpage

authConfigCookieSecure=false

githubHandler=authGithub(githubClientKeygithubSecretKey)

githubHandlerServeHTTP(thisCtxResponseWriterthisCtxRequest)

3 Handlingafterasuccessfullandingpage

Uservalidation

315

packagecontrollers

import(

githubcomastaxiebeego

githubcombradrydzewskigoauth

nethttp

neturl

)

typePageControllerstruct

beegoController

func(thisPageController)Get()

settheauthparameters

authConfigCookieSecret=[]byte(7H9xiimk2QdTdYI7rDddfJeV)

authConfigLoginSuccessRedirect=mainpage

authConfigCookieSecure=false

usererr=authGetUserCookie(thisCtxRequest)

ifnoactiveusersessionthenauthorizeuser

iferr=nil||userId()==

httpRedirect(thisCtxResponseWriterthisCtxRequestauthConfigLoginRedirecthttpStatusSeeOther

)

return

elseaddtheusertotheURLandcontinue

thisCtxRequestURLUser=urlUser(userId())

thisData[pic]=userPicture()

thisData[id]=userId()

thisData[name]=userName()

thisTplNames=hometpl

Thewholeprocessisasfollows

firstopenyourbrowserandentertheaddress

Figure144showsthehomepagewithaloginbutton

Whenclickingonthelinkthefollowingscreenappears

Figure145displayedafterclickingtheloginbuttontoauthenticatewithyourGitHubcredentials

AfterclickingAuthorizeappthefollowingscreenappears

Figure146authorizedGithubinformationgetsdisplayedaftertheloginpage

CustomauthenticationCustomauthenticationisgenerallycombinedwithsessionauthenticationthefollowingcodeisaBeegobasedopensourceblogwhichdemonstratesthis

Loginprocess

func(thisLoginController)Post()

thisTplNames=logintpl

thisCtxRequestParseForm()

username=thisCtxRequestFormGet(username)

Uservalidation

316

password=thisCtxRequestFormGet(password)

md5Password=md5New()

ioWriteString(md5Passwordpassword)

buffer=bytesNewBuffer(nil)

fmtFprintf(bufferxmd5PasswordSum(nil))

newPass=bufferString()

now=timeNow()Format(2006-01-02150405)

userInfo=modelsGetUserInfo(username)

ifuserInfoPassword==newPass

varusersmodelsUser

usersLast_logintime=now

modelsUpdateUserInfo(users)

Setthesessionsuccessfullogin

sess=globalSessionsSessionStart(thisCtxResponseWriterthisCtxRequest)

sessSet(uiduserInfoId)

sessSet(unameuserInfoUsername)

thisCtxRedirect(302)

Registrationprocess

func(thisRegController)Post()

thisTplNames=regtpl

thisCtxRequestParseForm()

username=thisCtxRequestFormGet(username)

password=thisCtxRequestFormGet(password)

usererr=checkUsername(username)

fmtPrintln(usererr)

ifusererr==false

thisData[UsernameErr]=UsernameerrorPleasetoagain

return

passerr=checkPassword(password)

ifpasserr==false

thisData[PasswordErr]=PassworderrorPleasetoagain

return

md5Password=md5New()

ioWriteString(md5Passwordpassword)

buffer=bytesNewBuffer(nil)

fmtFprintf(bufferxmd5PasswordSum(nil))

newPass=bufferString()

now=timeNow()Format(2006-01-02150405)

userInfo=modelsGetUserInfo(username)

ifuserInfoUsername==

varusersmodelsUser

usersUsername=username

usersPassword=newPass

usersCreated=now

usersLast_logintime=now

modelsAddUser(users)

Setthesessionsuccessfullogin

sess=globalSessionsSessionStart(thisCtxResponseWriterthisCtxRequest)

sessSet(uiduserInfoId)

sessSet(unameuserInfoUsername)

thisCtxRedirect(302)

else

thisData[UsernameErr]=Useralreadyexists

Uservalidation

317

funccheckPassword(passwordstring)(bbool)

ifok_=regexpMatchString(^[a-zA-Z0-9]416$password)ok

returnfalse

returntrue

funccheckUsername(usernamestring)(bbool)

ifok_=regexpMatchString(^[a-zA-Z0-9]416$username)ok

returnfalse

returntrue

Onceyouhaveimplementeduserloginandregistrationothermodulescanbeaddedtodeterminewhethertheuserhasbeenloggedinornot

func(thisAddBlogController)Prepare()

sess=globalSessionsSessionStart(thisCtxResponseWriterthisCtxRequest)

sess_uid=sessGet(userid)

sess_username=sessGet(username)

ifsess_uid==nil

thisCtxRedirect(302adminlogin)

return

thisData[Username]=sess_username

LinksDirectoryPrevioussectionFormNextsectionMulti-languagesupport

Uservalidation

318

145Multi-languagesupportInthechapterwhereweintroducedinternationalizationandlocalizationwedevelopedthego-i18nlibraryInthissectionwewillseehowthislibraryisintegratedintotheBeegoframeworkandhowitenablesourBeegoapplicationstosupportbothinternationalizationandlocalization

I18nintegrationBeegofirstsetssomeglobalvariables

Translationi18nIL

Langstringsetthelanguagepackzhen

LangPathstringsetthelanguagepacklocation

Amulti-languageinitializationfunctionisdefined

funcInitLang()

beegoTranslation=i18nNewLocale()

beegoTranslationLoadPath(beegoLangPath)

beegoTranslationSetLocale(beegoLang)

Inordertofacilitatemulti-languagecallsinthetemplatepackagedirectlywedesignedthreefunctionsforhandlingmulti-languageresponses

Multi-languagesupport

319

beegoTplFuncMap[Trans]=i18nI18nT

beegoTplFuncMap[TransDate]=i18nI18nTimeDate

beegoTplFuncMap[TransMoney]=i18nI18nMoney

funcI18nT(argsinterface)string

ok=false

varsstring

iflen(args)==1

sok=args[0](string)

ifok

s=fmtSprint(args)

returnbeegoTranslationTranslate(s)

funcI18nTimeDate(argsinterface)string

ok=false

varsstring

iflen(args)==1

sok=args[0](string)

ifok

s=fmtSprint(args)

returnbeegoTranslationTime(s)

funcI18nMoney(argsinterface)string

ok=false

varsstring

iflen(args)==1

sok=args[0](string)

ifok

s=fmtSprint(args)

returnbeegoTranslationMoney(s)

Multi-languagedevelopment1 Settingthelanguageandlocationofthelanguagepacktheninitializei18nobjects

beegoLang=zh

beegoLangPath=viewslang

beegoInitLang()

2 Designingamulti-languagepackage

Abovewetalkedabouthowtoinitializeamulti-languagepackageNowletslookathowtodesignoneMulti-languagepackagesaretypicallyJSONfilesasyouvealreadyseeninChapter10WemustprovidetranslationfilesforlanguageswewishtosupportonourLangPathsuchasthefollowing

Multi-languagesupport

320

zhjson

zh

submit提交

create创建

enjson

en

submitSubmit

createCreate

3 Usinglanguagepackages

Wecancallthecontrollertogetthetranslatedresponseinthedesiredlanguagelikeso

func(thisMainController)Get()

thisData[create]=beegoTranslationTranslate(create)

thisTplNames=indextpl

Wecanalsodirectlyinterpolatetranslatedresponsesinourtemplates

DirectTexttranslation

create|Trans

Timetotranslate

time|TransDate

Currencytranslation

money|TransMoney

LinksDirectoryPrevioussectionUservalidationNextsectionpprof

Multi-languagesupport

321

146pprofAgreatfeatureofGosstandardlibraryisitscodeperformancemonitoringtoolsThesepackagesexistintwoplaces

nethttppprof

runtimepprof

InfactnethttppprofsimplyexposesruntimeprofilingdatafromtheruntimepprofpackageonanHTTPport

pprofsupportinBeegoTheBeegoframeworkcurrentlysupportspprofhoweveritisnotturnedonbydefaultIfyouneedtotesttheperformanceofyourapplication(forinstancebyviewingtheexecutiongoroutine)suchinformationfromGosdefaultpackagenethttppprofalreadyhasthisfeatureBecausebeegohasrepackagedtheServHTTPfunctionyoucannotopenthedefaultfeatureincludedinpprofThisresultedinbeegosupportingpprofinternally

FirstinourbeegoRunfunctionwechoosewhetherornottoautomaticallyloadtheperformancepackaccordingtoourconfigurationvariable(inthiscasePprofOn)

ifPprofOn

BeeAppRegisterController(`debugpprof`ampProfController)

BeeAppRegisterController(`debugpprofpp([w]+)`ampProfController)

DesigningProfController

packagebeego

import(

nethttppprof

)

typeProfControllerstruct

Controller

func(thisProfController)Get()

switchthisCtxParams[pp]

default

pprofIndex(thisCtxResponseWriterthisCtxRequest)

case

pprofIndex(thisCtxResponseWriterthisCtxRequest)

casecmdline

pprofCmdline(thisCtxResponseWriterthisCtxRequest)

caseprofile

pprofProfile(thisCtxResponseWriterthisCtxRequest)

casesymbol

pprofSymbol(thisCtxResponseWriterthisCtxRequest)

thisCtxResponseWriterWriteHeader(200)

GettingstartedFromtheabovewecanseethatenablingpprofisassimpleassettingthePprofOnconfigurationvariabletotrue

pprof

322

beegoPprofOn=true

YoucanthenopenthefollowingURLinyourbrowsertoseethefollowinginterface

Figure147currentsystemgoroutineheapthreadinformation

Byclickingonagoroutinewecanseealotofdetailedinformation

Figure148showsthecurrentgoroutinedetails

Ofcoursewecanalsogetmoredetailsfromthecommandline

gotoolpprofhttplocalhost8080debugpprofprofile

Thistimetheprogramwillbeginprofilingtheapplicationforaperiodof30secondsduringwhichtimeitwillrepeatedlyrefreshthepageinthebrowserinanattempttogatherCPUusageandperformancedata

(pprof)top10

Total3samples

13333331333MHeap_AllocLocked

13336671333osexec(Cmd)closeDescriptors

133310001333runtimesigprocmask

00010001333MCentral_Grow

00010002667mainCompile

00010002667maincompile

00010002667mainrun

00010001333makeslice1

00010002667nethttp(ServeMux)ServeHTTP

00010002667nethttp(conn)serve

(pprof)web

Figure149showstheexecutionflowofinformation

LinksDirectoryPrevioussectionMulti-languagesupportNextsectionSummary

pprof

323

147SummaryThischapterillustratessomewaysinwhichtheBeegoframeworkcanbeextendedWefirstlookedatstaticfilesupportlearninghowBeegohandlesservingstaticfilesinternallyWesawhowthisfunctionalityallowedustoeasilyintegratestaticassets(suchasBootstrapsCSSfiles)forrapidandgreatlookingwebsitedevelopmentNextwesawhowtointegratesessionManagertopainlesslyfacilitateusersessionsinBeegoWethendescribedformmanagementandvalidationleveragingGosstructstoreducecoderepetitionandforsimplifyingfieldvalidationAfterthatwediscusseduserauthenticationwhichinvolvedthreemainstrategiesHTTPauthentication(basicanddigest)thirdpartyauthenticationandcustomauthenticationWelearnedaboutsomeexistingthirdpartyauthenticationpackagesthathavealreadyimplementedthesestrategieswhichareconvenientlyaccommodatedbyBeegoThenextsectionre-introducedlanguagesupportinBeegowesawhowtointegratethego-i18npackageandlearnedhowtoeasilyloadmultiplelanguagepacksintoourapplicationsasneededLastlywediscussedhowtoworkwithGospprofpackagesinBeegoThepprofpackageisusedforperformanceprofilinginGoandBeegorepackagesitsoitcanservethesamepurposeinBeegoapplicationswithoutmuchadditionalworkThroughthesesixsectionsweveextendedBeegowithmanyfeaturesmakingitintoaversatileframeworksuitablefortherequirementsofmanywebapplicationsUsershavethefreedomofextendingtheframeworktosuittheirindividualneedsthisbriefintroductiontoBeegosimplyoffersasmalltasteofwhatcanbedone

LinksDirectoryPrevioussectionpprofNextchapterAppendixAReferences

Summary

324

AppendixAReferencesThisbookisasummaryofmyGoexperiencesomecontentarefromotherGopherseitherblogsorsitesThankstothem

1 golangblog2 RussCoxsblog3 gobook4 golangtutorials5 轩脉刃de刀光剑影

6 GoProgrammingLanguage7 NetworkprogrammingwithGo8 setup-the-rails-application-for-internationalization9 TheCross-SiteScripting(XSS)FAQ

References

325

1Goenvironmentconfiguration11Installation12$GOPATHandworkspace13Gocommands14Godevelopmenttools15Summary

2Gobasicknowledge21HelloGo22Gofoundation23Controlstatementsandfunctions24struct25Object-oriented26interface27Concurrency28Summary

3Webfoundation31Webworkingprinciples32Buildasimplewebserver33HowGoworkswithweb34Getintohttppackage35Summary

4Userform41Processforminputs42Verificationofinputs43Crosssitescripting44Duplicatesubmissions45Fileupload46Summary

5Database51databasesqlinterface52MySQL53SQLite54PostgreSQL55DevelopORMbasedonbeedb56NoSQLdatabase57Summary

6Datastorageandsession61Sessionandcookies62HowtousesessioninGo63Sessionstorage64Preventhijackofsession65Summary

7Textfiles71XML72JSON73Regexp74Templates75Files76Strings77Summary

8Webservices81Sockets82WebSocket

preface

326

83REST84RPC85Summary

9Securityandencryption91CSRFattacks92Filterinputs93XSSattacks94SQLinjection95Passwordstorage96Encryptanddecryptdata97Summary

10Internationalizationandlocalization101Timezone102Localizedresources103Internationalsites104Summary

11Errorhandlingdebuggingandtesting111Errorhandling112DebuggingbyusingGDB113Writetestcases114Summary

12Deploymentandmaintenance121Logs122Errorsandcrashes123Deployment124Backupandrecovery125Summary

13Buildawebframework131Projectprogram132Customizedrouters133Designcontrollers134Logsandconfigurations135Adddeleteandupdateblogs136Summary

14Developwebframework141Staticfiles142Session143Form144Uservalidation145Multi-languagesupport146pprof147Summary

AppendixAReferences

preface

327

  • Introduction
  • Go Environment Configuration
    • Installation
    • $GOPATH and workspace
    • Go commands
    • Go development tools
    • Summary
      • Go basic knowledge
        • Hello Go
        • Go foundation
        • Control statements and functions
        • struct
        • Object-oriented
        • interface
        • Concurrency
        • Summary
          • Web foundation
            • Web working principles
            • Build a simple web server
            • How Go works with web
            • Get into http package
            • Summary
              • HTTP Form
                • Process form inputs
                • Validation of inputs
                • Cross site scripting
                • Duplicate submissions
                • File upload
                • Summary
                  • Database
                    • databasesql interface
                    • How to use MySQL
                    • How to use SQLite
                    • How to use PostgreSQL
                    • How to use beedb ORM
                    • NOSQL
                    • Summary
                      • Data storage and session
                        • Session and cookies
                        • How to use session in Go
                        • Session storage
                        • Prevent hijack of session
                        • Summary
                          • Text files
                            • XML
                            • JSON
                            • Regexp
                            • Templates
                            • Files
                            • Strings
                            • Summary
                              • Web services
                                • Sockets
                                • WebSocket
                                • REST
                                • RPC
                                • Summary
                                  • Security and encryption
                                    • CSRF attacks
                                    • Filter inputs
                                    • XSS attacks
                                    • SQL injection
                                    • Password storage
                                    • Encrypt and decrypt data
                                    • Summary
                                      • Internationalization and localization
                                        • Time zone
                                        • Localized resources
                                        • International sites
                                        • Summary
                                          • Error handling debugging and testing
                                            • Error handling
                                            • Debugging by using GDB
                                            • Write test cases
                                            • Summary
                                              • Deployment and maintenance
                                                • Logs
                                                • Errors and crashes
                                                • Deployment
                                                • Backup and recovery
                                                • Summary
                                                  • Build a web framework
                                                    • Project program
                                                    • Customized routers
                                                    • Design controllers
                                                    • Logs and configurations
                                                    • Add delete and update blogs
                                                    • Summary
                                                      • Develop web framework
                                                        • Static files
                                                        • Session
                                                        • Form
                                                        • User validation
                                                        • Multi-language support
                                                        • pprof
                                                        • Summary
                                                          • References
                                                          • preface
Page 3: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write

114

1141

1142

1143

1144

1145

1146

115

1151

1152

1153

1154

1155

1156

1157

116

117

Buildawebframework

Projectprogram

Customizedrouters

Designcontrollers

Logsandconfigurations

Adddeleteandupdateblogs

Summary

Developwebframework

Staticfiles

Session

Form

Uservalidation

Multi-languagesupport

pprof

Summary

References

preface

4

BuildWebApplicationwithGolangPurpose

BecauseIminterestedinwebapplicationdevelopmentIusedmyfreetimetowritethisbookasanopensourceversionItdoesntmeanthatIhaveaverygoodabilitytobuildwebapplicationsIwouldliketosharewhatIvedonewithGoinbuildingwebapplications

ForthoseofyouwhoareworkingwithPHPPythonRubyyouwilllearnhowtobuildawebapplicationwithGoForthoseofyouwhoareworkingwithCC++youwillknowhowthewebworks

IbelievethepurposeofstudyingissharingwithothersThehappiestthinginmylifeissharingeverythingIveknownwithmorepeople

Donate

AliPay

alipay

EnglishDonatedonate

CommunityQQ群386056972

BBShttpgocnio

Acknowledgments四月份平民AprilCitizen(reviewcode)洪瑞琦HongRuiqi(reviewcode)边疆BianJiang(writetheconfigurationsaboutVimandEmacsforGodevelopment)欧林猫OlingCat(reviewcode)吴文磊WenleiWu(providesomepictures)北极星Polaris(reviewwholebook)雨痕RainTrail(reviewchapter2and3)

LicenseThisbookislicensedundertheCCBY-SA30LicensethecodeislicensedunderaBSD3-ClauseLicenseunlessotherwisespecified

GetStarted

Index

Introduction

5

Introduction

6

1GoEnvironmentConfigurationWelcometotheworldofGoletsstartexploring

Goisafast-compiledgarbage-collectedconcurrentsystemsprogramminglanguageIthasthefollowingadvantages

CompilesalargeprojectwithinafewsecondsProvidesasoftwaredevelopmentmodelthatiseasytoreasonaboutavoidingmostoftheproblemsassociatedwithC-styleheaderfilesIsastaticlanguagethatdoesnothavelevelsinitstypesystemsousersdonotneedtospendmuchtimedealingwithrelationsbetweentypesItismorelikealightweightobject-orientedlanguagePerformsgarbagecollectionItprovidesbasicsupportforconcurrencyandcommunicationDesignedformulti-corecomputers

GoisacompiledlanguageItcombinesthedevelopmentefficiencyofinterpretedordynamiclanguageswiththesecurityofstaticlanguagesItisgoingtobethelanguageofchoiceformodernmulti-corecomputerswithnetworkingForthesepurposestherearesomeproblemsthatneedtoinherentlyberesolvedatthelevelofthelanguageofchoicesuchasarichlyexpressivelightweighttypesystemanativeconcurrencymodelandstrictlyregulatedgarbagecollectionForquitesometimenopackagesortoolshaveemergedthathaveaimedtosolvealloftheseproblemsinapragmaticfashionthuswasbornthemotivationfortheGolanguage

InthischapterIwillshowyouhowtoinstallandconfigureyourownGodevelopmentenvironment

LinksDirectoryNextsectionInstallation

GoEnvironmentConfiguration

7

11Installation

ThreewaystoinstallGoTherearemanywaystoconfiguretheGodevelopmentenvironmentonyourcomputerandyoucanchoosewhicheveroneyoulikeThethreemostcommonwaysareasfollows

OfficialinstallationpackagesTheGoteamprovidesconvenientinstallationpackagesinWindowsLinuxMacandotheroperatingsystemsThisisprobablytheeasiestwaytogetstartedYoucangettheinstallersfromtheGolangDownloadPage

InstallityourselffromsourcecodePopularwithdeveloperswhoarefamiliarwithUnix-likesystems

Usingthird-partytoolsTherearemanythird-partytoolsandpackagemanagersforinstallingGolikeapt-getinUbuntuandhomebrewforMac

IncaseyouwanttoinstallmorethanoneversionofGoonacomputeryoushouldtakealookatatoolcalledGVMItisthebesttoolIveseensofarforaccomplishingthistaskotherwiseyoudhavetodealwithityourself

InstallfromsourcecodeTocompileGo15andupwardsyouonlyneedthepreviousversionofGoasGohasachievedbootstrappingYouonlyneedGotocompileGo

TocompileGo14downwardsyouwillneedaCcompilerassomepartsofGoarestillwritteninPlan9CandATampTassembler

OnaMacifyouhaveinstalledXcodeyoualreadyhavethecompiler

OnUnix-likesystemsyouneedtoinstallgccorasimilarcompilerForexampleusingthepackagemanagerapt-get(includedwithUbuntu)onecaninstalltherequiredcompilersasfollows

sudoapt-getinstallgcclibc6-dev

OnWindowsyouneedtoinstallMinGWinordertoinstallgccDontforgettoconfigureyourenvironmentvariablesaftertheinstallationhascompleted(EverythingthatlookslikethismeansitscommentedbyatranslatorIfyouareusing64-bitWindowsyoushouldinstallthe64-bitversionofMinGW)

AtthispointexecutethefollowingcommandstoclonetheGosourcecodeandcompileit(ItwillclonethesourcecodetoyourcurrentdirectorySwitchyourworkpathbeforeyoucontinueThismaytakesometime)

gitclonehttpsgogooglesourcecomgo

cdgosrc

allbash

AsuccessfulinstallationwillendwiththemessageALLTESTSPASSED

OnWindowsyoucanachievethesamebyrunningallbat

IfyouareusingWindowstheinstallationpackagewillsetyourenvironmentvariablesautomaticallyInUnix-likesystemsyouneedtosetthesevariablesmanuallyasfollows(IfyourGoversionisgreaterthan10youdonthavetoset$GOBINanditwillautomaticallyberelatedtoyour$GOROOTbinwhichwewilltalkaboutinthenextsection)

Installation

8

exportGOROOT=$HOMEgo

exportGOBIN=$GOROOTbin

exportPATH=$PATH$GOROOTbin

Ifyouseethefollowinginformationonyourscreenyoureallset

Figure11Informationafterinstallingfromsourcecode

OnceyouseetheusageinformationofGoitmeansyouhavesuccessfullyinstalledGoonyourcomputerIfitsaysnosuchcommandcheckthatyour$PATHenvironmentvariablecontainstheinstallationpathofGo

UsingthestandardinstallationpackagesGohasone-clickinstallationpackagesforeverysupportedoperatingsystemThesepackageswillinstallGoinusrlocalgo(cGoinWindows)bydefaultOfcoursethiscanbemodifiedbutyoualsoneedtochangealltheenvironmentvariablesmanuallyasIveshownabove

Howtocheckifyouroperatingsystemis32-bitor64-bit

Ournextstepdependsonyouroperatingsystemtypesowehavetocheckitbeforewedownloadthestandardinstallationpackages

IfyouareusingWindowspressWin+RandthenrunthecommandtoolTypethesysteminfocommandanditwillshowyousomeusefulsysteminformationFindthelinethatsayssystemtype-ifyouseex64-basedPCthatmeansyouroperatingsystemis64-bit32-bitotherwise

Istronglyrecommenddownloadingthe64-bitpackageifyouareaMacuserasGonolongersupportspure32-bitprocessorsonMacOSX

Linuxuserscantypeuname-aintheterminaltoseesysteminformationA64-bitoperatingsystemwillshowthefollowing

ltsomedescriptiongtx86_64x86_64x86_64GNULinux

somemachinessuchasUbuntu1004willshowasfollowing

x86_64GNULinux

32-bitoperatingsystemsinsteadshow

ltsomedescriptiongti686i686i386GNULinux

Mac

Gotothedownloadpagechoosego142darwin-386pkg(Thelaterversionhasno32-bitdownload)for32-bitsystemsandgo183darwin-amd64pkgfor64-bitsystemsGoingallthewaytotheendbyclickingnext~gobinwillbeaddedtoyoursystems$PATHafteryoufinishtheinstallationNowopentheterminalandtypegoYoushouldseethesameoutputshowninfigure11

Linux

Gotothedownloadpagechoosego183linux-386targzfor32-bitsystemsandgo183linux-amd64targzfor64-bitsystemsSupposeyouwanttoinstallGointhe$GO_INSTALL_DIRpathUncompressthetargztoyourchosenpathusingthecommandtarzxvfgo183linux-amd64targz-C$GO_INSTALL_DIRThensetyour$PATHwiththefollowingexportPATH=$PATH$GO_INSTALL_DIRgobinNowjustopentheterminalandtypegoYoushouldnowseethesameoutputdisplayedinfigure11

Installation

9

Windows

Gotothedownloadpagechoosego183windows-386msifor32-bitsystemsandgo183windows-amd64msifor64-bitsystemsGoingallthewaytotheendbyclickingnextcgobinwillbeaddedtopathNowjustopenacommandlinewindowandtypegoYoushouldnowseethesameoutputdisplayedinfigure11

Usethird-partytools

GVM

GVMisaGomulti-versioncontroltooldevelopedbyathird-partylikervmforrubyItsquiteeasytouseInstallgvmbytypingthefollowingcommandsinyourterminal

bashltlt(curl-s-S-Lhttpsrawgithubcommoovwebgvmmasterbinscriptsgvm-installer)

ThenweinstallGousingthefollowingcommands

gvminstallgo183

gvmusego183

Aftertheprocesshasfinishedyoureallset

apt-get

UbuntuisthemostpopulardesktopreleaseversionofLinuxItusesapt-gettomanagepackagesWecaninstallGousingthefollowingcommands

sudoadd-apt-repositoryppagophersgo

sudoapt-getupdate

sudoapt-getinstallgolang-go

wget

wgethttpsstoragegoogleapiscomgolanggo183linux-amd64targz

sudotar-xzfgo183linux-amd64targz-Cusrlocal

Goenvironment

exportGOROOT=usrlocalgo

exportGOBIN=$GOROOTbin

exportPATH=$PATH$GOBIN

exportGOPATH=$HOMEgopath

Startingfromgo18TheGOPATHenvironmentvariablenowhasadefaultvalueifitisunsetItdefaultsto$HOMEgoonUnixandUSERPROFILEgoonWindows

HomebrewHomebrewisasoftwaremanagementtoolcommonlyusedinMactomanagepackagesJusttypethefollowingcommandstoinstallGo

1 InstallHomebrew

usrbinruby-e$(curl-fsSLhttpsrawgithubusercontentcomHomebrewinstallmasterinstall)

Installation

10

1 InstallGo

brewupdateampampbrewupgrade

brewinstallgo

LinksDirectoryPrevioussectionGoenvironmentconfigurationNextsection$GOPATHandworkspace

Installation

11

12$GOPATHandworkspace

$GOPATHGotakesauniqueapproachtomanagethecodefileswiththeintroductionofa$GOPATHdirectorywhichcontainsallthegocodeinthemachineNotethatthisisdifferentfromthe$GOROOTenvironmentvariablewhichstateswheregoisinstalledonthemachineWehavetodefinethe$GOPATHvariablebeforeusingthelanguageinnixsystemsthereisafilecalledprofileweneedtoappendthebelowexportstatementtothefileTheconceptbehindgopathisanovelonewherewecanlinktoanygocodeatanyinstantoftimewithoutambiguity

Startingfromgo18theGOPATHenvironmentvariablenowhasadefaultvalueifitisunsetItdefaultsto$HOMEgoonUnixandUSERPROFILEgoonWindows

InUnix-likesystemsthevariableshouldbeusedlikethis

exportGOPATH=$HOMEmygo

InWindowsyouneedtocreateanewenvironmentvariablecalledGOPATHthensetitsvaluetocmygo(Thisvaluedependsonwhereyourworkspaceislocated)

ItsOKtohavemorethanonepath(workspace)in$GOPATHbutrememberthatyouhavetouse(inWindows)tobreakthemupAtthispointgogetwillsavethecontenttoyourfirstpathin$GOPATHItishighlyrecommendedtonothavemultiplesversionstheworstcaseistocreateafolderbythenameofyourprojectrightinside$GOPATHitbreakseverythingthatthecreatorswerewishingtochangeinprogrammingwiththecreationofgolanguagebecausewhenyoucreateafolderinside$GOPATHyouwillreferenceyourpackagesasdirectlyasandthisbreaksalltheapplicationswhichwillimportyourpackagebecausethegogetwontfindyourpackagePleasefollowconventionsthereisareasonconventionsarecreated

In$GOPATHyoumusthavethreefoldersasfollows

srcforsourcefileswhosesuffixisgocgspkgforcompiledfileswhosesuffixisabinforexecutablefiles

InthisbookIusemygoasmyonlypathin$GOPATH

PackagedirectoryCreatepackagesourcefilesandfolderslike$GOPATHsrcmymathsqrtgo(mymathisthepackagename)(Authorusesmymathashispackagenameandthesamenameforthefolderthatcontainsthepackagesourcefiles)

EverytimeyoucreateapackageyoushouldcreateanewfolderinthesrcdirectorywiththenotableexceptionofmainforwhichmainfoldercreationisoptionalFoldernamesareusuallythesameasthepackagethatyouaregoingtouseYoucanhavemulti-leveldirectoriesifyouwanttoForexampleifyoucreatethedirectory$GOPATHsrcgithubcomastaxiebeedbthenthepackagepathwouldbegithubcomastaxiebeedbThepackagenamewillbethelastdirectoryinyourpathwhichisbeedbinthiscase

Executefollowingcommands(Nowauthorgoesbacktotalkexamples)

cd$GOPATHsrc

mkdirmymath

Createanewfilecalledsqrtgotypethefollowingcontenttoyourfile

$GOPATHandworkspace

12

Sourcecodeof$GOPATHsrcmymathsqrtgo

packagemymath

funcSqrt(xfloat64)float64

z=00

fori=0ilt1000i++

z-=(zz-x)(2x)

returnz

NowmypackagedirectoryhasbeencreatedanditscodehasbeenwrittenIrecommendthatyouusethesamenameforyourpackagesastheircorrespondingdirectoriesandthatthedirectoriescontainallofthepackagesourcefiles

CompilepackagesWevealreadycreatedourpackageabovebuthowdowecompileitforpracticalpurposesTherearetwowaystodothis

1 Switchyourworkpathtothedirectoryofyourpackagethenexecutethegoinstallcommand2 Executetheabovecommandexceptwithafilenamelikegoinstallmymath

Aftercompilingwecanopenthefollowingfolder

cd$GOPATHpkg$GOOS_$GOARCH

youcanseethefilewasgenerated

mymatha

ThefilewhosesuffixisaisthebinaryfileofourpackageHowdoweuseit

Obviouslyweneedtocreateanewapplicationtouseit

Createanewapplicationpackagecalledmathapp

cd$GOPATHsrc

mkdirmathapp

cdmathapp

vimmaingo

Writethefollowingcontenttomaingo

$GOPATHsrcmathappmaingosourcecode

packagemain

import(

mymath

fmt

)

funcmain()

fmtPrintf(HelloworldSqrt(2)=vnmymathSqrt(2))

Tocompilethisapplicationyouneedtoswitchtotheapplicationdirectorywhichinthiscaseis$GOPATHsrcmathappthenexecutethegoinstallcommandNowyoushouldseeanexecutablefilecalledmathappwasgeneratedinthedirectory$GOPATHbinTorunthisprogramusethemathappcommandYoushouldseethefollowingcontentinyourterminal

HelloworldSqrt(2)=1414213562373095

$GOPATHandworkspace

13

InstallremotepackagesGohasatoolforinstallingremotepackageswhichisacommandcalledgogetItsupportsmostopensourcecommunitiesincludingGithubGoogleCodeBitBucketandLaunchpad

gogetgithubcomastaxiebeedb

Youcanusegoget-uhelliptoupdateyourremotepackagesanditwillautomaticallyinstallallthedependentpackagesaswell

ThistoolwillusedifferentversioncontroltoolsfordifferentopensourceplatformsForexamplegitforGithubandhgforGoogleCodeThereforeyouhavetoinstalltheseversioncontroltoolsbeforeyouusegoget

Afterexecutingtheabovecommandsthedirectorystructureshouldlooklikefollowing

$GOPATH

src

|-githubcom

|-astaxie

|-beedb

pkg

|--$GOOS_$GOARCH

|-githubcom

|-astaxie

|-beedba

Actuallygogetclonessourcecodetothe$GOPATHsrcofthelocalfilesystemthenexecutesgoinstall

Youcanuseremotepackagesinthesamewaythatweuselocalpackages

importgithubcomastaxiebeedb

DirectorycompletestructureIfyouvefollowedalloftheabovestepsyourdirectorystructureshouldnowlooklikethefollowing

bin

mathapp

pkg

$GOOS_$GOARCHsuchasdarwin_amd64linux_amd64

mymatha

githubcom

astaxie

beedba

src

mathapp

maingo

mymath

sqrtgo

githubcom

astaxie

beedb

beedbgo

utilgo

Nowyouareabletoseethedirectorystructureclearlybincontainsexecutablefilespkgcontainscompiledfilesandsrccontainspackagesourcefiles

(TheformatofenvironmentvariablesinWindowsisGOPATHhoweverthisbookmainlyfollowstheUnix-stylesoWindowsusersneedtoreplacetheseyourself)

$GOPATHandworkspace

14

LinksDirectoryPrevioussectionInstallationNextsectionGocommands

$GOPATHandworkspace

15

13Gocommands

GocommandsTheGolanguagecomeswithacompletesetofcommandoperationtoolsYoucanexecutethegocommandontheterminaltoseethem

Figure13Gocommanddisplaysdetailedinformation

TheseareallusefulforusLetsseehowtousesomeofthem

gobuildThiscommandisforcompilingtestsItwillcompilepackagesanddependenciesifitsnecessary

Ifthepackageisnotthemainpackagesuchasmymathinsection12nothingwillbegeneratedafteryouexecutegobuildIfyouneedthepackagefileain$GOPATHpkgusegoinstallinsteadIfthepackageisthemainpackageitwillgenerateanexecutablefileinthesamefolderIfyouwantthefiletobegeneratedin$GOPATHbinusegoinstallorgobuild-o$PATH_HEREaexeIftherearemanyfilesinthefolderbutyoujustwanttocompileoneofthemyoushouldappendthefilenameaftergobuildForexamplegobuildagogobuildwillcompileallthefilesinthefolderYoucanalsoassignthenameofthefilethatwillbegeneratedForinstanceinthemathappproject(insection12)usinggobuild-oastaxieexewillgenerateastaxieexeinsteadofmathappexeThedefaultnameisyourfoldername(non-mainpackage)orthefirstsourcefilename(mainpackage)

(AccordingtoTheGoProgrammingLanguageSpecificationpackagenamesshouldbethenameafterthewordpackageinthefirstlineofyoursourcefilesItdoesnthavetobethesameasthefoldernameandtheexecutablefilenamewillbeyourfoldernamebydefault)

gobuildignoresfileswhosenamesstartwith_orIfyouwanttohavedifferentsourcefilesforeveryoperatingsystemyoucannamefileswiththesystemnameasasuffixSupposetherearesomesourcefilesforloadingarraysTheycouldbenamedasfollows

array_linuxgo|array_darwingo|array_windowsgo|array_freebsdgo

gobuildchoosestheonethatsassociatedwithyouroperatingsystemForexampleitonlycompilesarray_linuxgoinLinuxsystemsandignoresalltheothers

gocleanThiscommandisforcleaningfilesthataregeneratedbycompilersincludingthefollowingfiles

_objolddirectoryofobjectleftbyMakefiles

_testolddirectoryoftestleftbyMakefiles

_testmaingoolddirectoryofgotestleftbyMakefiles

testoutolddirectoryoftestleftbyMakefiles

buildoutolddirectoryoftestleftbyMakefiles

[568ao]objectfilesleftbyMakefiles

DIR(exe)generatedbygobuild

DIRtest(exe)generatedbygotest-c

MAINFILE(exe)generatedbygobuildMAINFILEgo

Gocommands

16

IusuallyusethiscommandtocleanupmyfilesbeforeIuploadmyprojecttoGithubTheseareusefulforlocaltestsbutuselessforversioncontrol

gofmtandgofmtThepeoplewhoareworkingwithCC++shouldknowthatpeoplearealwaysarguingaboutwhichcodestyleisbetterKampR-styleorANSI-styleHoweverinGothereisonlyonecodestylewhichisenforcedForexampleleftbracesmustonlybeinsertedattheendoflinesandtheycannotbeontheirownlinesotherwiseyouwillgetcompileerrorsFortunatelyyoudonthavetoremembertheserulesgofmtdoesthisjobforyouJustexecutethecommandgofmtltFilenamegtgointerminalIdontusethiscommandverymuchbecauseIDEsusuallyexecutethiscommandautomaticallywhenyousavesourcefilesIwilltalkmoreaboutIDEsinthenextsection

gofmtisjustanaliaswhichrunsthecommandgofmt-l-wonthepackagesnamedbytheimportpaths

Weusuallyusegofmt-winsteadofgofmtThelatterwillnotrewriteyoursourcefilesafterformattingcodegofmt-wsrcformatsthewholeproject

gogetThiscommandisforgettingremotepackagesSofaritsupportsBitBucketGithubGoogleCodeandLaunchpadThereareactuallytwothingsthathappenafterweexecutethiscommandThefirstthingisthatGodownloadsthesourcecodethenexecutesgoinstallBeforeyouusethiscommandmakesureyouhaveinstalledalloftherelatedtools

BitBucket(MercurialGit)

Github(git)

GoogleCode(GitMercurialSubversion)

Launchpad(Bazaar)

InordertousethiscommandyouhavetoinstallthesetoolscorrectlyDontforgettoupdatethe$PATHvariableBythewayitalsosupportscustomizeddomainnamesUsegohelpimportpathformoredetailsaboutthis

goinstallThiscommandcompilesallpackagesandgeneratesfilesthenmovesthemto$GOPATHpkgor$GOPATHbin

gotestThiscommandloadsallfileswhosenameinclude_testgoandgeneratestestfilesthenprintsinformationthatlookslikethefollowing

okarchivetar0011s

FAILarchivezip0022s

okcompressgzip0033s

IttestsallyourtestfilesbydefaultUsecommandgohelptestflagformoredetails

godocManypeoplesaythatwedontneedanythird-partydocumentationforprogramminginGo(actuallyIvemadeaCHMalready)Gohasapowerfultooltomanagedocumentationnatively

Gocommands

17

SohowdowelookuppackageinformationindocumentationForinstanceifyouwanttogetmoredetailsaboutthebuiltinpackageusethegodocbuiltincommandSimilarlyusethegodocnethttpcommandtolookupthehttppackagedocumentationIfyouwanttoseemoredetailsaboutspecificfunctionsusethegodocfmtPrintfandgodoc-srcfmtPrintfcommandstoviewthesourcecode

Executethegodoc-http=8080commandthenopen1270018080inyourbrowserYoushouldseealocalizedgolangorgItcannotonlyshowthestandardpackagesinformationbutalsopackagesinyour$GOPATHpkgItsgreatforpeoplewhoaresufferingfromtheGreatFirewallofChina

OthercommandsGoprovidesmorecommandsthanthosewevejusttalkedabout

gofixupgradecodefromanoldversionbeforego1toanewversionaftergo1

goversiongetinformationaboutyourversionofGo

goenvviewenvironmentvariablesaboutGo

golistlistallinstalledpackages

goruncompiletemporaryfilesandruntheapplication

TherearealsomoredetailsaboutthecommandsthatIvetalkedaboutYoucanusegohelpltcommandgttolookthemup

LinksDirectoryPrevioussection$GOPATHandworkspaceNextsectionGodevelopmenttools

Gocommands

18

GodevelopmenttoolsInthissectionImgoingtoshowyouafewIDEsthatcanhelpyoubecomeamoreefficientprogrammerwithcapabilitiessuchasintelligentcodecompletionandauto-formattingTheyareallcross-platformsothestepsIwillbeshowingyoushouldnotbeverydifferentevenifyouarenotusingthesameoperatingsystem

LiteIDELiteIDEisanopensourcelightweightIDEfordevelopingGoprojectsonlydevelopedbyvisualfc

Figure14MainpanelofLiteIDE

LiteIDEfeatures

Cross-platformWindowsLinuxMacOS

Cross-compileManagemultiplecompileenvironmentsSupportscross-compilationofGo

ProjectmanagementstandardDocumentationviewbasedon$GOPATHCompilationsystembasedon$GOPATHAPIdocumentationindexbasedon$GOPATH

GosourcecodeeditorCodeoutliningFullsupportofgocodeGodocumentationviewandAPIindexViewcodeexpressionusingF1FunctiondeclarationjumpusingF2GdbsupportAuto-formatwithgofmt

OthersMulti-languagePluginsystemTexteditorthemesSyntaxsupportbasedonKateintelligentcompletionbasedonfull-textCustomizedshortcutsMarkdownsupport

Real-timepreviewCustomizedCSSExportHTMLandPDFConvertandmergetoHTMLandPDF

LiteIDEinstallationInstallLiteIDE

Downloadpage

Godevelopmenttools

19

Sourcecode

YouneedtoinstallGofirstthendownloadtheversionappropriateforyouroperatingsystemDecompressthepackagetodirectlyuseit

Installgocode

Youhavetoinstallgocodeinordertouseintelligentcompletion

goget-ugithubcomnsfgocode

Compilationenvironment

SwitchconfigurationinLiteIDEtosuityouroperatingsystemInWindowsandusingthe64-bitversionofGoyoushouldchoosewin64astheconfigurationenvironmentinthetoolbarThenchooseOptionsfindLiteEnvintheleftlistandopenfilewin64envintherightlist

GOROOT=cgo

GOBIN=

GOARCH=amd64

GOOS=windows

CGO_ENABLED=1

PATH=GOBINGOROOTbinPATH

ReplaceGOROOT=cgotoyourGoinstallationpathsaveitIfyouhaveMinGW64addcMinGW64bintoyourpathenvironmentvariableforcgosupport

InLinuxandusingthe64-bitversionofGoyoushouldchooselinux64astheconfigurationenvironmentinthetoolbarThenchooseOptionsfindLiteEnvintheleftlistandopenthelinux64envfileintherightlist

GOROOT=$HOMEgo

GOBIN=

GOARCH=amd64

GOOS=linux

CGO_ENABLED=1

PATH=$GOBIN$GOROOTbin$PATH

ReplaceGOROOT=$HOMEgotoyourGoinstallationpathsaveit

$GOPATH$GOPATHisthepaththatcontainsalistofprojectsOpenthecommandtool(orpressCtrl+`inLiteIDE)thentypegohelpgopathformoredetailsItsveryeasytoviewandchange$GOPATHinLiteIDEFollowView-SetupGOPATHtoviewandchangethesevalues

SublimeTextHereImgoingtointroduceyoutheSublimeText3(Sublimeforshort)+GoSublime+gocodeLetmeexplainwhy

Intelligentcompletion

Figure15Sublimeintelligentcompletion

Auto-formatsourcefilesProjectmanagement

Godevelopmenttools

20

Figure16Sublimeprojectmanagement

Syntaxhighlight

FreetrialforeverwithnofunctionallimitationsYoumaybepromptedonceinawhiletoremindyoutopurchasealicensebutyoucansimplyignoreitifyouwishOfcourseifyoudofindthatitenhancesyourproductivityandyoureallyenjoyusingitpleasepurchaseacopyofitandsupportitscontinueddevelopment

FirstdownloadtheversionofSublimesuitableforyouroperatingsystem

1 PressCtrl+`openthecommandtoolandinputthefollowingcommands

ApplicabletoSublimeText3

importurllibrequestospf=PackageControlsublime-packageipp=sublimeinstalled_packages_path()urllibrequesti

nstall_opener(urllibrequestbuild_opener(urllibrequestProxyHandler()))open(ospathjoin(ipppf)wb)write(urlli

brequesturlopen(httpsublimewbondnet+pfreplace(20))read())

ApplicabletoSublimeText2

importurllib2ospf=PackageControlsublime-packageipp=sublimeinstalled_packages_path()osmakedirs(ipp)ifnotos

pathexists(ipp)elseNoneurllib2install_opener(urllib2build_opener(urllib2ProxyHandler()))open(ospathjoin(ipp

pf)wb)write(urllib2urlopen(httpsublimewbondnet+pfreplace(20))read())print(PleaserestartSubl

imeTexttofinishinstallation)

RestartSublimeTextwhentheinstallationhasfinishedYoushouldthenfinda`PackageControl`optioninthePref

erencesmenu

[](images14sublime3pngraw=true)

Figure17SublimePackageControl

1 ToinstallGoSublimeSidebarEnhancementsandGoBuildpressCtrl+Shift+ptoopenPackageControlthentypepcip(shortforPackageControlInstallPackage)

Figure18SublimeInstallPackages

NowtypeinGoSublimepressOKtoinstallthepackageandrepeatthesamestepsforinstallingSidebarEnhancementsandGoBuildOnceagainrestarttheeditorwhenitcompletestheinstallation

2 ToverifythattheinstallationissuccessfulopenSublimethenopenthemaingofiletoseeifithasthepropersyntaxhighlightingTypeimporttoseeifcodecompletionpromptsappearAftertypingimportfmttypefmtanywhereaftertheimportdeclarationtoseewhetherornotintelligentcodecompletionforfunctionswassuccessfullyenabled

Ifeverythingisfineyoureallset

Ifnotcheckyour$PATHagainOpenaterminaltypegocodeIfitdoesnotrunyour$PATHwasnotconfiguredcorrectly

VimVimisapopulartexteditorforprogrammerswhichevolvedfromitsslimmerpredecessorViIthasfunctionsforintelligentcompletioncompilationandjumpingtoerrors

vim-goisvimaboveanopen-sourcegolanguageusingthemostextensivedevelopmentenvironmentplug-ins

Thepluginaddressgithubcomfatihvim-go

Godevelopmenttools

21

VimpluginmanagementarethemainstreamPathogenandVundleButtheaspectsthereofaredifferentPathogenistosolveeachplug-inaftertheinstallationoffilesscatteredtomultipledirectoriesandpoormanagementoftheexistenceVundleistosolvetheautomaticsearchanddownloadplug-insexistThesetwoplug-inscanbeusedsimultaneously

1InstallVundle

mkdir~vimbundle

gitclonehttpsgithubcomgmarikVundlevimgit~vimbundleVundlevim

EditvimrcVundletherelevantconfigurationwillbeplacedinthebeginning(RefertotheVundledocumentationfordetails)

setnocompatiblebeiMprovedrequired

filetypeoffrequired

settheruntimepathtoincludeVundleandinitialize

setrtp+=~vimbundleVundlevim

callvundlebegin()

letVundlemanageVundlerequired

PlugingmarikVundlevim

AllofyourPluginsmustbeaddedbeforethefollowingline

callvundleend()required

filetypepluginindentonrequired

2InstallVim-go

Edit~vimrcAddalinebetweenvundlebeginandvundleend

Pluginfatihvim-go

ExecutedwithinVimPluginInstall

3InstallYCM(YourCompleteMe)toAutoCompleteAddalineto~vimrc

PluginValloricYouCompleteMe

ExecutedwithinVimPluginInstall

Figure18VimintelligentcompletionforGo

1 SyntaxhighlightingforGo

cp-r$GOROOTmiscvim~vim

2 Enablingsyntaxhighlighting

filetypepluginindenton

syntaxon

3 Installgocode

goget-ugithubcomnsfgocode

gocodewillbeinstalledin$GOBINasdefault

Godevelopmenttools

22

4 Configuregocode

~cd$GOPATHsrcgithubcomnsfgocodevim

~updatesh

~gocodesetpropose-builtinstrue

propose-builtinstrue

~gocodesetlib-pathhomebordergocodepkglinux_amd64

lib-pathhomebordergocodepkglinux_amd64

~gocodeset

propose-builtinstrue

lib-pathhomebordergocodepkglinux_amd64

Explanationofgocodeconfiguration

propose-builtinsspecifieswhetherornottoopenintelligentcompletionfalsebydefaultlib-pathgocodeonlysearchesforpackagesin$GOPATHpkg$GOOS_$GOARCHand$GOROOTpkg$GOOS_$GOARCHThissettingcanbeusedtoaddadditionalpaths

5 CongratulationsTryemaingotoexperiencetheworldofGo

EmacsEmacsistheso-calledWeaponofGodSheisnotonlyaneditorbutalsoapowerfulIDE

Figure110EmacsmainpanelofGoeditor

1 Syntaxhighlighting

cp$GOROOTmiscemacs~emacsd

2 Installgocode

goget-ugithubcomnsfgocode

gocodewillbeinstalledin$GOBINasdefault

3 Configuregocode

~cd$GOPATHsrcgithubcomnsfgocodevim

~updatebash

~gocodesetpropose-builtinstrue

propose-builtinstrue

~gocodesetlib-pathhomebordergocodepkglinux_amd64

lib-pathhomebordergocodepkglinux_amd64

~gocodeset

propose-builtinstrue

lib-pathhomebordergocodepkglinux_amd64

4 InstallAutoCompletionDownloadanduncompress

~makeinstallDIR=$HOMEemacsdauto-complete

Configure~emacsfile

Godevelopmenttools

23

auto-complete

(requireauto-complete-config)

(add-to-listac-dictionary-directories~emacsdauto-completeac-dict)

(ac-config-default)

(local-set-key(kbdM-)semantic-complete-analyze-inline)

(local-set-keysemantic-complete-self-insert)

(local-set-keygtsemantic-complete-self-insert)

Followthislinkformoredetails

5 Configureemacs

golangmode

(requirego-mode-load)

(requirego-autocomplete)

speedbar

(speedbar1)

(speedbar-add-supported-extensiongo)

(add-hook

go-mode-hook

(lambda()

gocode

(auto-complete-mode1)

(setqac-sources(ac-source-go))

ImenuampSpeedbar

(setqimenu-generic-expression

((type^type([^tnrf])1)

(func^func()1)))

(imenu-add-to-menubarIndex)

Outlinemode

(make-local-variableoutline-regexp)

(setqoutline-regexp|[^rnf][^rnf]|pack|func|impo|cons|var|type|tt)

(outline-minor-mode1)

(local-set-keyM-aoutline-previous-visible-heading)

(local-set-keyM-eoutline-next-visible-heading)

Menubar

(requireeasymenu)

(defconstgo-hooked-menu

(Gotools

[Gorunbuffergot]

[Goreformatbuffergo-fmt-buffert]

[Gocheckbuffergo-fix-buffert]))

(easy-menu-define

go-added-menu

(current-local-map)

Gotools

go-hooked-menu)

Other

(setqshow-trailing-whitespacet)

))

helperfunction

(defungo()

runcurrentbuffer

(interactive)

(compile(concatgorun(buffer-file-name))))

helperfunction

(defungo-fmt-buffer()

rungofmtoncurrentbuffer

(interactive)

(ifbuffer-read-only

(progn

(ding)

(messageBufferisreadonly))

(let((p(line-number-at-pos))

(filename(buffer-file-name))

(old-max-mini-window-heightmax-mini-window-height))

(show-all)

(if(get-bufferGoReformatErrors)

Godevelopmenttools

24

(progn

(delete-windows-onGoReformatErrors)

(kill-bufferGoReformatErrors)))

(setqmax-mini-window-height1)

(if(=0(shell-command-on-region(point-min)(point-max)gofmtGoReformatOutputnilGoRefor

matErrorst))

(progn

(erase-buffer)

(insert-buffer-substringGoReformatOutput)

(goto-char(point-min))

(forward-line(1-p)))

(with-current-bufferGoReformatErrors

(progn

(goto-char(point-min))

(while(re-search-forwardltstandardinputgtnilt)

(replace-matchfilename))

(goto-char(point-min))

(compilation-mode))))

(setqmax-mini-window-heightold-max-mini-window-height)

(delete-windows-onGoReformatOutput)

(kill-bufferGoReformatOutput))))

helperfunction

(defungo-fix-buffer()

rungofixoncurrentbuffer

(interactive)

(show-all)

(shell-command-on-region(point-min)(point-max)gotoolfix-diff))

6 CongratulationsyouredoneSpeedbarisclosedbydefault-removethecommentsymbolsintheline(speedbar1)toenablethisfeatureoryoucanuseitthroughM-xspeedbar

EclipseEclipseisalsoagreatdevelopmenttoolIllshowyouhowtouseittowriteGoprograms

Figure11EclipsemainpanelforeditingGo

1 DownloadandinstallEclipse2 DownloadgoclipsehttpcodegooglecompgoclipsewikiInstallationInstructions3 Downloadgocode

gocodeinGithub

httpsgithubcomnsfgocode

YouneedtoinstallgitinWindowsusuallyweusemsysgit

Installgocodeinthecommandtool

goget-ugithubcomnsfgocode

Youcaninstallfromsourcecodeifyoulike

4 DownloadandinstallMinGW5 Configureplugins

Windows-gtPreferences-gtGo

(1)ConfigureGocompiler

Godevelopmenttools

25

Figure112GoSettinginEclipse

(2)Configuregocode(optional)setgocodepathtowherethegocodeexeis

Figure113gocodeSetting

(3)Configuregdb(optional)setgdbpathtowherethegdbexeis

Figure114gdbSetting

6 Checktheinstallation

CreateanewGoprojectandhellogofileasfollowing

Figure115Createanewprojectandfile

Testinstallationasfollows(youneedtotypecommandinconsoleinEclipse)

Figure116TestGoprograminEclipse

IntelliJIDEAPeoplewhohaveworkedwithJavashouldbefamiliarwiththisIDEItsupportsGosyntaxhighlightingandintelligentcodecompletionimplementedbyaplugin

1 DownloadIDEAthereisnodifferencebetweentheUltimateandCommunityeditions

2 InstalltheGopluginChooseFile-Setting-PluginsthenclickBrowserrepo

3 Searchgolangdoubleclickdownloadandinstallandwaitforthedownloadtocomplete

ClickApplythenrestart

4 NowyoucancreateaGoproject

InputthepositionofyourGosdkinthenextstep-basicallyitsyour$GOROOT

(SeeablogpostforsetupanduseIntelliJIDEAwithGostepbystep)

VisualStudioVSCodeThisisanawesometexteditorreleasedasopensourcecrossplatformmyMicrosoftwhichtakesthedevelopmentexperiencetoawholenewlevelhttpscodevisualstudiocomIthaseverythingamoderntexteditorisexpectedtohaveanddespitebeingbasedonthesamebackendthatatomioisbaseditisveryfast

ItworkswithWindowsMacLinuxIthasgopackagebuiltitprovidescodelinting

Godevelopmenttools

26

AtomAtomisanawesometexteditorreleasedasopensourcecrossplatformbuiltonElectronandbasedoneverythingweloveaboutourfavoriteeditorsWedesignedittobedeeplycustomizablebutstillapproachableusingthedefaultconfiguration

Downloadhttpsatomio

GoglandGoglandisthecodenameforanewcommercialIDEbyJetBrainsaimedatprovidinganergonomicenvironmentforGodevelopment

Theofficialversionisnotyetreleased

Downloadhttpswwwjetbrainscomgo

LinksDirectoryPrevioussectionGocommandsNextsectionSummary

Godevelopmenttools

27

15SummaryInthischapterwetalkedabouthowtoinstallGousingthreedifferentmethodsincludingfromsourcecodethestandardpackageandviathird-partytoolsThenweshowedyouhowtoconfiguretheGodevelopmentenvironmentmainlycoveringhowtosetupyour$GOPATHAfterthatweintroducedsomestepsforcompilinganddeployingGoprogramsWethencoveredGocommandsincludingthecompileinstallformatandtestcommandsFinallytherearemanypowerfultoolstodevelopGoprogramssuchasLiteIDESublimeTextVSCodeAtomGoglangVimEmacsEclipseIntelliJIDEAetcYoucanchooseanyoneyoulikeexploringtheworldofGo

LinksDirectoryPrevioussectionGodevelopmenttoolsNextchapterGobasicknowledge

Summary

28

2GobasicknowledgeGoisacompiledsystemprogramminglanguageanditbelongstotheC-familyHoweveritscompilationspeedismuchfasterthanotherC-familylanguagesIthasonly25keywordsevenlessthanthe26lettersoftheEnglishalphabetLetstakealookatthesekeywordsbeforewegetstarted

breakdefaultfuncinterfaceselect

casedefergomapstruct

chanelsegotopackageswitch

constfallthroughifrangetype

continueforimportreturnvar

InthischapterImgoingtoteachyousomebasicGoknowledgeYouwillfindouthowconcisetheGoprogramminglanguageisandthebeautifuldesignofthelanguageProgrammingcanbeveryfuninGoAfterwecompletethischapteryoullbefamiliarwiththeabovekeywords

LinksDirectoryPreviouschapterChapter1SummaryNextsectionHelloGo

Gobasicknowledge

29

WhatmakesGodifferentfromotherlanguagesTheGoprogramminglanguagewascreatedwithonegoalinmindtobeabletobuildscalableweb-applicationsforlargescaleaudiencesinalargeteamSothatisthereasontheymadethelanguageasstandardizedaspossiblehencethegofmttoolandthestrictusageguidelinestothelanguagewasforthesakeofnothavingtwofactionsinthedeveloperbaseinotherlanguagestherearereligiouswarsonwheretokeeptheopeningbrace

publicstaticvoidmain()

or

publicstaticvoidmain()

orforpythonshouldweuse4spacesor6spacesoratabortwotabsandotheruserpreferencesIfyouknowpythonthenyoumightbeawareofPEP8whichisasetofguidelinesabouthowtowriteelegantcode

WhilethismightseemtobeashallowproblemwhenthecodebasegrowsandmoreandmorepeopleworkonthesamecodebaseitisbecomesincreasinglydifficulttomaintainthecodesbeautyWeliveinaworldwhererobotscandriveacarsoweshouldntjustwritecodeweshouldwriteelegantcode

ForotherlanguagestherearemanyvariableswhenitcomestowritingcodeEverylanguageisgoodforitsusecasebutGoisalittlespecialbecauseitwasdesignedatacompanywhichistheverysynonymoftheInternet(anddistributedcomputing)TypicallyinordertooptimizeprogramsdeveloperschoosetowriteJavaoverPythonandC++overJavabutalmostallavailablelanguageswidelyinusewerewrittendecadesagowhen1GBstoragewasmuchpricierNowstorageandcomputingisrelativelycheapandcomputersaregettingmultiplescoresbuttheoldlanguagesarenotharnessingconcurrencyinawaythatgodoesItsnotbecausethoselanguagesarebadutilizingconcurrencywasntarelevantusecasewhiletheolderlanguagesevolved

TomitigatealltheproblemsthatGooglefacedwithcurrenttoolstheywroteasystemslanguagecalledGowhichyouareabouttolearnTherearemanyadvantagestousinggolangandtherearedisadvantagestooforeverycoinhasbothsidesOneofthesignificantimprovementsinincodeformattingGooglehasdesignedthelanguagetoavoiddebatesoncodeformattingGocodewrittenbyanyoneintheworld(assumingtheyknowandusegofmt)willlookexactlythesameThiswontseemtomatteruntilyouworkinateamAlsowhenthecompanyusesautomatedcoderevieworsomeotherfancytechniquetheformattedcodemaybreakinotherlanguageswhichdonthavestrictandstandardformattingrulesbutnotingo

Gowasdesignedwithconcurrencyinmindpleasenotethatparallelism=concurrencythereisanamazingpostbyRobPikeonthegolangblogyouwillfinditthereitiswortharead

AnotherveryimportantchangethatistheconceptofGOPATHGonearethedayswhenyouhadtocreateafoldercalledcodeandthencreateworkspacesforeclipseandwhatnotNowyouhavetokeeponefoldertreeforgocodewhichwillbeupdatedbythepackagemanagerautomaticallyItisalsorecommendedtocreatefolderswitheitheracustomdomainorthegithubdomainforexampleIcreatedataskmanagerusinggolangsoIcreatedasetoffolders~gosrcgithubcomthewhitetulipTasks

NoteInnixsystems~standsforhomedirectorywhichisthewindowsequivalentofCUsersusernameNowthe~goistheuniverseforthegocodeinyourmachineThisisasignificantimprovementoverotherlanguageswecanstorethecodeefficientlywithouthasslesWhileitmightseemstrangeatfirstthisapproachmakealotofsensethantheridiculouspackagenamesiepackagenamesgeneratedforotherlanguagesusingreversedomains

NoteAlongwithsrctherearetwofolderspkgwhichisforpackagesandbinwhichisforbinary

HelloGo

30

ThisGOPATHadvantageisntjustrestrictedtostoringcodeinparticularfolderWhenyouhavecreatedfivepackagesforyourprojectyoudonthavetoimportthemlikeimportdbInsteadyoucanuseimportgithubcomthewhitetulipTasksdbsothatwhenexecutinggogetonmyrepothegotoolwillfindthepackagefromgithubcompathifitwasntdownloadedinitiallyThisstandardizesalotofscrewedupthingsintheprogrammingdiscipline(lt--Toremoveandreplacewithactualexplanationofwhythisisbetter)

Whiletheremaybesomefoundedcomplaintsthatgocreatorshaveignoredalllanguageresearchdonesincethepast30yrsyoucannotcreateaproductoralanguagewhicheveryonewillfallinlovewithTherearealwayssomeortheotherusecasesorconstraintswhichthecreatorsshouldconsiderConsideringalltheadvantagesatleastforwebdevelopmentIdonotthinkanylanguagegetsclosetotheadvantageswhichgohasevenifyouignoreallthatIsaidaboveGoisacompiledlanguagewhichmeansinproductionyouwonthavetosetupaJVMoravirtualenvandwillinsteadhaveasinglestaticbinaryLikeanicingonacakeallthemodernlibrariesareinthestandardlibrarysuchasthehttpliballowingyoutocreatewebappsingolangwithoutusingathirdpartywebframework

21HelloGoBeforewestartbuildinganapplicationinGoweneedtolearnhowtowriteasimpleprogramYoucantexpecttobuildabuildingwithoutfirstknowinghowtobuilditsfoundationThereforewearegoingtolearnthebasicsyntaxtorunsomesimpleprogramsinthissection

ProgramAccordingtointernationalpracticebeforeyoulearnhowtoprograminsomelanguagesyouwillwanttoknowhowtowriteaprogramtoprintHelloworld

AreyoureadyLetsGo

packagemain

importfmt

funcmain()

fmtPrintf(Helloworldor你好世界orΚαλημέρακόσμεorこんにちは世界n)

Itprintsfollowinginformation

Helloworldor你好世界orΚαλημέρακόσμεorこんにちは世界

ExplanationOnethingthatyoushouldknowinthefirstisthatGoprogramsarecomposedbypackage

packageltpkgNamegt(Inthiscaseispackagemain)tellsusthissourcefilebelongstomainpackageandthekeywordmaintellsusthispackagewillbecompiledtoaprograminsteadofpackagefileswhoseextensionsarea

Everyexecutableprogramhasoneandonlyonemainpackageandyouneedanentryfunctioncalledmainwithoutanyargumentsorreturnvaluesinthemainpackage

InordertoprintHelloworldhellipwecalledafunctioncalledPrintfThisfunctioniscomingfromfmtpackagesoweimportthispackageinthethirdlineofsourcecodewhichisimportfmt

ThewaytothinkaboutpackagesinGoissimilartoPythonandtherearesomeadvantagesModularity(breakupyourprogramintomanymodules)andreusability(everymodulecanbereusedinmanyprograms)Wejusttalkedaboutconceptsregardingpackagesandwewillmakeourownpackageslater

HelloGo

31

OnthefifthlineweusethekeywordfunctodefinethemainfunctionThebodyofthefunctionisinsideofjustlikeCC++andJava

AsyoucanseetherearenoargumentsWewilllearnhowtowritefunctionswithargumentsinjustasecondandyoucanalsohavefunctionsthathavenoreturnvalueorhaveseveralreturnvalues

OnthesixthlinewecalledthefunctionPrintfwhichisfromthepackagefmtThiswascalledbythesyntaxltpkgNamegtltfuncNamegtwhichisverylikePython-style

Aswementionedinchapter1thepackagesnameandthenameofthefolderthatcontainsthatpackagecanbedifferentHeretheltpkgNamegtcomesfromthenameinpackageltpkgNamegtnotthefoldersname

Youmaynoticethattheexampleabovecontainsmanynon-ASCIIcharactersThepurposeofshowingthisistotellyouthatGosupportsUTF-8bydefaultYoucanuseanyUTF-8characterinyourprograms

EachgofileisinsomepackageandthatpackageshouldbeadistinctfolderintheGOPATHbutmainisaspecialpackagewhichdoesntrequireamainfolderThisisoneaspectwhichtheyleftoutforstandardizationButshouldyouchoosetomakeamainfolderthenyouhavetoensurethatyourunthebinaryproperlyAlsoonegocodecanthavemorethanonemaingofile

~gosrcgithubcomthewhitetulipTasksmain$gobuild~gosrcgithubcomthewhitetulipTasks$mainmain

thethinghereisthatwhenyourcodeisusingsomestaticfilesorsomethingelsethenyououghttorunthebinaryfromtherootoftheapplicationasweseeinthesecondlineaboveIamrunningthemainbinaryoutsidethemainpackagesometimesyoumightwonderwhyyourapplicationisntworkingthenthismightbeoneofthepossibleproblemspleasekeepthisinmind

Onethingyouwillnoticehereisthatgodoesntseetousesemicolonstoendastatementwellitdoesjustthereisaminorcatchtheprogrammerisntexpectedtoputsemicolonsthecompileraddssemicolonstothegocodewhenitcompileswhichisthereasonthatthis(thankfully)isasyntaxerror

funcmain()

becausethecompileraddsasemicolonattheendofmain()whichisasyntaxerrorandasstatedaboveithelpsavoidreligiouswarsiwishtheycombinevimandemacsandcreateauniversaleditorwhichllhelpsavesomemorewarsButfornowwelllearnGo

ConclusionGousespackage(likemodulesinPython)toorganizeprogramsThefunctionmainmain()(thisfunctionmustbeinthemainpackage)istheentrypointofanyprogramGostandardizeslanguageandmostoftheprogrammingmethodologysavingtimeofdeveloperswhichtheydhavewastedinreligiouswarsTherecanbeonlyonemainpackageandonlyonemainfunctioninsideagomainpackageGosupportsUTF-8charactersbecauseoneofthecreatorsofGoisacreatorofUTF-8soGohassupportedmultiplelanguagesfromthetimeitwasborn

LinksDirectoryPrevioussectionGobasicknowledgeNextsectionGofoundation

HelloGo

32

HelloGo

33

22GofoundationInthissectionwearegoingtoteachyouhowtodefineconstantsvariableswithelementarytypesandsomeskillsinGoprogramming

DefinevariablesTherearemanyformsofsyntaxthatcanbeusedtodefinevariablesinGo

ThekeywordvaristhebasicformtodefinevariablesnoticethatGoputsthevariabletypeafterthevariablename

defineavariablewithnameldquovariableNamerdquoandtypetype

varvariableNametype

Definemultiplevariables

definethreevariableswhichtypesaretype

varvname1vname2vname3type

Defineavariablewithinitialvalue

defineavariablewithnameldquovariableNamerdquotypetypeandvaluevalue

varvariableNametype=value

Definemultiplevariableswithinitialvalues

Definethreevariableswithtypetypeandinitializetheirvalues

vname1isv1vname2isv2vname3isv3

varvname1vname2vname3type=v1v2v3

DoyouthinkthatitstootedioustodefinevariablesusethewayaboveDontworrybecausetheGoteamhasalsofoundthistobeaproblemThereforeifyouwanttodefinevariableswithinitialvalueswecanjustomitthevariabletypesothecodewilllooklikethisinstead

Definethreevariableswithouttypetypeandinitializetheirvalues

vname1isv1vname2isv2vname3isv3

varvname1vname2vname3=v1v2v3

WellIknowthisisstillnotsimpleenoughforyouLetsseehowwefixit

Definethreevariableswithouttypetypeandwithoutkeywordvarandinitializetheirvalues

vname1isv1vname2isv2vname3isv3

vname1vname2vname3=v1v2v3

NowitlooksmuchbetterUse=toreplacevarandtypethisiscalledashortassignmentIthasonelimitationthisformcanonlybeusedinsideofafunctionsYouwillgetcompileerrorsifyoutrytouseitoutsideoffunctionbodiesThereforeweusuallyusevartodefineglobalvariables

Gofoundation

34

_(blank)isaspecialvariablenameAnyvaluethatisgiventoitwillbeignoredForexamplewegive35tobanddiscard34(ThisexamplejustshowyouhowitworksItlooksuselessherebecauseweoftenusethissymbolwhenwegetfunctionreturnvalues)

_b=3435

IfyoudontusevariablesthatyouvedefinedinyourprogramthecompilerwillgiveyoucompilationerrorsTrytocompilethefollowingcodeandseewhathappens

packagemain

funcmain()

variint

ConstantsSo-calledconstantsarethevaluesthataredeterminedduringcompiletimeandyoucannotchangethemduringruntimeInGoyoucanusenumberbooleanorstringastypesofconstants

Defineconstantsasfollows

constconstantName=value

youcanassigntypeofconstantsifitsnecessary

constPifloat32=31415926

Moreexamples

constPi=31415926

consti=10000

constMaxThread=10

constprefix=astaxie_

Elementarytypes

Boolean

InGoweusebooltodefineavariableasbooleantypethevaluecanonlybetrueorfalseandfalsewillbethedefaultvalue(Youcannotconvertvariablestypebetweennumberandboolean)

samplecode

varisActiveboolglobalvariable

varenableddisabled=truefalseomittypeofvariables

functest()

varavailableboollocalvariable

valid=falsebriefstatementofvariable

available=trueassignvaluetovariable

Numericaltypes

IntegertypesincludebothsignedandunsignedintegertypesGohasintanduintatthesametimetheyhavesamelengthbutspecificlengthdependsonyouroperatingsystemTheyuse32-bitin32-bitoperatingsystemsand64-bitin64-bitoperatingsystemsGoalsohastypesthathavespecificlengthincludingruneint8int16int32int64byteuint8uint16uint32uint64Notethatruneisaliasofint32andbyteisaliasofuint8

Gofoundation

35

Oneimportantthingyoushouldknowthatyoucannotassignvaluesbetweenthesetypesthisoperationwillcausecompileerrors

varaint8

varbint32

c=a+b

Althoughint32hasalongerlengththanint8andhasthesametypeasintyoucannotassignvaluesbetweenthem(cwillbeassertedastypeinthere)

Floattypeshavethefloat32andfloat64typesandnotypecalledfloatThelatteroneisthedefaulttypeifusingbriefstatement

ThatsallNoGosupportscomplexnumbersaswellcomplex128(witha64-bitrealand64-bitimaginarypart)isthedefaulttypeifyouneedasmallertypethereisonecalledcomplex64(witha32-bitrealand32-bitimaginarypart)ItsformisRE+IMiwhereREisrealpartandIMisimaginarypartthelastiistheimaginarynumberThereisaexampleofcomplexnumber

varccomplex64=5+5i

output(5+5i)

fmtPrintf(Valueisvc)

String

WejusttalkedabouthowGousestheUTF-8charactersetStringsarerepresentedbydoublequotesorbackticks `

samplecode

varfrenchHellostringbasicformtodefinestring

varemptyStringstring=defineastringwithemptystring

functest()

noyesmaybe=noyesmaybebriefstatement

japaneseHello=Ohaiou

frenchHello=Bonjourbasicformofassignvalues

ItsimpossibletochangestringvaluesbyindexYouwillgeterrorswhenyoucompilethefollowingcode

varsstring=hello

s[0]=c

WhatifIreallywanttochangejustonecharacterinastringTrythefollowingcode

s=hello

c=[]byte(s)convertstringto[]bytetype

c[0]=c

s2=string(c)convertbacktostringtype

fmtPrintf(sns2)

Youusethe+operatortocombinetwostrings

s=hello

m=world

a=s+m

fmtPrintf(sna)

andalso

Gofoundation

36

s=hello

s=c+s[1]youcannotchangestringvaluesbyindexbutyoucangetvaluesinstead

fmtPrintf(sns)

WhatifIwanttohaveamultiple-linestring

m=`hello

world`

willnotescapeanycharactersinastring

ErrortypesGohasoneerrortypeforpurposeofdealingwitherrormessagesThereisalsoapackagecallederrorstohandleerrors

err=errorsNew(emitmachodwarfelfheadercorrupted)

iferr=nil

fmtPrint(err)

Underlyingdatastructure

ThefollowingpicturecomesfromanarticleaboutGodatastructureinRussCoxsBlogAsyoucanseeGoutilizesblocksofmemorytostoredata

Figure21Gounderlyingdatastructure

Someskills

Definebygroup

Ifyouwanttodefinemultipleconstantsvariablesorimportpackagesyoucanusethegroupform

Basicform

importfmt

importos

consti=100

constpi=31415

constprefix=Go_

variint

varpifloat32

varprefixstring

Groupform

Gofoundation

37

import(

fmt

os

)

const(

i=100

pi=31415

prefix=Go_

)

var(

iint

pifloat32

prefixstring

)

Unlessyouassignthevalueofconstantisiotathefirstvalueofconstantinthegroupconst()willbe0IffollowingconstantsdontassignvaluesexplicitlytheirvalueswillbethesameasthelastoneIfthevalueoflastconstantisiotathevaluesoffollowingconstantswhicharenotassignedareiotaalso

iotaenumerate

Gohasonekeywordcallediotathiskeywordistomakeenumitbeginswith0increasedby1

const(

x=iotax==0

y=iotay==1

z=iotaz==2

wIfthereisnoexpressionaftertheconstantsnameitusesthelastexpression

soitssayingw=iotaimplicitlyThereforew==3andyandzbothcanomit=iotaaswell

)

constv=iotaonceiotameetskeyword`const`itresetsto`0`sov=0

const(

efg=iotaiotaiotae=0f=0g=0valuesofiotaaresameinoneline

)

Somerules

ThereasonthatGoisconcisebecauseithassomedefaultbehaviors

AnyvariablethatbeginswithacapitallettermeansitwillbeexportedprivateotherwiseThesameruleappliesforfunctionsandconstantsnopublicorprivatekeywordexistsinGo

arrayslicemap

array

arrayisanarrayobviouslywedefineoneasfollows

vararr[n]type

in[n]typenisthelengthofthearraytypeisthetypeofitselementsLikeotherlanguagesweuse[]togetorsetelementvalueswithinarrays

Gofoundation

38

vararr[10]intanarrayoftype[10]int

arr[0]=42arrayis0-based

arr[1]=13assignvaluetoelement

fmtPrintf(Thefirstelementisdnarr[0])

getelementvalueitreturns42

fmtPrintf(Thelastelementisdnarr[9])

itreturnsdefaultvalueof10thelementinthisarraywhichis0inthiscase

Becauselengthisapartofthearraytype[3]intand[4]intaredifferenttypessowecannotchangethelengthofarraysWhenyouusearraysasargumentsfunctionsgettheircopiesinsteadofreferencesIfyouwanttousereferencesyoumaywanttousesliceWelltalkaboutlater

Itspossibletouse=whenyoudefinearrays

a=[3]int123defineanintarraywith3elements

b=[10]int123

defineaintarraywith10elementsofwhichthefirstthreeareassigned

Therestofthemusethedefaultvalue0

c=[]int456use`hellip`toreplacethelengthparameterandGowillcalculateitforyou

YoumaywanttousearraysasarrayselementsLetsseehowtodothis

defineatwo-dimensionalarraywith2elementsandeachelementhas4elements

doubleArray=[2][4]int[4]int1234[4]int5678

Thedeclarationcanbewrittenmoreconciselyasfollows

easyArray=[2][4]int12345678

Arrayunderlyingdatastructure

Figure22Multidimensionalarraymappingrelationship

sliceInmanysituationsthearraytypeisnotagoodchoice-forinstancewhenwedontknowhowlongthearraywillbewhenwedefineitThusweneedadynamicarrayThisiscalledsliceinGo

sliceisnotreallyadynamicarrayItsareferencetypeslicepointstoanunderlyingarraywhosedeclarationissimilartoarraybutdoesntneedlength

justlikedefininganarraybutthistimeweexcludethelength

varfslice[]int

Thenwedefineasliceandinitializeitsdata

slice=[]byteabcd

slicecanredefineexistingslicesorarrayssliceusesarray[ij]toslicewhereiisthestartindexandjisendindexbutnoticethatarray[j]willnotbeslicedsincethelengthofthesliceisj-i

Gofoundation

39

defineanarraywith10elementswhosetypesarebytes

varar=[10]byteabcdefghij

definetwosliceswithtype[]byte

varab[]byte

apointstoelementsfrom3rdto5thinarrayar

a=ar[25]

nowahaselementsar[2]ar[3]andar[4]

bisanothersliceofarrayar

b=ar[35]

nowbhaselementsar[3]andar[4]

NoticethedifferencesbetweensliceandarraywhenyoudefinethemWeuse[hellip]toletGocalculatelengthbutuse[]todefinesliceonly

Theirunderlyingdatastructure

Figure23Correspondencebetweensliceandarray

slicehassomeconvenientoperations

sliceis0-basedar[n]equalstoar[0n]Thesecondindexwillbethelengthofsliceifomittedar[n]equalstoar[nlen(ar)]Youcanusear[]toslicewholearrayreasonsareexplainedinfirsttwostatements

Moreexamplespertainingtoslice

defineanarray

vararray=[10]byteabcdefghij

definetwoslices

varaSlicebSlice[]byte

someconvenientoperations

aSlice=array[3]equalstoaSlice=array[03]aSlicehaselementsabc

aSlice=array[5]equalstoaSlice=array[510]aSlicehaselementsfghij

aSlice=array[]equalstoaSlice=array[010]aSlicehasallelements

slicefromslice

aSlice=array[37]aSlicehaselementsdefglen=4cap=7

bSlice=aSlice[13]bSlicecontainsaSlice[1]aSlice[2]soithaselementsef

bSlice=aSlice[3]bSlicecontainsaSlice[0]aSlice[1]aSlice[2]soithasdef

bSlice=aSlice[05]slicecouldbeexpandedinrangeofcapnowbSlicecontainsdefgh

bSlice=aSlice[]bSlicehassameelementsasaSlicedoeswhicharedefg

sliceisareferencetypesoanychangeswillaffectothervariablespointingtothesamesliceorarrayForinstanceinthecaseofaSliceandbSliceaboveifyouchangethevalueofanelementinaSlicebSlicewillbechangedaswell

sliceislikeastructbydefinitionanditcontains3parts

ApointerthatpointstowhereslicestartsThelengthofsliceCapacitythelengthfromstartindextoendindexofslice

Array_a=[10]byteabcdefghij

Slice_a=Array_a[25]

Theunderlyingdatastructureofthecodeaboveasfollows

Gofoundation

40

Figure24Arrayinformationofslice

Therearesomebuilt-infunctionsforslice

lengetsthelengthofslicecapgetsthemaximumlengthofsliceappendappendsoneormoreelementstosliceandreturnsslicecopycopieselementsfromoneslicetotheotherandreturnsthenumberofelementsthatwerecopied

AttentionappendwillchangethearraythatslicepointstoandaffectotherslicesthatpointtothesamearrayAlsoifthereisnotenoughlengthfortheslice((cap-len)==0)appendreturnsanewarrayforthissliceWhenthishappensotherslicespointingtotheoldarraywillnotbeaffected

map

mapbehaveslikeadictionaryinPythonUsetheformmap[keyType]valueTypetodefineit

LetsseesomecodeThesetandgetvaluesinmaparesimilartoslicehowevertheindexinslicecanonlybeoftypeintwhilemapcanusemuchmorethanthatforexampleintstringorwhateveryouwantAlsotheyareallabletouse==and=tocomparevalues

usestringasthekeytypeintasthevaluetypeand`make`initializeit

varnumbersmap[string]int

anotherwaytodefinemap

numbers=make(map[string]int)

numbers[one]=1assignvaluebykey

numbers[ten]=10

numbers[three]=3

fmtPrintln(Thethirdnumberisnumbers[three])getvalues

ItprintsThethirdnumberis3

Somenoteswhenyouusemap

mapisdisorderlyEverytimeyouprintmapyouwillgetdifferentresultsItsimpossibletogetvaluesbyindex-youhavetousekeymapdoesnthaveafixedlengthItsareferencetypejustlikeslicelenworksformapalsoItreturnshowmanykeysthatmaphasItsquiteeasytochangethevaluethroughmapSimplyusenumbers[one]=11tochangethevalueofkeyoneto11

Youcanuseformkeyvaltoinitializemapsvaluesandmaphasbuilt-inmethodstocheckifthekeyexists

Usedeletetodeleteanelementinmap

Initializeamap

rating=map[string]float32C5Go45Python45C++2

maphastworeturnvaluesForthesecondreturnvalueifthekeydoesnt

existokreturnsfalseItreturnstrueotherwise

csharpRatingok=rating[C]

ifok

fmtPrintln(CisinthemapanditsratingiscsharpRating)

else

fmtPrintln(WehavenoratingassociatedwithCinthemap)

delete(ratingC)deleteelementwithkeyc

AsIsaidabovemapisareferencetypeIftwomapspointtosameunderlyingdataanychangewillaffectbothofthem

Gofoundation

41

m=make(map[string]string)

m[Hello]=Bonjour

m1=m

m1[Hello]=Salutnowthevalueofm[hello]isSalut

makenewmakedoesmemoryallocationforbuilt-inmodelssuchasmapsliceandchannelwhilenewisfortypesmemoryallocation

new(T)allocateszero-valuetotypeTsmemoryreturnsitsmemoryaddresswhichisthevalueoftypeTByGosdefinitionitreturnsapointerwhichpointstotypeTszero-value

newreturnspointers

Thebuilt-infunctionmake(Targs)hasdifferentpurposesthannew(T)makecanbeusedforslicemapandchannelandreturnsatypeTwithaninitialvalueThereasonfordoingthisisbecausetheunderlyingdataofthesethreetypesmustbeinitializedbeforetheypointtothemForexampleaslicecontainsapointerthatpointstotheunderlyingarraylengthandcapacityBeforethesedataareinitializedsliceisnilsoforslicemapandchannelmakeinitializestheirunderlyingdataandassignssomesuitablevalues

makereturnsnon-zerovalues

Thefollowingpictureshowshownewandmakearedifferent

Figure25Underlyingmemoryallocationofmakeandnew

Zero-valuedoesnotmeanemptyvalueItsthevaluethatvariablesdefaulttoinmostcasesHereisalistofsomezero-values

int0

int80

int320

int640

uint0x0

rune0theactualtypeofruneisint32

byte0x0theactualtypeofbyteisuint8

float320lengthis4byte

float640lengthis8byte

boolfalse

string

LinksDirectoryPrevioussectionHelloGoNextsectionControlstatementsandfunctions

Gofoundation

42

23ControlstatementsandfunctionsInthissectionwearegoingtotalkaboutcontrolstatementsandfunctionoperationsinGo

ControlstatementThegreatestinventioninprogrammingisflowcontrolBecauseofthemyouareabletousesimplecontrolstatementsthatcanbeusedtorepresentcomplexlogicTherearethreecategoriesofflowcontrolconditionalcyclecontrolandunconditionaljump

if

ifwillmostlikelybethemostcommonkeywordinyourprogramsIfitmeetstheconditionsthenitdoessomethinganditdoessomethingelseifnot

ifdoesntneedparenthesesinGo

ifxgt10

fmtPrintln(xisgreaterthan10)

else

fmtPrintln(xislessthanorequalto10)

ThemostusefulthingconcerningifinGoisthatitcanhaveoneinitializationstatementbeforetheconditionalstatementThescopeofthevariablesdefinedinthisinitializationstatementareonlyavailableinsidetheblockofthedefiningif

initializexthencheckifxgreaterthan

ifx=computedValue()xgt10

fmtPrintln(xisgreaterthan10)

else

fmtPrintln(xislessthan10)

thefollowingcodewillnotcompile

fmtPrintln(x)

Useif-elseformultipleconditions

ifinteger==3

fmtPrintln(Theintegerisequalto3)

elseifintegerlt3

fmtPrintln(Theintegerislessthan3)

else

fmtPrintln(Theintegerisgreaterthan3)

gotoGohasagotokeywordbutbecarefulwhenyouuseitgotoreroutesthecontrolflowtoapreviouslydefinedlabelwithinthebodyofsamecodeblock

Controlstatementsandfunctions

43

funcmyFunc()

i=0

Herelabelendswith

fmtPrintln(i)

i++

gotoHerejumptolabelHere

Thelabelnameiscasesensitive

for

foristhemostpowerfulcontrollogicinGoItcanreaddatainloopsanditerativeoperationsjustlikewhile

forexpression1expression2expression3

expression1expression2andexpression3areallexpressionswhereexpression1andexpression3arevariabledefinitionsorreturnvaluesfromfunctionsandexpression2isaconditionalstatementexpression1willbeexecutedoncebeforeloopingandexpression3willbeexecutedaftereachloop

Examplesaremoreusefulthanwords

packagemain

importfmt

funcmain()

sum=0

forindex=0indexlt10index++

sum+=index

fmtPrintln(sumisequaltosum)

Printsumisequalto45

SometimesweneedmultipleassignmentsbutGodoesnthavetheoperatorsoweuseparallelassignmentlikeij=i+1j-1

Wecanomitexpression1andexpression3iftheyarenotnecessary

sum=1

forsumlt1000

sum+=sum

OmitaswellFeelfamiliarYesitsidenticaltowhile

sum=1

forsumlt1000

sum+=sum

TherearetwoimportantoperationsinloopswhicharebreakandcontinuebreakjumpsoutoftheloopandcontinueskipsthecurrentloopandstartsthenextoneIfyouhavenestedloopsusebreakalongwithlabels

Controlstatementsandfunctions

44

forindex=10indexgt0index--

ifindex==5

breakorcontinue

fmtPrintln(index)

breakprints109876

continueprints1098764321

forcanreaddatafromarrayslicemapandstringwhenitisusedtogetherwithrange

forkv=rangemap

fmtPrintln(mapskeyk)

fmtPrintln(mapsvalv)

BecauseGosupportsmulti-valuereturnsandgivescompileerrorswhenyoudontusevaluesthatweredefinedyoumaywanttouse_todiscardcertainreturnvalues

for_v=rangemap

fmtPrintln(mapsvalv)

Withgoyoucanaswellcreateaninfiniteloopwhichisequivalenttowhiletrueinotherlanguges

for

yourlogic

switchSometimesyoumayfindthatyouareusingtoomanyif-elsestatementstoimplementsomelogicwhichmaymakeitdifficulttoreadandmaintaininthefutureThisistheperfecttimetousetheswitchstatementtosolvethisproblem

switchsExpr

caseexpr1

someinstructions

caseexpr2

someotherinstructions

caseexpr3

someotherinstructions

default

othercode

ThetypeofsExprexpr1expr2andexpr3mustbethesameswitchisveryflexibleConditionsdonthavetobeconstantsanditexecutesfromtoptobottomuntilitmatchesconditionsIfthereisnostatementafterthekeywordswitchthenitmatchestrue

i=10

switchi

case1

fmtPrintln(iisequalto1)

case234

fmtPrintln(iisequalto23or4)

case10

fmtPrintln(iisequalto10)

default

fmtPrintln(AllIknowisthatiisaninteger)

Controlstatementsandfunctions

45

InthefifthlineweputmanyvaluesinonecaseandwedontneedtoaddthebreakkeywordattheendofcasesbodyItwilljumpoutoftheswitchbodyonceitmatchedanycaseIfyouwanttocontinuetomatchingmorecasesyouneedtousethefallthroughstatement

integer=6

switchinteger

case4

fmtPrintln(integerlt=4)

fallthrough

case5

fmtPrintln(integerlt=5)

fallthrough

case6

fmtPrintln(integerlt=6)

fallthrough

case7

fmtPrintln(integerlt=7)

fallthrough

case8

fmtPrintln(integerlt=8)

fallthrough

default

fmtPrintln(defaultcase)

Thisprogramprintsthefollowinginformation

integerlt=6

integerlt=7

integerlt=8

defaultcase

FunctionsUsethefunckeywordtodefineafunction

funcfuncName(input1type1input2type2)(output1type1output2type2)

functionbody

multi-valuereturn

returnvalue1value2

Wecanextrapolatethefollowinginformationfromtheexampleabove

UsekeywordfunctodefineafunctionfuncNameFunctionshavezerooneormorethanoneargumentsTheargumenttypecomesaftertheargumentnameandargumentsareseparatedbyFunctionscanreturnmultiplevaluesTherearetworeturnvaluesnamedoutput1andoutput2youcanomittheirnamesandusetheirtypeonlyIfthereisonlyonereturnvalueandyouomittedthenameyoudontneedbracketsforthereturnvaluesIfthefunctiondoesnthavereturnvaluesyoucanomitthereturnparametersaltogetherIfthefunctionhasreturnvaluesyouhavetousethereturnstatementsomewhereinthebodyofthefunction

Letsseeonepracticalexample(calculatemaximumvalue)

Controlstatementsandfunctions

46

packagemain

importfmt

returngreatervaluebetweenaandb

funcmax(abint)int

ifagtb

returna

returnb

funcmain()

x=3

y=4

z=5

max_xy=max(xy)callfunctionmax(xy)

max_xz=max(xz)callfunctionmax(xz)

fmtPrintf(max(dd)=dnxymax_xy)

fmtPrintf(max(dd)=dnxzmax_xz)

fmtPrintf(max(dd)=dnyzmax(yz))callfunctionhere

IntheaboveexampletherearetwoargumentsinthefunctionmaxtheirtypesarebothintsothefirsttypecanbeomittedForinstanceabintinsteadofaintbintThesamerulesapplyforadditionalargumentsNoticeherethatmaxonlyhasonereturnvaluesoweonlyneedtowritethetypeofitsreturnvalue-thisistheshortformofwritingit

Multi-valuereturn

OnethingthatGoisbetteratthanCisthatitsupportsmulti-valuereturns

Wellusethefollowingexamplehere

packagemain

importfmt

returnresultsofA+BandAB

funcSumAndProduct(ABint)(intint)

returnA+BAB

funcmain()

x=3

y=4

xPLUSyxTIMESy=SumAndProduct(xy)

fmtPrintf(d+d=dnxyxPLUSy)

fmtPrintf(dd=dnxyxTIMESy)

Theaboveexamplereturnstwovalueswithoutnames-youhavetheoptionofnamingthemalsoIfwenamedthereturnvalueswewouldjustneedtousereturntoreturnthevaluessincetheyareinitializedinthefunctionautomaticallyNoticethatifyourfunctionsaregoingtobeusedoutsideofthepackagewhichmeansyourfunctionnamesstartwithacapitalletteryoudbetterwritecompletestatementsforreturnitmakesyourcodemorereadable

funcSumAndProduct(ABint)(addintmultipliedint)

add=A+B

multiplied=AB

return

Controlstatementsandfunctions

47

Variadicfunctions

GosupportsfunctionswithavariablenumberofargumentsThesefunctionsarecalledvariadicwhichmeansthefunctionallowsanuncertainnumbersofarguments

funcmyfunc(argint)

arghellipinttellsGothatthisisafunctionthathasvariableargumentsNoticethattheseargumentsaretypeintInthebodyoffunctiontheargbecomesasliceofint

for_n=rangearg

fmtPrintf(Andthenumberisdnn)

Passbyvalueandpointers

Whenwepassanargumenttothefunctionthatwascalledthatfunctionactuallygetsthecopyofourvariablessoanychangewillnotaffecttotheoriginalvariable

Letsseeoneexampleinordertoprovewhatimsaying

packagemain

importfmt

simplefunctiontoadd1toa

funcadd1(aint)int

a=a+1wechangevalueofa

returnareturnnewvalueofa

funcmain()

x=3

fmtPrintln(x=x)shouldprintx=3

x1=add1(x)calladd1(x)

fmtPrintln(x+1=x1)shouldprintx+1=4

fmtPrintln(x=x)shouldprintx=3

CanyouseethatEventhoughwecalledadd1withxtheoriginvalueofxdoesntchange

Thereasonisverysimplewhenwecalledadd1wegaveacopyofxtoitnotthexitself

NowyoumayaskhowIcanpasstherealxtothefunction

WeneedusepointershereWeknowvariablesarestoredinmemoryandtheyhavesomememoryaddressesSoifwewanttochangethevalueofavariablewemustchangeitsmemoryaddressThereforethefunctionadd1hastoknowthememoryaddressofxinordertochangeitsvalueHerewepassampxtothefunctionandchangetheargumentstypetothepointertypeintBeawarethatwepassacopyofthepointernotcopyofvalue

Controlstatementsandfunctions

48

packagemain

importfmt

simplefunctiontoadd1toa

funcadd1(aint)int

a=a+1wechangedvalueofa

returnareturnnewvalueofa

funcmain()

x=3

fmtPrintln(x=x)shouldprintx=3

x1=add1(ampx)calladd1(ampx)passmemoryaddressofx

fmtPrintln(x+1=x1)shouldprintx+1=4

fmtPrintln(x=x)shouldprintx=4

NowwecanchangethevalueofxinthefunctionsWhydoweusepointersWhataretheadvantages

AllowsustousemorefunctionstooperateononevariableLowcostbypassingmemoryaddresses(8bytes)copyisnotanefficientwaybothintermsoftimeandspacetopassvariableschannelsliceandmaparereferencetypessotheyusepointerswhenpassingtofunctionsbydefault(AttentionIfyouneedtochangethelengthofsliceyouhavetopasspointersexplicitly)

deferGohasawelldesignedkeywordcalleddeferYoucanhavemanydeferstatementsinonefunctiontheywillexecuteinreverseorderwhentheprogramexecutestotheendoffunctionsInthecasewheretheprogramopenssomeresourcefilesthesefileswouldhavetobeclosedbeforethefunctioncanreturnwitherrorsLetsseesomeexamples

funcReadWrite()bool

fileOpen(file)

Dosomework

iffailureX

fileClose()

returnfalse

iffailureY

fileClose()

returnfalse

fileClose()

returntrue

WesawsomecodebeingrepeatedseveraltimesdefersolvesthisproblemverywellItdoesntonlyhelpyoutowritecleancodebutalsomakesyourcodemorereadable

Controlstatementsandfunctions

49

funcReadWrite()bool

fileOpen(file)

deferfileClose()

iffailureX

returnfalse

iffailureY

returnfalse

returntrue

IftherearemorethanonedeferstheywillexecutebyreverseorderThefollowingexamplewillprint43210

fori=0ilt5i++

deferfmtPrintf(di)

Functionsasvaluesandtypes

FunctionsarealsovariablesinGowecanusetypetodefinethemFunctionsthathavethesamesignaturecanbeseenasthesametype

typetypeNamefunc(input1inputType1input2inputType2[])(result1resultType1[])

WhatstheadvantageofthisfeatureTheansweristhatitallowsustopassfunctionsasvalues

packagemain

importfmt

typetestIntfunc(int)booldefineafunctiontypeofvariable

funcisOdd(integerint)bool

returninteger2=0

funcisEven(integerint)bool

returninteger2==0

passthefunction`f`asanargumenttoanotherfunction

funcfilter(slice[]intftestInt)[]int

varresult[]int

for_value=rangeslice

iff(value)

result=append(resultvalue)

returnresult

varslice=[]int123457

funcmain()

odd=filter(sliceisOdd)

even=filter(sliceisEven)

fmtPrintln(slice=slice)

fmtPrintln(Oddelementsofsliceareodd)

fmtPrintln(Evenelementsofsliceareeven)

Controlstatementsandfunctions

50

ItsveryusefulwhenweuseinterfacesAsyoucanseetestIntisavariablethathasafunctionastypeandthereturnedvaluesandargumentsoffilterarethesameasthoseoftestIntThereforewecanhavecomplexlogicinourprogramswhilemaintainingflexibilityinourcode

PanicandRecover

Godoesnthavetry-catchstructurelikeJavadoesInsteadofthrowingexceptionsGousespanicandrecovertodealwitherrorsHoweveryoushouldntusepanicverymuchalthoughitspowerful

Panicisabuilt-infunctiontobreakthenormalflowofprogramsandgetintopanicstatusWhenafunctionFcallspanicFwillnotcontinueexecutingbutitsdeferfunctionswillcontinuetoexecuteThenFgoesbacktothebreakpointwhichcausedthepanicstatusTheprogramwillnotterminateuntilallofthesefunctionsreturnwithpanictothefirstlevelofthatgoroutinepaniccanbeproducedbycallingpanicintheprogramandsomeerrorsalsocausepaniclikearrayaccessoutofboundserrors

Recoverisabuilt-infunctiontorecovergoroutinesfrompanicstatusCallingrecoverindeferfunctionsisusefulbecausenormalfunctionswillnotbeexecutedwhentheprogramisinthepanicstatusItcatchespanicvaluesiftheprogramisinthepanicstatusanditgetsniliftheprogramisnotinpanicstatus

Thefollowingexampleshowshowtousepanic

varuser=osGetenv(USER)

funcinit()

ifuser==

panic(novaluefor$USER)

Thefollowingexampleshowshowtocheckpanic

functhrowsPanic(ffunc())(bbool)

deferfunc()

ifx=recover()x=nil

b=true

()

f()iffcausespanicitwillrecover

return

mainfunctionandinitfunction

GohastworetentionswhicharecalledmainandinitwhereinitcanbeusedinallpackagesandmaincanonlybeusedinthemainpackageThesetwofunctionsarenotabletohaveargumentsorreturnvaluesEventhoughwecanwritemanyinitfunctionsinonepackageIstronglyrecommendwritingonlyoneinitfunctionforeachpackage

Goprogramswillcallinit()andmain()automaticallysoyoudontneedtocallthembyyourselfForeverypackagetheinitfunctionisoptionalbutpackagemainhasoneandonlyonemainfunction

ProgramsinitializeandbeginexecutionfromthemainpackageIfthemainpackageimportsotherpackagestheywillbeimportedinthecompiletimeIfonepackageisimportedmanytimesitwillbeonlycompiledonceAfterimportingpackagesprogramswillinitializetheconstantsandvariableswithintheimportedpackagesthenexecutetheinitfunctionifitexistsandsoonAfteralltheotherpackagesareinitializedprogramswillinitializeconstantsandvariablesinthemainpackagethenexecutetheinitfunctioninsidethepackageifitexistsThefollowingfigureshowstheprocess

Figure26FlowofprogramsinitializationinGo

Controlstatementsandfunctions

51

import

WeuseimportveryofteninGoprogramsasfollows

import(

fmt

)

Thenweusefunctionsinthatpackageasfollows

fmtPrintln(helloworld)

fmtisfromGostandardlibraryitislocatedwithin$GOROOTpkgGosupportsthird-partypackagesintwoways

1 RelativepathimportmodelloadpackageinthesamedirectoryIdontrecommendthisway2 Absolutepathimportshorturlmodelloadpackageinpath$GOPATHpkgshorturlmodel

Therearesomespecialoperatorswhenweimportpackagesandbeginnersarealwaysconfusedbytheseoperators

1 DotoperatorSometimeweseepeopleusefollowingwaytoimportpackages

import(

fmt

)

ThedotoperatormeansyoucanomitthepackagenamewhenyoucallfunctionsinsideofthatpackageNowfmtPrintf(Helloworld)becomestoPrintf(Helloworld)

2 AliasoperationItchangesthenameofthepackagethatweimportedwhenwecallfunctionsthatbelongtothatpackage

import(

ffmt

)

NowfmtPrintf(Helloworld)becomestofPrintf(Helloworld)3 _operatorThisistheoperatorthatisdifficulttounderstandwithoutsomeoneexplainingittoyou

import(

databasesql

_githubcomziutekmymysqlgodrv

)

The_operatoractuallymeanswejustwanttoimportthatpackageandexecuteitsinitfunctionandwearenotsureifwewanttousethefunctionsbelongingtothatpackage

LinksDirectoryPrevioussectionGofoundationNextsectionstruct

Controlstatementsandfunctions

52

24struct

structWecandefinenewtypesofcontainersofotherpropertiesorfieldsinGojustlikeinotherprogramminglanguagesForexamplewecancreateatypecalledpersontorepresentapersonwithfieldsnameandageWecallthiskindoftypeastruct

typepersonstruct

namestring

ageint

Lookhoweasyitistodefineastruct

Therearetwofields

nameisastringusedtostoreapersonsnameageisaintusedtostoreapersonsage

Letsseehowtouseit

typepersonstruct

namestring

ageint

varPpersonpispersontype

Pname=AstaxieassignAstaxietothefieldnameofp

Page=25assign25tofieldageofp

fmtPrintf(ThepersonsnameissnPname)accessfieldnameofp

Therearethreemorewaystoinitializeastruct

Assigninitialvaluesbyorder

P=personTom25

Usetheformatfieldvaluetoinitializethestructwithoutorder

P=personage24nameBob

Defineananonymousstructtheninitializeit

P=structnamestringageintAmy18

Letsseeacompleteexample

struct

53

packagemain

importfmt

defineanewtype

typepersonstruct

namestring

ageint

structispassedbyvalue

comparetheageoftwopeoplethenreturntheolderpersonanddifferencesofage

funcOlder(p1p2person)(personint)

ifp1agegtp2age

returnp1p1age-p2age

returnp2p2age-p1age

funcmain()

vartomperson

tomnametomage=Tom18

bob=personage25nameBob

paul=personPaul43

tb_Oldertb_diff=Older(tombob)

tp_Oldertp_diff=Older(tompaul)

bp_Olderbp_diff=Older(bobpaul)

fmtPrintf(Ofsandssisolderbydyearsntomnamebobnametb_Oldernametb_diff)

fmtPrintf(Ofsandssisolderbydyearsntomnamepaulnametp_Oldernametp_diff)

fmtPrintf(Ofsandssisolderbydyearsnbobnamepaulnamebp_Oldernamebp_diff)

embeddedfieldsinstructIvejustintroducedtoyouhowtodefineastructwithfieldnamesandtypeInfactGosupportsfieldswithoutnamesbutwithtypesWecalltheseembeddedfields

Whentheembeddedfieldisastructallthefieldsinthatstructwillimplicitlybethefieldsinthestructinwhichithasbeenembedded

Letsseeoneexample

struct

54

packagemain

importfmt

typeHumanstruct

namestring

ageint

weightint

typeStudentstruct

HumanembeddedfielditmeansStudentstructincludesallfieldsthatHumanhas

specialtystring

funcmain()

instantiateandinitializeastudent

mark=StudentHumanMark25120ComputerScience

accessfields

fmtPrintln(Hisnameismarkname)

fmtPrintln(Hisageismarkage)

fmtPrintln(Hisweightismarkweight)

fmtPrintln(Hisspecialtyismarkspecialty)

modifymarksspecialty

markspecialty=AI

fmtPrintln(Markchangedhisspecialty)

fmtPrintln(Hisspecialtyismarkspecialty)

fmtPrintln(MarkbecomeoldHeisnotanathleteanymore)

markage=46

markweight+=60

fmtPrintln(Hisageismarkage)

fmtPrintln(Hisweightismarkweight)

Figure27EmbeddinginStudentandHuman

WeseethatwecanaccesstheageandnamefieldsinStudentjustlikewecaninHumanThisishowembeddedfieldsworkItsverycoolisntitHoldontheressomethingcoolerYoucanevenuseStudenttoaccessHumaninthisembeddedfield

markHuman=HumanMarcus55220

markHumanage-=1

AllthetypesinGocanbeusedasembeddedfields

struct

55

packagemain

importfmt

typeSkills[]string

typeHumanstruct

namestring

ageint

weightint

typeStudentstruct

Humanstructasembeddedfield

Skillsstringsliceasembeddedfield

intbuilt-intypeasembeddedfield

specialtystring

funcmain()

initializeStudentJane

jane=StudentHumanHumanJane35100specialtyBiology

accessfields

fmtPrintln(Hernameisjanename)

fmtPrintln(Herageisjaneage)

fmtPrintln(Herweightisjaneweight)

fmtPrintln(Herspecialtyisjanespecialty)

modifyvalueofskillfield

janeSkills=[]stringanatomy

fmtPrintln(HerskillsarejaneSkills)

fmtPrintln(Sheacquiredtwonewones)

janeSkills=append(janeSkillsphysicsgolang)

fmtPrintln(HerskillsnowarejaneSkills)

modifyembeddedfield

janeint=3

fmtPrintln(Herpreferrednumberisjaneint)

Intheaboveexamplewecanseethatalltypescanbeembeddedfieldsandwecanusefunctionstooperateonthem

ThereisonemoreproblemhoweverIfHumanhasafieldcalledphoneandStudenthasafieldwithsamenamewhatshouldwedo

GouseaverysimplewaytosolveitTheouterfieldsgetupperaccesslevelswhichmeanswhenyouaccessstudentphonewewillgetthefieldcalledphoneinstudentnottheoneintheHumanstructThisfeaturecanbesimplyseenasfieldoverloading

struct

56

packagemain

importfmt

typeHumanstruct

namestring

ageint

phonestringHumanhasphonefield

typeEmployeestruct

Human

specialtystring

phonestringphoneinemployee

funcmain()

Bob=EmployeeHumanBob34777-444-XXXXDesigner333-222

fmtPrintln(BobsworkphoneisBobphone)

fmtPrintln(BobspersonalphoneisBobHumanphone)

LinksDirectoryPrevioussectionControlstatementsandfunctionsNextsectionObject-oriented

struct

57

Object-orientedWetalkedaboutfunctionsandstructsinthelasttwosectionsbutdidyoueverconsiderusingfunctionsasfieldsofastructInthissectionIwillintroduceyoutoanotherformoffunctionthathasareceiverwhichiscalledamethod

methodSupposeyoudefinearectanglestructandyouwanttocalculateitsareaWedtypicallyusethefollowingcodetoachievethisgoal

packagemain

importfmt

typeRectanglestruct

widthheightfloat64

funcarea(rRectangle)float64

returnrwidthrheight

funcmain()

r1=Rectangle122

r2=Rectangle94

fmtPrintln(Areaofr1isarea(r1))

fmtPrintln(Areaofr2isarea(r2))

TheaboveexamplecancalculatearectanglesareaWeusethefunctioncalledareabutitsnotamethodoftherectanglestruct(likeclassmethodsinclassicobject-orientedlanguages)Thefunctionandstructaretwoindependentthingsasyoumaynotice

ItsnotaproblemsofarHoweverifyoualsohavetocalculatetheareaofacirclesquarepentagonoranyotherkindofshapeyouaregoingtoneedtoaddadditionalfunctionswithverysimilarnames

Figure28Relationshipbetweenfunctionandstruct

ObviouslythatsnotcoolAlsotheareashouldreallybethepropertyofacircleorrectangle

ThisiswhereamethodcomestoplayThemethodisafunctionaffiliatedwithatypeIthassimilarsyntaxasfunctionexceptafterthefunckeywordhasaparametercalledthereceiverwhichisthemainbodyofthatmethod

UsingthesameexampleRectangleArea()belongsdirectlytorectangleinsteadofasaperipheralfunctionMorespecificallylengthwidthandArea()allbelongtorectangle

AsRobPikesaid

Amethodisafunctionwithanimplicitfirstargumentcalledareceiver

Syntaxofmethod

func(rReceiverType)funcName(parameters)(results)

Letschangeourexampleusingmethodinstead

Object-oriented

58

packagemain

import(

fmt

math

)

typeCirclestruct

radiusfloat64

typeRectanglestruct

widthheightfloat64

method

func(cCircle)Area()float64

returncradiuscradiusmathPi

method

func(rRectangle)Area()float64

returnrwidthrheight

funcmain()

c1=Circle10

c2=Circle25

r1=Rectangle94

r2=Rectangle122

fmtPrintln(Areaofc1isc1Area())

fmtPrintln(Areaofc2isc2Area())

fmtPrintln(Areaofr1isr1Area())

fmtPrintln(Areaofr2isr2Area())

Notesforusingmethods

IfthenameofmethodsarethesamebuttheydontsharethesamereceiverstheyarenotthesameMethodsareabletoaccessfieldswithinreceiversUsetocallamethodinthestructthesamewayfieldsarecalled

Figure29Methodsaredifferentindifferentstructs

IntheexampleabovetheArea()methodsbelongtobothRectangleandCirclerespectivelysothereceiversareRectangleandCircle

OnethingthatsworthnotingisthatthemethodwithadottedlinemeansthereceiverispassedbyvaluenotbyreferenceThedifferencebetweenthemisthatamethodcanchangeitsreceiversvalueswhenthereceiverispassedbyreferenceanditgetsacopyofthereceiverwhenthereceiverispassedbyvalue

CanthereceiveronlybeastructOfcoursenotAnytypecanbethereceiverofamethodYoumaybeconfusedaboutcustomizedtypesStructisaspecialkindofcustomizedtype-therearemorecustomizedtypes

Usethefollowingformattodefineacustomizedtype

typetypeNametypeLiteral

Examplesofcustomizedtypes

Object-oriented

59

typeageint

typemoneyfloat32

typemonthsmap[string]int

m=months

January31

February28

December31

IhopethatyouknowhowtousecustomizedtypesnowSimilartotypedefinCweuseagestosubstituteintintheaboveexample

Letsgetbacktotalkingaboutmethod

Youcanuseasmanymethodsincustomtypesasyouwant

packagemain

importfmt

const(

WHITE=iota

BLACK

BLUE

RED

YELLOW

)

typeBoxstruct

widthheightdepthfloat64

colorColor

typeColorbyte

typeBoxList[]Boxasliceofboxes

method

func(bBox)Volume()float64

returnbwidthbheightbdepth

methodwithapointerreceiver

func(bBox)SetColor(cColor)

bcolor=c

method

func(blBoxList)BiggestsColor()Color

v=000

k=Color(WHITE)

for_b=rangebl

ifbVolume()gtv

v=bVolume()

k=bcolor

returnk

method

func(blBoxList)PaintItBlack()

fori_=rangebl

bl[i]SetColor(BLACK)

method

func(cColor)String()string

Object-oriented

60

strings=[]stringWHITEBLACKBLUEREDYELLOW

returnstrings[c]

funcmain()

boxes=BoxList

Box444RED

Box10101YELLOW

Box1120BLACK

Box10101BLUE

Box10301WHITE

Box202020YELLOW

fmtPrintf(Wehavedboxesinoursetnlen(boxes))

fmtPrintln(Thevolumeofthefirstoneisboxes[0]Volume()cmsup3)

fmtPrintln(Thecolorofthelastoneisboxes[len(boxes)-1]colorString())

fmtPrintln(ThebiggestoneisboxesBiggestsColor()String())

Letspaintthemallblack

boxesPaintItBlack()

fmtPrintln(Thecolorofthesecondoneisboxes[1]colorString())

fmtPrintln(ObviouslynowthebiggestoneisboxesBiggestsColor()String())

Wedefinesomeconstantsandcustomizedtypes

UseColorasaliasofbyteDefineastructBoxwhichhasfieldsheightwidthlengthandcolorDefineastructBoxListwhichhasBoxasitsfield

Thenwedefinedsomemethodsforourcustomizedtypes

Volume()usesBoxasitsreceiverandreturnsthevolumeofBoxSetColor(cColor)changesBoxscolorBiggestsColor()returnsthecolorwhichhasthebiggestvolumePaintItBlack()setscolorforallBoxinBoxListtoblackString()useColorasitsreceiverreturnsthestringformatofcolorname

IsitmuchclearerwhenweusewordstodescribeourrequirementsWeoftenwriteourrequirementsbeforewestartcoding

Usepointerasreceiver

LetstakealookatSetColormethodItsreceiverisapointerofBoxYesyoucanuseBoxasareceiverWhydoweuseapointerhereBecausewewanttochangeBoxscolorinthismethodThusifwedontuseapointeritwillonlychangethevalueinsideacopyofBox

Ifweseethatareceiveristhefirstargumentofamethoditsnothardtounderstandhowitworks

Youmightbeaskingwhywearentusing(b)Color=cinsteadofbColor=cintheSetColor()methodEitheroneisOKherebecauseGoknowshowtointerprettheassignmentDoyouthinkGoismorefascinatingnow

Youmayalsobeaskingwhetherweshoulduse(ampbl[i])SetColor(BLACK)inPaintItBlackbecausewepassapointertoSetColorAgaineitheroneisOKbecauseGoknowshowtointerpretit

Inheritanceofmethod

WelearnedaboutinheritanceoffieldsinthelastsectionSimilarlywealsohavemethodinheritanceinGoIfananonymousfieldhasmethodsthenthestructthatcontainsthefieldwillhaveallthemethodsfromitaswell

Object-oriented

61

packagemain

importfmt

typeHumanstruct

namestring

ageint

phonestring

typeStudentstruct

Humananonymousfield

schoolstring

typeEmployeestruct

Human

companystring

defineamethodinHuman

func(hHuman)SayHi()

fmtPrintf(HiIamsyoucancallmeonsnhnamehphone)

funcmain()

sam=EmployeeHumanSam45111-888-XXXXGolangInc

mark=StudentHumanMark25222-222-YYYYMIT

samSayHi()

markSayHi()

MethodOverridingIfwewantEmployeetohaveitsownmethodSayHiwecandefineamethodthathasthesamenameinEmployeeanditwillhideSayHiinHumanwhenwecallit

Object-oriented

62

packagemain

importfmt

typeHumanstruct

namestring

ageint

phonestring

typeStudentstruct

Human

schoolstring

typeEmployeestruct

Human

companystring

func(hHuman)SayHi()

fmtPrintf(HiIamsyoucancallmeonsnhnamehphone)

func(eEmployee)SayHi()

fmtPrintf(HiIamsIworkatsCallmeonsnename

ecompanyephone)Yesyoucansplitinto2lineshere

funcmain()

sam=EmployeeHumanSam45111-888-XXXXGolangInc

mark=StudentHumanMark25222-222-YYYYMIT

samSayHi()

markSayHi()

YouareabletowriteanObject-orientedprogramnowandmethodsuseruleofcapitallettertodecidewhetherpublicorprivateaswell

LinksDirectoryPrevioussectionstructNextsectioninterface

Object-oriented

63

26Interface

InterfaceOneofthesubtlestdesignfeaturesinGoareinterfacesAfterreadingthissectionyouwilllikelybeimpressedbytheirimplementation

Whatisaninterface

Inshortaninterfaceisasetofmethodsthatweusetodefineasetofactions

LiketheexamplesinprevioussectionsbothStudentandEmployeecanSayHi()buttheydontdothesamething

LetsdosomemoreworkWelladdonemoremethodSing()tothemalongwiththeBorrowMoney()methodtoStudentandtheSpendSalary()methodtoEmployee

NowStudenthasthreemethodscalledSayHi()Sing()andBorrowMoney()andEmployeehasSayHi()Sing()andSpendSalary()

ThiscombinationofmethodsiscalledaninterfaceandisimplementedbybothStudentandEmployeeSoStudentandEmployeeimplementtheinterfaceSayHi()andSing()AtthesametimeEmployeedoesntimplementtheinterfaceBorrowMoney()andStudentdoesntimplementtheinterfaceSpendSalary()ThisisbecauseEmployeedoesnthavethemethodBorrowMoney()andStudentdoesnthavethemethodSpendSalary()

TypeofInterfaceAninterfacedefinesasetofmethodssoifatypeimplementsallthemethodswesaythatitimplementstheinterface

interface

64

typeHumanstruct

namestring

ageint

phonestring

typeStudentstruct

Human

schoolstring

loanfloat32

typeEmployeestruct

Human

companystring

moneyfloat32

defineinterfaces

typeMeninterface

SayHi()

Sing(lyricsstring)

Guzzle(beerSteinstring)

typeYoungChapinterface

SayHi()

Sing(songstring)

BorrowMoney(amountfloat32)

typeElderlyGentinterface

SayHi()

Sing(songstring)

SpendSalary(amountfloat32)

func(hHuman)SayHi()

fmtPrintf(HiIamsyoucancallmeonsnhnamehphone)

func(hHuman)Sing(lyricsstring)

fmtPrintln(Lalalalalalalalalalalyrics)

func(hHuman)Guzzle(beerSteinstring)

fmtPrintln(GuzzleGuzzleGuzzlebeerStein)

EmployeeoverloadsSayHi

func(eEmployee)SayHi()

fmtPrintf(HiIamsIworkatsCallmeonsnename

ecompanyephone)Yesyoucansplitinto2lineshere

func(sStudent)BorrowMoney(amountfloat32)

sloan+=amount(againandagainand)

func(eEmployee)SpendSalary(amountfloat32)

emoney-=amountMorevodkapleaseGetmethroughtheday

Weknowthataninterfacecanbeimplementedbyanytypeandonetypecanimplementmanyinterfacessimultaneously

Notethatanytypeimplementstheemptyinterfaceinterfacebecauseitdoesnthaveanymethodsandalltypeshavezeromethodsbydefault

Valueofinterface

interface

65

SowhatkindofvaluescanbeputintheinterfaceIfwedefineavariableasatypeinterfaceanytypethatimplementstheinterfacecanassignedtothisvariable

LiketheaboveexampleifwedefineavariablemasinterfaceMenthenanyoneofStudentHumanorEmployeecanbeassignedtomSowecouldhaveasliceofMenandanytypethatimplementsinterfaceMencanassigntothissliceBeawarehoweverthatthesliceofinterfacedoesnthavethesamebehaviorasasliceofothertypes

packagemain

importfmt

typeHumanstruct

namestring

ageint

phonestring

typeStudentstruct

Human

schoolstring

loanfloat32

typeEmployeestruct

Human

companystring

moneyfloat32

InterfaceMenimplementedbyHumanStudentandEmployee

typeMeninterface

SayHi()

Sing(lyricsstring)

method

func(hHuman)SayHi()

fmtPrintf(HiIamsyoucancallmeonsnhnamehphone)

method

func(hHuman)Sing(lyricsstring)

fmtPrintln(Lalalalalyrics)

method

func(eEmployee)SayHi()

fmtPrintf(HiIamsIworkatsCallmeonsnename

ecompanyephone)Yesyoucansplitinto2lineshere

funcmain()

mike=StudentHumanMike25222-222-XXXMIT000

paul=StudentHumanPaul26111-222-XXXHarvard100

sam=EmployeeHumanSam36444-222-XXXGolangInc1000

tom=EmployeeHumanSam36444-222-XXXThingsLtd5000

defineinterfacei

variMen

icanstoreStudent

i=mike

fmtPrintln(ThisisMikeaStudent)

iSayHi()

iSing(Novemberrain)

icanstoreEmployee

i=tom

fmtPrintln(ThisisTomanEmployee)

iSayHi()

interface

66

iSing(Borntobewild)

sliceofMen

fmtPrintln(LetsuseasliceofMenandseewhathappens)

x=make([]Men3)

thesethreeelementsaredifferenttypesbuttheyallimplementedinterfaceMen

x[0]x[1]x[2]=paulsammike

for_value=rangex

valueSayHi()

Aninterfaceisasetofabstractmethodsandcanbeimplementedbynon-interfacetypesItcannotthereforeimplementitself

Emptyinterface

AnemptyinterfaceisaninterfacethatdoesntcontainanymethodssoalltypesimplementanemptyinterfaceThisfactisveryusefulwhenwewanttostorealltypesatsomepointandissimilartovoidinC

defineaasemptyinterface

varvoidinterface

vars

i=5

s=Helloworld

acanstorevalueofanytype

void=i

void=s

Ifafunctionusesanemptyinterfaceasitsargumenttypeitcanacceptanytypeifafunctionusesemptyinterfaceasitsreturnvaluetypeitcanreturnanytype

Methodargumentsofaninterface

AnyvariablecanbeusedinaninterfaceSohowcanweusethisfeaturetopassanytypeofvariabletoafunction

ForexampleweusefmtPrintlnalotbuthaveyouevernoticedthatitcanacceptanytypeofargumentLookingattheopensourcecodeoffmtweseethefollowingdefinition

typeStringerinterface

String()string

ThismeansanytypethatimplementsinterfaceStringercanbepassedtofmtPrintlnasanargumentLetsproveit

interface

67

packagemain

import(

fmt

strconv

)

typeHumanstruct

namestring

ageint

phonestring

HumanimplementsfmtStringer

func(hHuman)String()string

returnName+hname+Age+strconvItoa(hage)+yearsContact+hphone

funcmain()

Bob=HumanBob39000-7777-XXX

fmtPrintln(ThisHumanisBob)

LookingbacktotheexampleofBoxyouwillfindthatColorimplementsinterfaceStringeraswellsoweareabletocustomizetheprintformatIfwedontimplementthisinterfacefmtPrintlnprintsthetypewithitsdefaultformat

fmtPrintln(ThebiggestoneisboxesBiggestsColor()String())

fmtPrintln(ThebiggestoneisboxesBiggestsColor())

AttentionIfthetypeimplementedtheinterfaceerrorfmtwillcallError()soyoudonthavetoimplementStringeratthispoint

TypeofvariableinaninterfaceIfavariableisthetypethatimplementsaninterfaceweknowthatanyothertypethatimplementsthesameinterfacecanbeassignedtothisvariableThequestionishowcanweknowthespecifictypestoredintheinterfaceTherearetwowayswhichIwillshowyou

AssertionofComma-okpattern

Gohasthesyntaxvalueok=element(T)ThischeckstoseeifthevariableisthetypethatweexpectwherevalueisthevalueofthevariableokisavariableofbooleantypeelementistheinterfacevariableandtheTisthetypeofassertion

Iftheelementisthetypethatweexpectokwillbetruefalseotherwise

Letsuseanexampletoseemoreclearly

interface

68

packagemain

import(

fmt

strconv

)

typeElementinterface

typeList[]Element

typePersonstruct

namestring

ageint

func(pPerson)String()string

return(name+pname+-age+strconvItoa(page)+years)

funcmain()

list=make(List3)

list[0]=1anint

list[1]=Helloastring

list[2]=PersonDennis70

forindexelement=rangelist

ifvalueok=element(int)ok

fmtPrintf(list[d]isanintanditsvalueisdnindexvalue)

elseifvalueok=element(string)ok

fmtPrintf(list[d]isastringanditsvalueissnindexvalue)

elseifvalueok=element(Person)ok

fmtPrintf(list[d]isaPersonanditsvalueissnindexvalue)

else

fmtPrintf(list[d]isofadifferenttypenindex)

Itsquiteeasytousethispatternbutifwehavemanytypestotestwedbetteruseswitch

switchtest

Letsuseswitchtorewritetheaboveexample

interface

69

packagemain

import(

fmt

strconv

)

typeElementinterface

typeList[]Element

typePersonstruct

namestring

ageint

func(pPerson)String()string

return(name+pname+-age+strconvItoa(page)+years)

funcmain()

list=make(List3)

list[0]=1anint

list[1]=Helloastring

list[2]=PersonDennis70

forindexelement=rangelist

switchvalue=element(type)

caseint

fmtPrintf(list[d]isanintanditsvalueisdnindexvalue)

casestring

fmtPrintf(list[d]isastringanditsvalueissnindexvalue)

casePerson

fmtPrintf(list[d]isaPersonanditsvalueissnindexvalue)

default

fmtPrintln(list[d]isofadifferenttypeindex)

Onethingyoushouldrememberisthatelement(type)cannotbeusedoutsideoftheswitchbodywhichmeansinthatcaseyouhavetousethecomma-okpattern

Embeddedinterfaces

ThemostbeautifulthingisthatGohasalotofbuilt-inlogicsyntaxsuchasanonymousfieldsinstructNotsuprisinglywecanuseinterfacesasanonymousfieldsaswellbutwecallthemEmbeddedinterfacesHerewefollowthesamerulesasanonymousfieldsMorespecificallyifaninterfacehasanotherinterfaceembeddedwithinititwillbehaveasifithasallthemethodsthattheembeddedinterfacehas

Wecanseethatthesourcefileincontainerheaphasthefollowingdefinition

typeInterfaceinterface

sortInterfaceembeddedsortInterface

Push(xinterface)aPushmethodtopushelementsintotheheap

Pop()interfaceaPopmethodthatpopselementsfromtheheap

WeseethatsortInterfaceisanembeddedinterfacesotheaboveInterfacehasthethreemethodscontainedwithinthesortInterfaceimplicitly

interface

70

typeInterfaceinterface

Lenisthenumberofelementsinthecollection

Len()int

Lessreturnswhethertheelementwithindexishouldsort

beforetheelementwithindexj

Less(ijint)bool

Swapswapstheelementswithindexesiandj

Swap(ijint)

AnotherexampleistheioReadWriterinpackageio

ioReadWriter

typeReadWriterinterface

Reader

Writer

Reflection

ReflectioninGoisusedfordetermininginformationatruntimeWeusethereflectpackageandTheLawsofReflectionpostexplainshowreflectworksinGo

TherearethreestepsinvolvedwhenusingreflectFirstweneedtoconvertaninterfacetoreflecttypes(reflectTypeorreflectValuethisdependsonthesituation)

t=reflectTypeOf(i)getmeta-dataintypeiandusettogetallelements

v=reflectValueOf(i)getactualvalueintypeiandusevtochangeitsvalue

Afterthatwecanconvertthereflectedtypestogetthevaluesthatweneed

varxfloat64=34

t=reflectTypeOf(x)

v=reflectValueOf(x)

fmtPrintln(typet)

fmtPrintln(valuev)

fmtPrintln(kindisfloat64vKind()==reflectFloat64)

FinallyifwewanttochangethevaluesofthereflectedtypesweneedtomakeitmodifiableAsdiscussedearlierthereisadifferencebetweenpassbyvalueandpassbyreferenceThefollowingcodewillnotcompile

varxfloat64=34

v=reflectValueOf(x)

vSetFloat(71)

Insteadwemustusethefollowingcodetochangethevaluesfromreflecttypes

varxfloat64=34

p=reflectValueOf(ampx)

v=pElem()

vSetFloat(71)

Wehavejustdiscussedthebasicsofreflectionhoweveryoumustpracticemoreinordertounderstandmore

Links

interface

71

DirectoryPrevioussectionObject-orientedNextsectionConcurrency

interface

72

ConcurrencyItissaidthatGoistheCofthe21stcenturyIthinktherearetworeasonsforitFirstGoisasimplelanguageSecondconcurrencyisahottopicintodaysworldandGosupportsthisfeatureatthelanguagelevel

goroutinegoroutinesandconcurrencyarebuiltintothecoredesignofGoTheyresimilartothreadsbutworkdifferentlyGoalsogivesyoufullsupporttosharingmemoryinyourgoroutinesOnegoroutineusuallyuses4~5KBofstackmemoryThereforeitsnothardtorunthousandsofgoroutinesonasinglecomputerAgoroutineismorelightweightmoreefficientandmoreconvenientthansystemthreads

goroutinesrunonthethreadmanageratruntimeinGoWeusethegokeywordtocreateanewgoroutinewhichisafunctionattheunderlyinglevel(main()isagoroutine)

gohello(abc)

Letsseeanexample

packagemain

import(

fmt

runtime

)

funcsay(sstring)

fori=0ilt5i++

runtimeGosched()

fmtPrintln(s)

funcmain()

gosay(world)createanewgoroutine

say(hello)currentgoroutine

Output

hello

world

hello

world

hello

world

hello

world

hello

WeseethatitsveryeasytouseconcurrencyinGobyusingthekeywordgoIntheaboveexamplethesetwogoroutinessharesomememorybutwewouldbetterofffollowingthedesignrecipeDontuseshareddatatocommunicateusecommunicationtosharedata

runtimeGosched()meanslettheCPUexecuteothergoroutinesandcomebackatsomepoint

InGo15theruntimenowsetsthedefaultnumberofthreadstorunsimultaneouslydefinedbyGOMAXPROCStothenumberofcoresavailableontheCPU

Concurrency

73

BeforeGo15ThescheduleronlyusesonethreadtorunallgoroutineswhichmeansitonlyimplementsconcurrencyIfyouwanttousemoreCPUcoresinordertotakeadvantageofparallelprocessingyouhavetocallruntimeGOMAXPROCS(n)tosetthenumberofcoresyouwanttouseIfnlt1itchangesnothing

channelsgoroutinesruninthesamememoryaddressspacesoyouhavetomaintainsynchronizationwhenyouwanttoaccesssharedmemoryHowdoyoucommunicatebetweendifferentgoroutinesGousesaverygoodcommunicationmechanismcalledchannelAchannelisliketwo-waypipelineinUnixshellsusechanneltosendorreceivedataTheonlydatatypethatcanbeusedinchannelsisthetypechannelandthekeywordchanBeawarethatyouhavetousemaketocreateanewchannel

ci=make(chanint)

cs=make(chanstring)

cf=make(chaninterface)

channelusestheoperatorlt-tosendorreceivedata

chlt-vsendvtochannelch

v=lt-chreceivedatafromchandassigntov

Letsseemoreexamples

packagemain

importfmt

funcsum(a[]intcchanint)

total=0

for_v=rangea

total+=v

clt-totalsendtotaltoc

funcmain()

a=[]int728-940

c=make(chanint)

gosum(a[len(a)2]c)

gosum(a[len(a)2]c)

xy=lt-clt-creceivefromc

fmtPrintln(xyx+y)

SendingandreceivingdatainchannelsblocksbydefaultsoitsmucheasiertousesynchronousgoroutinesWhatImeanbyblockisthatagoroutinewillnotcontinuewhenreceivingdatafromanemptychannelie(value=lt-ch)untilothergoroutinessenddatatothischannelOntheotherhandthegoroutinewillnotcontinueuntilthedataitsendstoachannelie(chlt-5)isreceived

BufferedchannelsIintroducednon-bufferedchannelsaboveGoalsohasbufferedchannelsthatcanstoremorethanasingleelementForexamplech=make(chanbool4)herewecreateachannelthatcanstore4booleanelementsSointhischannelweareabletosend4elementsintoitwithoutblockingbutthegoroutinewillbeblockedwhenyoutrytosendafifthelementandnogoroutinereceivesit

Concurrency

74

ch=make(chantypen)

n==0non-buffer(block)

ngt0buffer(non-blockuntilnelementsinthechannel)

Youcantrythefollowingcodeonyourcomputerandchangesomevalues

packagemain

importfmt

funcmain()

c=make(chanint2)change2to1willhaveruntimeerrorbut3isfine

clt-1

clt-2

fmtPrintln(lt-c)

fmtPrintln(lt-c)

RangeandCloseWecanuserangetooperateonbufferchannelsasinsliceandmap

packagemain

import(

fmt

)

funcfibonacci(nintcchanint)

xy=11

fori=0iltni++

clt-x

xy=yx+y

close(c)

funcmain()

c=make(chanint10)

gofibonacci(cap(c)c)

fori=rangec

fmtPrintln(i)

fori=rangecwillnotstopreadingdatafromchanneluntilthechannelisclosedWeusethekeywordclosetoclosethechannelinaboveexampleItsimpossibletosendorreceivedataonaclosedchannelyoucanusevok=lt-chtotestifachannelisclosedIfokreturnsfalseitmeansthethereisnodatainthatchannelanditwasclosed

Remembertoalwaysclosechannelsinproducersandnotinconsumersoritsveryeasytogetintopanicstatus

AnotherthingyouneedtorememberisthatchannelsarenotlikefilesYoudonthavetoclosethemfrequentlyunlessyouaresurethechanneliscompletelyuselessoryouwanttoexitrangeloops

SelectIntheaboveexamplesweonlyuseonechannelbuthowcanwedealwithmorethanonechannelGohasakeywordcalledselecttolistentomanychannels

Concurrency

75

selectisblockingbydefaultanditcontinuestoexecuteonlywhenoneofchannelshasdatatosendorreceiveIfseveralchannelsarereadytouseatthesametimeselectchooseswhichtoexecuterandomly

packagemain

importfmt

funcfibonacci(cquitchanint)

xy=11

for

select

caseclt-x

xy=yx+y

caselt-quit

fmtPrintln(quit)

return

funcmain()

c=make(chanint)

quit=make(chanint)

gofunc()

fori=0ilt10i++

fmtPrintln(lt-c)

quitlt-0

()

fibonacci(cquit)

selecthasadefaultcaseaswelljustlikeswitchWhenallthechannelsarenotreadyforuseitexecutesthedefaultcase(itdoesntwaitforthechannelanymore)

select

casei=lt-c

usei

default

executesherewhencisblocked

TimeoutSometimesagoroutinebecomesblockedHowcanweavoidthistopreventthewholeprogramfromblockingItssimplewecansetatimeoutintheselect

funcmain()

c=make(chanint)

o=make(chanbool)

gofunc()

for

select

casev=lt-c

println(v)

caselt-timeAfter(5timeSecond)

println(timeout)

olt-true

break

()

lt-o

Concurrency

76

RuntimegoroutineThepackageruntimehassomefunctionsfordealingwithgoroutines

runtimeGoexit()

Exitsthecurrentgoroutinebutdeferedfunctionswillbeexecutedasusual

runtimeGosched()

Letstheschedulerexecuteothergoroutinesandcomesbackatsomepoint

runtimeNumCPU()int

ReturnsthenumberofCPUcores

runtimeNumGoroutine()int

Returnsthenumberofgoroutines

runtimeGOMAXPROCS(nint)int

SetshowmanyCPUcoresyouwanttouse

LinksDirectoryPrevioussectioninterfaceNextsectionSummary

Concurrency

77

28SummaryInthischapterwemainlyintroducedthe25GokeywordsLetsreviewwhattheyareandwhattheydo

breakdefaultfuncinterfaceselect

casedefergomapstruct

chanelsegotopackageswitch

constfallthroughifrangetype

continueforimportreturnvar

varandconstareusedtodefinevariablesandconstantspackageandimportareforpackageusefuncisusedtodefinefunctionsandmethodsreturnisusedtoreturnvaluesinfunctionsormethodsdeferisusedtodefinedeferfunctionsgoisusedtostartanewgoroutineselectisusedtoswitchovermultiplechannelsforcommunicationinterfaceisusedtodefineinterfacesstructisusedtodefinespecialcustomizedtypesbreakcasecontinueforfallthroughelseifswitchgotoanddefaultwereintroducedinsection23chanisthetypeofchannelforcommunicationamonggoroutinestypeisusedtodefinecustomizedtypesmapisusedtodefinemapwhichissimilartohashtablesinotherlanguagesrangeisusedforreadingdatafromslicemapandchannel

Ifyouunderstandhowtousethese25keywordsyouvelearnedalotofGoalready

LinksDirectoryPrevioussectionConcurrencyNextchapterWebfoundation

Summary

78

3WebfoundationThereasonyouarereadingthisbookisthatyouwanttolearntobuildwebapplicationsinGoAsIvesaidbeforeGoprovidesmanypowerfulpackageslikehttpThesepackagescanhelpyoualotwhentryingtobuildwebapplicationsIllteachyoueverythingyouneedtoknowinthefollowingchaptersandwelltalkaboutsomeconceptsofthewebandhowtorunwebapplicationsinGointhischapter

LinksDirectoryPreviouschapterChapter2SummaryNextsectionWebworkingprinciples

Webfoundation

79

WebworkingprinciplesEverytimeyouopenyourbrowserstypesomeURLsandpressenteryouwillseebeautifulwebpagesappearonyourscreenButdoyouknowwhatishappeningbehindthesesimpleactions

NormallyyourbrowserisaclientAfteryoutypeaURLittakesthehostpartoftheURLandsendsittoaDomainNameServer(DNS)inordertogettheIPaddressofthehostThenitconnectstotheIPaddressandaskstosetupaTCPconnectionThebrowsersendsHTTPrequeststhroughtheconnectionTheserverhandlesthemandreplieswithHTTPresponsescontainingthecontentthatmakeupthewebpageFinallythebrowserrendersthebodyofthewebpageanddisconnectsfromtheserver

Figure31Processesofusersvisitawebsite

AwebserveralsoknownasanHTTPserverusestheHTTPprotocoltocommunicatewithclientsAllwebbrowserscanbeconsideredclients

Wecandividethewebsworkingprinciplesintothefollowingsteps

ClientusesTCPIPprotocoltoconnecttoserverClientsendsHTTPrequestpackagestoserverServerreturnsHTTPresponsepackagestoclientIftherequestedresourcesincludedynamicscriptsservercallsscriptenginefirstClientdisconnectsfromserverstartsrenderingHTML

ThisisasimpleworkflowofHTTPaffairs-noticethattheserverclosesitsconnectionsafteritsendsdatatotheclientsthenwaitsforthenextrequest

URLandDNSresolutionWealwaysuseURLstoaccesswebpagesbutdoyouknowhowURLswork

ThefullnameofaURLisUniformResourceLocatorItsfordescribingresourcesontheinternetanditsbasicformisasfollows

schemehost[port]path[query-string][anchor]

schemeassignunderlyingprotocol(suchasHTTPHTTPSFTP)

hostIPordomainnameofHTTPserver

portdefaultportis80anditcanbeomittedinthiscase

IfyouwanttouseotherportsyoumustspecifywhichportForexample

httpwwwcnblogscom8080

pathresourcespath

query-stringdataaresenttoserver

anchoranchor

DNSisanabbreviationofDomainNameSystemItsthenamingsystemforcomputernetworkservicesanditconvertsdomainnamestoactualIPaddressesjustlikeatranslator

Figure32DNSworkingprinciples

TounderstandmoreaboutitsworkingprincipleletsseethedetailedDNSresolutionprocessasfollows

1 AftertypingthedomainnamewwwqqcominthebrowsertheoperatingsystemwillcheckifthereareanymappingrelationshipsinthehostsfilesforthisdomainnameIfsothenthedomainnameresolutioniscomplete

2 IfnomappingrelationshipsexistinthehostsfilestheoperatingsystemwillcheckifanycacheexistsintheDNSIfso

Webworkingprinciples

80

thenthedomainnameresolutioniscomplete3 IfnomappingrelationshipsexistinboththehostandDNScachetheoperatingsystemfindsthefirstDNSresolution

serverinyourTCPIPsettingswhichislikelyyourlocalDNSserverWhenthelocalDNSserverreceivesthequeryifthedomainnamethatyouwanttoqueryiscontainedwithinthelocalconfigurationofitsregionalresourcesitreturnstheresultstotheclientThisDNSresolutionisauthoritative

4 IfthelocalDNSserverdoesntcontainthedomainnamebutamappingrelationshipexistsinthecachethelocalDNSservergivesbackthisresulttotheclientThisDNSresolutionisnotauthoritative

5 IfthelocalDNSservercannotresolvethisdomainnameeitherbyconfigurationofregionalresourcesorcacheitwillproceedtothenextstepwhichdependsonthelocalDNSserverssettings-IfthelocalDNSserverdoesntenableforwardingitroutestherequesttotherootDNSserverthenreturnstheIPaddressofatoplevelDNSserverwhichmayknowthedomainnamecominthiscaseIfthefirsttoplevelDNSserverdoesntrecognizethedomainnameitagainreroutestherequesttothenexttoplevelDNSserveruntilitreachesonethatrecognizesthedomainnameThenthetoplevelDNSserverasksthisnextlevelDNSserverfortheIPaddresscorrespondingtowwwqqcom-IfthelocalDNSserverhasforwardingenableditsendstherequesttoanupperlevelDNSserverIftheupperlevelDNSserveralsodoesntrecognizethedomainnamethentherequestkeepsgettingreroutedtohigherlevelsuntilitfinallyreachesaDNSserverwhichrecognizesthedomainname

WhetherornotthelocalDNSserverenablesforwardingtheIPaddressofthedomainnamealwaysreturnstothelocalDNSserverandthelocalDNSserversendsitbacktotheclient

Figure33DNSresolutionworkflow

RecursivequeryprocesssimplymeansthattheenquirerschangeintheprocessEnquirersdonotchangeinIterativequeryprocesses

NowweknowclientsgetIPaddressesintheendsothebrowsersarecommunicatingwithserversthroughIPaddresses

HTTPprotocolTheHTTPprotocolisacorepartofwebservicesItsimportanttoknowwhattheHTTPprotocolisbeforeyouunderstandhowthewebworks

HTTPistheprotocolthatisusedtofacilitatecommunicationbetweenbrowserandwebserverItisbasedontheTCPprotocolandusuallyusesport80onthesideofthewebserverItisaprotocolthatutilizestherequest-responsemodel-clientssendrequestsandserversrespondAccordingtotheHTTPprotocolclientsalwayssetupnewconnectionsandsendHTTPrequeststoserversServersarenotabletoconnecttoclientsproactivelyorestablishcallbackconnectionsTheconnectionbetweenaclientandaservercanbeclosedbyeithersideForexampleyoucancancelyourdownloadrequestandHTTPconnectionandyourbrowserwilldisconnectfromtheserverbeforeyoufinishdownloading

TheHTTPprotocolisstatelesswhichmeanstheserverhasnoideaabouttherelationshipbetweenthetwoconnectionseventhoughtheyarebothfromsameclientTosolvethisproblemwebapplicationsusecookiestomaintainthestateofconnections

BecausetheHTTPprotocolisbasedontheTCPprotocolallTCPattackswillaffectHTTPcommunicationsinyourserverExamplesofsuchattacksareSYNfloodingDoSandDDoSattacks

HTTPrequestpackage(browserinformation)

RequestpackagesallhavethreepartsrequestlinerequestheaderandbodyThereisoneblanklinebetweenheaderandbody

Webworkingprinciples

81

GETdomainsexampleHTTP11requestlinerequestmethodURLprotocolanditsversion

Hostwwwianaorgdomainname

User-AgentMozilla50(WindowsNT61)AppleWebKit5374(KHTMLlikeGecko)Chrome220122994Safari5374

browserinformation

Accepttexthtmlapplicationxhtml+xmlapplicationxmlq=09q=08mimethatclientscanaccept

Accept-Encodinggzipdeflatesdchstreamcompression

Accept-CharsetUTF-8q=05charactersetinclientside

blankline

bodyrequestresourcearguments(forexampleargumentsinPOST)

Weusefiddlertogetthefollowingrequestinformation

Figure34InformationofaGETrequestcaughtbyfiddler

Figure35InformationofaPOSTrequestcaughtbyfiddler

WecanseethatGETdoesnothavearequestbodyunlikePOSTwhichdoes

TherearemanymethodsyoucanusetocommunicatewithserversinHTTPGETPOSTPUTandDELETEarethe4basicmethodsthatwetypicallyuseAURLrepresentsaresourceonanetworksothese4methodsdefinethequerychangeaddanddeleteoperationsthatcanactontheseresourcesGETandPOSTareverycommonlyusedinHTTPGETcanappendqueryparameterstotheURLusingtoseparatetheURLandparametersandampbetweentheargumentslikeEditPostsaspxname=test1ampid=123456POSTputsdataintherequestbodybecausetheURLimplementsalengthlimitationviathebrowserThusPOSTcansubmitmuchmoredatathanGETAlsowhenwesubmitusernamesandpasswordswedontwantthiskindofinformationtoappearintheURLsoweusePOSTtokeeptheminvisible

HTTPresponsepackage(serverinformation)Letsseewhatinformationiscontainedintheresponsepackages

HTTP11200OKstatusline

Servernginx108webserversoftwareanditsversionintheservermachine

DateDateTue30Oct2012041425GMTrespondedtime

Content-Typetexthtmlrespondeddatatype

Transfer-Encodingchunkeditmeansdataweresentinfragments

Connectionkeep-alivekeepconnection

Content-Length90lengthofbody

blankline

ltDOCTYPEhtmlPUBLIC-W3CDTDXHTML10TransitionalENmessagebody

ThefirstlineiscalledthestatuslineItsuppliestheHTTPversionstatuscodeandstatusmessage

ThestatuscodeinformstheclientofthestatusoftheHTTPserversresponseInHTTP115kindsofstatuscodesweredefined

-1xxInformational

-2xxSuccess

-3xxRedirection

-4xxClientError

-5xxServerError

Letsseemoreexamplesaboutresponsepackages200meansserverrespondedcorrectly302meansredirection

Figure36Fullinformationforvisitingawebsite

HTTPisstatelessandConnectionkeep-alive

Webworkingprinciples

82

ThetermstatelessdoesntmeanthattheserverhasnoabilitytokeepaconnectionItsimplymeansthattheserverdoesntrecognizeanyrelationshipsbetweenanytworequests

InHTTP11Keep-aliveisusedbydefaultIfclientshaveadditionalrequeststheywillusethesameconnectionforthem

NoticethatKeep-alivecannotmaintainoneconnectionforevertheapplicationrunningintheserverdeterminesthelimitwithwhichtokeeptheconnectionaliveforandinmostcasesyoucanconfigurethislimit

Requestinstance

Figure37Allpackagesforopeningonewebpage

WecanseetheentirecommunicationprocessbetweenclientandserverfromtheabovepictureYoumaynoticethattherearemanyresourcefilesinthelistthesearecalledstaticfilesandGohasspecializedprocessingmethodsforthesefiles

ThisisthemostimportantfunctionofbrowserstorequestforaURLandretrievedatafromwebserversthenrendertheHTMLIfitfindssomefilesintheDOMsuchasCSSorJSfilesbrowserswillrequesttheseresourcesfromtheserveragainuntilalltheresourcesfinishrenderingonyourscreen

ReducingHTTPrequesttimesisonewayofimprovingtheloadingspeedofwebpagesByreducingthenumberofCSSandJSfilesthatneedtobeloadedbothrequestlatenciesandpressureonyourwebserverscanbereducedatthesametime

LinksDirectoryPrevioussectionWebfoundationNextsectionBuildasimplewebserver

Webworkingprinciples

83

32BuildasimplewebserverWevediscussedthatwebapplicationsarebasedontheHTTPprotocolandGoprovidesfullHTTPsupportinthenethttppackageItsveryeasytosetawebserverupusingthispackage

Usehttppackagesetupawebserver

packagemain

import(

fmt

nethttp

strings

log

)

funcsayhelloName(whttpResponseWriterrhttpRequest)

rParseForm()parseargumentsyouhavetocallthisbyyourself

fmtPrintln(rForm)printforminformationinserverside

fmtPrintln(pathrURLPath)

fmtPrintln(schemerURLScheme)

fmtPrintln(rForm[url_long])

forkv=rangerForm

fmtPrintln(keyk)

fmtPrintln(valstringsJoin(v))

fmtFprintf(wHelloastaxie)senddatatoclientside

funcmain()

httpHandleFunc(sayhelloName)setrouter

err=httpListenAndServe(9090nil)setlistenport

iferr=nil

logFatal(ListenAndServeerr)

Afterweexecutetheabovecodetheserverbeginslisteningtoport9090inlocalhost

Openyourbrowserandvisithttplocalhost9090YoucanseethatHelloastaxieisonyourscreen

Letstryanotheraddresswithadditionalargumentshttplocalhost9090url_long=111ampurl_long=222

Nowletsseewhathappensonboththeclientandserversides

Youshouldseethefollowinginformationontheserverside

Figure38Serverprintedinformation

Asyoucanseeweonlyneedtocalltwofunctionsinordertobuildasimplewebserver

IfyouareworkingwithPHPyoureprobablyaskingwhetherornotweneedsomethinglikeNginxorApacheTheansweriswedontsinceGolistenstotheTCPportbyitselfandthefunctionsayhelloNameisthelogicfunctionjustlikeacontrollerinPHP

IfyouareworkingwithPythonyoushouldknowtornadoandtheaboveexampleisverysimilartothat

IfyouareworkingwithRubyyoumaynoticeitislikescriptserverinROR(RubyonRails)

Buildasimplewebserver

84

WeusedtwosimplefunctionstosetupasimplewebserverinthissectionandthissimpleserveralreadyhasthecapacityforhighconcurrencyoperationsWewilltalkabouthowtoutilizethisinthenexttwosections

LinksDirectoryPrevioussectionWebworkingprinciplesNextsectionHowGoworkswithweb

Buildasimplewebserver

85

33HowGoworkswithwebWelearnedtousethenethttppackagetobuildasimplewebserverintheprevioussectionandallthoseworkingprinciplesarethesameasthosewewilltalkaboutinthefirstsectionofthischapter

ConceptsinwebprinciplesRequestrequestdatafromusersincludingPOSTGETCookieandURL

Responseresponsedatafromservertoclients

Connconnectionsbetweenclientsandservers

HandlerRequesthandlinglogicandresponsegeneration

httppackageoperatingmechanismThefollowingpictureshowstheworkflowofaGowebserver

Figure39httpworkflow

1 Createalisteningsocketlistentoaportandwaitforclients2 Acceptrequestsfromclients3 HandlerequestsreadHTTPheaderIftherequestusesPOSTmethodreaddatainthemessagebodyandpassthem

tohandlersFinallysocketreturnsresponsedatatoclients

OnceweknowtheanswerstothethreefollowingquestionsitseasytoknowhowthewebworksinGo

HowdowelistentoaportHowdoweacceptclientrequestsHowdoweallocatehandlers

IntheprevioussectionwesawthatGousesListenAndServetohandlethesestepsinitializeaserverobjectcallnetListen(tcpaddr)tosetupaTCPlistenerandlistentoaspecificaddressandport

Letstakealookatthehttppackagessourcecode

HowGoworkswithweb

86

Buildversiongo112

func(srvServer)Serve(lnetListener)error

deferlClose()

vartempDelaytimeDurationhowlongtosleeponacceptfailure

for

rwe=lAccept()

ife=nil

ifneok=e(netError)okampampneTemporary()

iftempDelay==0

tempDelay=5timeMillisecond

else

tempDelay=2

ifmax=1timeSecondtempDelaygtmax

tempDelay=max

logPrintf(httpAccepterrorvretryinginvetempDelay)

timeSleep(tempDelay)

continue

returne

tempDelay=0

cerr=srvnewConn(rw)

iferr=nil

continue

gocserve()

HowdoweacceptclientrequestsafterwebeginlisteningtoaportInthesourcecodewecanseethatsrvServe(netListener)iscalledtohandleclientrequestsInthebodyofthefunctionthereisaforItacceptsarequestcreatesanewconnectionthenstartsanewgoroutinepassingtherequestdatatothegocserve()goroutineThisishowGosupportshighconcurrencyandeverygoroutineisindependent

HowdoweusespecificfunctionstohandlerequestsconnparsesrequestcReadRequest()atfirstthengetsthecorrespondinghandlerhandler=shsrvHandlerwhichisthesecondargumentwepassedwhenwecalledListenAndServeBecausewepassednilGousesitsdefaulthandlerhandler=DefaultServeMuxSowhatisDefaultServeMuxdoinghereWellitstheroutervariablewhichcancallhandlerfunctionsforspecificURLsDidwesetthisYeswedidWedidthisinthefirstlinewhereweusedhttpHandleFunc(sayhelloName)WereusingthisfunctiontoregistertherouterruleforthepathWhentheURListheroutercallsthefunctionsayhelloNameDefaultServeMuxcallsServerHTTPtogethandlerfunctionsfordifferentpathscallingsayhelloNameinthisspecificcaseFinallytheserverwritesdataandrespondstoclients

Detailedworkflow

Figure310WorkflowofhandlinganHTTPrequest

IthinkyoushouldknowhowGorunswebserversnow

LinksDirectoryPrevioussectionBuildasimplewebserverNextsectionGetintohttppackage

HowGoworkswithweb

87

HowGoworkswithweb

88

34GetintohttppackageInprevioussectionswelearnedabouttheworkflowofthewebandtalkedalittlebitaboutGoshttppackageInthissectionwearegoingtolearnabouttwocorefunctionsinthehttppackageConnandServeMux

goroutineinConnUnlikenormalHTTPserversGousesgoroutinesforeveryjobinitiatedbyConninordertoachievehighconcurrencyandperformancesoeveryjobisindependent

Gousesthefollowingcodetowaitfornewconnectionsfromclients

cerr=srvnewConn(rw)

iferr=nil

continue

gocserve()

Asyoucanseeitcreatesanewgoroutineforeveryconnectionandpassesthehandlerthatisabletoreaddatafromtherequesttothegoroutine

CustomizedServeMuxWeusedGosdefaultrouterinprevioussectionswhendiscussingconnserverwiththerouterpassingrequestdatatoaback-endhandler

Thestructofthedefaultrouter

typeServeMuxstruct

musyncRWMutexbecauseofconcurrencywehavetouseamutexhere

mmap[string]muxEntryrouterruleseverystringmappingtoahandler

ThestructofmuxEntry

typemuxEntrystruct

explicitboolexactmatchornot

hHandler

TheinterfaceofHandler

typeHandlerinterface

ServeHTTP(ResponseWriterRequest)routingimplementer

HandlerisaninterfacebutifthefunctionsayhelloNamedidntimplementthisinterfacethenhowdidweadditashandlerTheanswerliesinanothertypecalledHandlerFuncinthehttppackageWecalledHandlerFunctodefineoursayhelloNamemethodsosayhelloNameimplementedHandleratthesametimeItslikewerecallingHandlerFunc(f)andthefunctionfisforceconvertedtotypeHandlerFunc

Getintohttppackage

89

typeHandlerFuncfunc(ResponseWriterRequest)

ServeHTTPcallsf(wr)

func(fHandlerFunc)ServeHTTP(wResponseWriterrRequest)

f(wr)

Howdoestheroutercallhandlersafterwesettherouterrules

TheroutercallsmuxhandlerServeHTTP(wr)whenitreceivesrequestsInotherwordsitcallstheServeHTTPinterfaceofthehandlerswhichhaveimplementedit

Nowletsseehowmuxhandlerworks

func(muxServeMux)handler(rRequest)Handler

muxmuRLock()

defermuxmuRUnlock()

Host-specificpatterntakesprecedenceovergenericones

h=muxmatch(rHost+rURLPath)

ifh==nil

h=muxmatch(rURLPath)

ifh==nil

h=NotFoundHandler()

returnh

TherouterusestherequestsURLasakeytofindthecorrespondinghandlersavedinthemapthencallshandlerServeHTTPtoexecutefunctionstohandlethedata

YoushouldunderstandthedefaultroutersworkflowbynowandGoactuallysupportscustomizedroutersThesecondargumentofListenAndServeisforconfiguringcustomizedroutersItsaninterfaceofHandlerThereforeanyrouterthatimplementstheHandlerinterfacecanbeused

Thefollowingexampleshowshowtoimplementasimplerouter

packagemain

import(

fmt

nethttp

)

typeMyMuxstruct

func(pMyMux)ServeHTTP(whttpResponseWriterrhttpRequest)

ifrURLPath==

sayhelloName(wr)

return

httpNotFound(wr)

return

funcsayhelloName(whttpResponseWriterrhttpRequest)

fmtFprintf(wHellomyroute)

funcmain()

mux=ampMyMux

httpListenAndServe(9090mux)

Getintohttppackage

90

RoutingIfyoudonotwanttouseaRouteryoucanstillachievewhatwewroteintheabovesectionbyreplacingthesecondargumenttoListenAndServetonilandregisteringtheURLsusingaHandleFuncfunctionwhichgoesthroughalltheregisteredURLstofindthebestmatchsocaremustbetakenabouttheorderoftheregistering

samplecode

httpHandleFunc(viewsShowAllTasksFunc)

httpHandleFunc(completeviewsCompleteTaskFunc)

httpHandleFunc(deleteviewsDeleteTaskFunc)

ShowAllTasksFuncisusedtohandletheURLwhichisthedefaultons

TODOaddhttp404error

funcShowAllTasksFunc(whttpResponseWriterrhttpRequest)

ifrMethod==GET

context=dbGetTasks(pending)truewhenyouwantnondeletedtasks

dbisapackagewhichinteractswiththedatabase

ifmessage=

contextMessage=message

homeTemplateExecute(wcontext)

message=

else

message=Methodnotallowed

httpRedirect(wrhttpStatusFound)

ThisisfineforsimpleapplicationswhichdoesntrequiresparameterizedroutingwhatwhenyouneedthatYoucaneitherusetheexistingtoolkitsorframeworksbutsincethisbookisaboutwritingwebappsingolangwearegoingtoteachhowtohandlethisscenarioaswell

WhenthematchismadeontheHandleFuncfunctiontheURLismatchedsosupposewearewritingatodolistmanagerandwewanttodeleteatasksotheURLwedecideforthatapplicationisdelete1soweregisterthedeleteURLlikethishttpHandleFunc(deleteviewsDeleteTaskFunc)delete1thisURLmatchesclosestwiththedeleteURLthananyotherURLsointherURLpathwegettheentireURLoftherequest

httpHandleFunc(deleteviewsDeleteTaskFunc)

DeleteTaskFuncisusedtodeleteatasktrash=movetorecyclebindelete=permanentdelete

funcDeleteTaskFunc(whttpResponseWriterrhttpRequest)

ifrMethod==DELETE

id=rURLPath[len(delete)]

ifid==all

dbDeleteAll()

httpRedirect(wrhttpStatusFound)

else

iderr=strconvAtoi(id)

iferr=nil

fmtPrintln(err)

else

err=dbDeleteTask(id)

iferr=nil

message=Errordeletingtask

else

message=Taskdeleted

httpRedirect(wrhttpStatusFound)

else

message=Methodnotallowed

httpRedirect(wrhttpStatusFound)

Getintohttppackage

91

linkhttpsgithubcomthewhitetulipTasksblobmasterviewsviewsgoL170-L195

InthisabovemethodwhatwebasicallydoisinthefunctionwhichhandlesthedeleteURLwetakeitscompeleteURLwhichisdelete1thenwetakeasliceofthestringandextracteverythingwhichstartsafterthedeletewordwhichistheactualparameterinthiscaseitis1ThenweusethestrconvpackagetoconvertittoanintegeranddeletethetaskwiththattaskID

InmorecomplexscenariostoowecanusethismethodtheadvantageisthatwedonthavetouseanythirdpartytoolkitbutthenagainthirdpartytoolkitsareusefulintheirownrightyouneedtomakeadecisionwhichmethodyoudpreferNoansweristherightanswer

GocodeexecutionflowLetstakealookatthewholeexecutionflow

CallhttpHandleFunc1 CallHandleFuncofDefaultServeMux2 CallHandleofDefaultServeMux3 Addrouterrulestomap[string]muxEntryofDefaultServeMux

CallhttpListenAndServe(9090nil)1 InstantiateServer2 CallListenAndServemethodofServer3 CallnetListen(tcpaddr)tolistentoport4 Startaloopandacceptrequestsintheloopbody5 InstantiateaConnandstartagoroutineforeveryrequestgocserve()6 Readrequestdatawerr=creadRequest()7 CheckwhetherhandlerisemptyornotifitsemptythenuseDefaultServeMux8 CallServeHTTPofhandler9 ExecutecodeinDefaultServeMuxinthiscase10 ChoosehandlerbyURLandexecutecodeinthathandlerfunctionmuxhandlerServeHTTP(wr)11 HowtochoosehandlerACheckrouterrulesforthisURLBCallServeHTTPinthathandlerifthereisoneCCall

ServeHTTPofNotFoundHandlerotherwise

LinksDirectoryPrevioussectionHowGoworkswithwebNextsectionSummary

Getintohttppackage

92

35SummaryInthischapterweintroducedHTTPDNSresolutionflowandhowtobuildasimplewebserverThenwetalkedabouthowGoimplementswebserversforusbylookingatthesourcecodeofthenethttppackage

IhopethatyounowknowmuchmoreaboutwebdevelopmentandyoushouldseethatitsquiteeasyandflexibletobuildawebapplicationinGo

LinksDirectoryPrevioussectionGetintohttppackageNextchapterUserform

Summary

93

4UserformAuserformissomethingthatisverycommonlyusedwhendevelopingwebapplicationsItprovidestheabilitytocommunicatebetweenclientsandserversYoumustbeveryfamiliarwithformsifyouareawebdeveloperifyouareaCC++programmeryoumaywanttoaskwhatisauserform

AformisanareathatcontainsformelementsUserscaninputinformationintoformelementsliketextboxesdropdownlistsradiobuttonscheckboxesetcWeusetheformtagltformgttodefineforms

ltformgt

inputelements

ltformgt

GoalreadyhasmanyconvenientfunctionstodealwithuserformsYoucaneasilygetformdatainHTTPrequestsandtheyareeasytointegrateintoyourownwebapplicationsInsection41wearegoingtotalkabouthowtohandleformdatainGoAlsosinceyoucannottrustanydatacomingfromtheclientsideyoumustfirstvalidatethedatabeforeusingitWellgothroughsomeexamplesabouthowtovalidateformdatainsection42

WesaythatHTTPisstatelessHowcanweidentifythatcertainformsarefromthesameuserAndhowdowemakesurethatoneformcanonlybesubmittedonceWelllookatsomedetailsconcerningcookies(acookieisinformationthatcanbesavedontheclientsideandaddedtotherequestheaderwhentherequestissenttotheserver)inbothsections43and44

Anothercommonuse-caseforformsisuploadingfilesInsection45youwilllearnhowtodothisaswellascontrollingthefileuploadsizebeforeitbeginsuploadinginGo

LinksDirectoryPreviouschapterChapter3SummaryNextsectionProcessforminputs

HTTPForm

94

41ProcessforminputsBeforewebeginletstakealookatasimpleexampleofatypicaluserformsavedaslogingtplinyourprojectfolder

lthtmlgt

ltheadgt

lttitlegtlttitlegt

ltheadgt

ltbodygt

ltformaction=loginmethod=postgt

Usernameltinputtype=textname=usernamegt

Passwordltinputtype=passwordname=passwordgt

ltinputtype=submitvalue=Logingt

ltformgt

ltbodygt

lthtmlgt

ThisformwillsubmittologinontheserverAftertheuserclickstheloginbuttonthedatawillbesenttotheloginhandlerregisteredbytheserverrouterThenweneedtoknowwhetheritusesthePOSTmethodorGET

ThisiseasytofindoutusingthehttppackageLetsseehowtohandletheformdataontheloginpage

Processforminputs

95

packagemain

import(

fmt

htmltemplate

log

nethttp

strings

)

funcsayhelloName(whttpResponseWriterrhttpRequest)

rParseForm()ParseurlparameterspassedthenparsetheresponsepacketforthePOSTbody(requestbody)

attentionIfyoudonotcallParseFormmethodthefollowingdatacannotbeobtainedform

fmtPrintln(rForm)printinformationonserverside

fmtPrintln(pathrURLPath)

fmtPrintln(schemerURLScheme)

fmtPrintln(rForm[url_long])

forkv=rangerForm

fmtPrintln(keyk)

fmtPrintln(valstringsJoin(v))

fmtFprintf(wHelloastaxie)writedatatoresponse

funclogin(whttpResponseWriterrhttpRequest)

fmtPrintln(methodrMethod)getrequestmethod

ifrMethod==GET

t_=templateParseFiles(logingtpl)

tExecute(wnil)

else

rParseForm()

logicpartoflogin

fmtPrintln(usernamerForm[username])

fmtPrintln(passwordrForm[password])

funcmain()

httpHandleFunc(sayhelloName)settingrouterrule

httpHandleFunc(loginlogin)

err=httpListenAndServe(9090nil)settinglisteningport

iferr=nil

logFatal(ListenAndServeerr)

HereweuserMethodtogettherequestmethodanditreturnsanhttpverb-GETPOSTPUTetc

IntheloginfunctionweuserMethodtocheckwhetheritsaloginpageorloginprocessinglogicInotherwordswechecktoseewhethertheuserissimplyopeningthepageortryingtologinServeshowsthepageonlywhentherequestcomesinviatheGETmethodanditexecutestheloginlogicwhentherequestusesthePOSTmethod

Youshouldseethefollowinginterfaceafteropeninghttp1270019090logininyourbrowser

Figure41Userlogininterface

TheserverwillnotprintanythinguntilafterwetypeinausernameandpasswordbecausethehandlerdoesntparsetheformuntilwecallrParseForm()LetsaddrParseForm()beforefmtPrintln(usernamerForm[username])compileourprogramandtestitagainYouwillfindthattheinformationisprintedontheserversidenow

rFormcontainsalloftherequestargumentsforinstancethequery-stringintheURLandthedatainPOSTandPUTIfthedatahasconflictsforexampleparametersthathavethesamenametheserverwillsavethedataintoaslicewithmultiplevaluesTheGodocumentationstatesthatGowillsavethedatafromGETandPOSTrequestsindifferentplaces

Processforminputs

96

Trychangingthevalueoftheactionintheformhttp1270019090logintohttp1270019090loginusername=astaxieinthelogingtplfiletestitagainandyouwillseethatthesliceisprintedontheserverside

Figure42Serverprintsrequestdata

ThetypeofrequestFormisurlValueItsavesdatawiththeformatkey=value

v=urlValues

vSet(nameAva)

vAdd(friendJess)

vAdd(friendSarah)

vAdd(friendZoe)

vEncode()==name=Avaampfriend=Jessampfriend=Sarahampfriend=Zoe

fmtPrintln(vGet(name))

fmtPrintln(vGet(friend))

fmtPrintln(v[friend])

TipsRequestshavetheabilitytoaccessformdatausingtheFormValue()methodForexampleyoucanchangerForm[username]torFormValue(username)andGocallsrParseFormautomaticallyNoticethatitreturnsthefirstvalueifthereareargumentswiththesamenameanditreturnsanemptystringifthereisnosuchargument

LinksDirectoryPrevioussectionUserformNextsectionVerificationofinputs

Processforminputs

97

42VerificationofinputsOneofthemostimportantprinciplesinwebdevelopmentisthatyoucannottrustanythingfromclientsideuserformsYouhavetovalidateallincomingdatabeforeuseitManywebsitesareaffectedbythisproblemwhichissimpleyetcrucial

TherearetwowaysofverifyingformdatathatareincommonuseThefirstisJavaScriptvalidationonthefront-endandthesecondisservervalidationontheback-endInthissectionwearegoingtotalkaboutserversidevalidationinwebdevelopment

RequiredfieldsSometimeswerequirethatusersinputsomefieldsbuttheyfailtocompletethefieldForexampleintheprevioussectionwhenwerequiredausernameYoucanusethelenfunctiontogetthelengthofafieldinordertoensurethatusershaveenteredsomething

iflen(rForm[username][0])==0

codeforemptyfield

rFormtreatsdifferentformelementtypesdifferentlywhentheyareblankForemptytextboxestextareasandfileuploadsitreturnsanemptystringforradiobuttonsandcheckboxesitdoesntevencreatethecorrespondingitemsInsteadyouwillgeterrorsifyoutrytoaccessitThereforeitssafertouserFormGet()togetfieldvaluessinceitwillalwaysreturnemptyifthevaluedoesnotexistOntheotherhandrFormGet()canonlygetonefieldvalueatatimesoyouneedtouserFormtogetthemapofvalues

NumbersSometimesyourequirenumbersratherthanothertextforthefieldvalueForexampleletssaythatyourequiretheageofauserinintegerformonlyie50or10insteadofoldenoughoryoungmanIfwerequireapositivenumberwecanconvertthevaluetotheinttypefirstthenprocessit

getinterr=strconvAtoi(rFormGet(age))

iferr=nil

erroroccurswhenconverttonumberitmaynotanumber

checkrangeofnumber

ifgetintgt100

toobig

Anotherwaytodothisisbyusingregularexpressions

ifm_=regexpMatchString(^[0-9]+$rFormGet(age))m

returnfalse

ForhighperformancepurposesregularexpressionsarenotefficienthoweversimpleregularexpressionsareusuallyfastenoughIfyouarefamiliarwithregularexpressionsitsaveryconvenientwaytoverifydataNoticethatGousesRE2soallUTF-8charactersaresupported

Chinese

Validationofinputs

98

SometimesweneeduserstoinputtheirChinesenamesandwehavetoverifythattheyalluseChineseratherthanrandomcharactersForChineseverificationregularexpressionsaretheonlyway

ifm_=regexpMatchString(^[x4e00-x9fa5]+$rFormGet(realname))m

returnfalse

EnglishlettersSometimesweneeduserstoinputonlyEnglishlettersForexamplewerequiresomeonesEnglishnamelikeastaxieinsteadofasta谢Wecaneasilyuseregularexpressionstoperformourverification

ifm_=regexpMatchString(^[a-zA-Z]+$rFormGet(engname))m

returnfalse

E-mailaddressIfyouwanttoknowwhetherusershaveenteredvalidE-mailaddressesyoucanusethefollowingregularexpression

ifm_=regexpMatchString(`^([w_]210)(w1)([a-z]24)$`rFormGet(email))m

fmtPrintln(no)

else

fmtPrintln(yes)

DropdownlistLetssaywerequireanitemfromourdropdownlistbutinsteadwegetavaluefabricatedbyhackersHowdowepreventthisfromhappening

Supposewehavethefollowingltselectgt

ltselectname=fruitgt

ltoptionvalue=applegtappleltoptiongt

ltoptionvalue=peargtpearltoptiongt

ltoptionvalue=bananagtbananaltoptiongt

ltselectgt

Wecanusethefollowingstrategytosanitizeourinput

slice=[]stringapplepearbanana

for_v=rangeslice

ifv==rFormGet(fruit)

returntrue

returnfalse

AllthefunctionsIveshownaboveareinmyopensourceprojectforoperatingonslicesandmapshttpsgithubcomastaxiebeeku

Radiobuttons

Validationofinputs

99

Ifwewanttoknowwhethertheuserismaleorfemalewemayusearadiobuttonreturning1formaleand2forfemaleHoweversomelittlekidwhojustreadhisfirstbookonHTTPdecidestosendtoyoua3WillyourprogramthrowanexceptionAsyoucanseeweneedtousethesamemethodaswedidforourdropdownlisttomakesurethatonlyexpectedvaluesarereturnedbyourradiobutton

ltinputtype=radioname=gendervalue=1gtMale

ltinputtype=radioname=gendervalue=2gtFemale

Andweusethefollowingcodetovalidatetheinput

slice=[]int12

for_v=rangeslice

ifv==rFormGet(gender)

returntrue

returnfalse

CheckboxesSupposetherearesomecheckboxesforuserinterestsandthatyoudontwantextraneousvalueshereeitherYoucanvalidatetheseasefollows

ltinputtype=checkboxname=interestvalue=footballgtFootball

ltinputtype=checkboxname=interestvalue=basketballgtBasketball

ltinputtype=checkboxname=interestvalue=tennisgtTennis

Inthiscasethesanitizationisalittlebitdifferenttovalidatingthebuttonandcheckboxinputssinceherewegetaslicefromthecheckboxes

slice=[]stringfootballbasketballtennis

a=Slice_diff(rForm[interest]slice)

ifa==nil

returntrue

returnfalse

DateandtimeSupposeyouwantuserstoinputvaliddatesortimesGohasthetimepackageforconvertingyearmonthanddaytotheircorrespondingtimesAfterthatitseasytocheckit

t=timeDate(2009timeNovember1023000timeUTC)

fmtPrintf(GolaunchedatsntLocal())

Afteryouhavethetimeyoucanusethetimepackageformoreoperationsdependingonyourneeds

InthissectionwevediscussedsomecommonmethodsofvalidatingformdataontheserversideIhopethatyounowunderstandmoreaboutdatavalidationinGoespeciallyhowtouseregularexpressionstoyouradvantage

LinksDirectory

Validationofinputs

100

PrevioussectionProcessforminputsNextsectionCrosssitescripting

Validationofinputs

101

43CrosssitescriptingTodayswebsiteshavemuchmoredynamiccontentinordertoimproveuserexperiencewhichmeansthatwemustprovidedynamicinformationdependingoneveryindividualsbehaviorUnfortunatelydynamicwebsitesaresusceptibletomaliciousattacksknownasCrosssitescripting(knownasXSS)StaticwebsitesarenotsusceptibletoCrosssitescripting

AttackersofteninjectmaliciousscriptslikeJavaScriptVBScriptActiveXorFlashintothosewebsitesthathaveloopholesOncetheyhavesuccessfullyinjectedtheirscriptsuserinformationcanbestolenandyourwebsitecanbefloodedwithspamTheattackerscanalsochangeusersettingstowhatevertheywant

Ifyouwishtopreventthiskindofattackyoushouldcombinethefollowingtwoapproaches

ValidationofalldatafromuserswhichwetalkedaboutintheprevioussectionCarefullyhandledatathatwillbesenttoclientsinordertopreventanyinjectedscriptsfromrunningonbrowsers

SohowcanwedothesetwothingsinGoFortunatelythehtmltemplatepackagehassomeusefulfunctionstoescapedataasfollows

funcHTMLEscape(wioWriterb[]byte)escapesbtowfuncHTMLEscapeString(sstring)stringreturnsastringafterescapingfromsfuncHTMLEscaper(argsinterface)stringreturnsastringafterescapingfrommultiplearguments

Letschangetheexampleinsection41

fmtPrintln(usernametemplateHTMLEscapeString(rFormGet(username)))printatserverside

fmtPrintln(passwordtemplateHTMLEscapeString(rFormGet(password)))

templateHTMLEscape(w[]byte(rFormGet(username)))respondedtoclients

Ifsomeonetriestoinputtheusernameasltscriptgtalert()ltscriptgtwewillseethefollowingcontentinthebrowser

Figure43JavaScriptafterescaped

FunctionsinthehtmltemplatepackagehelpyoutoescapeallHTMLtagsWhatifyoujustwanttoprintltscriptgtalert()ltscriptgttobrowsersYoushouldusetexttemplateinstead

importtexttemplate

terr=templateNew(foo)Parse(`defineTHelloend`)

err=tExecuteTemplate(outTltscriptgtalert(youhavebeenpwned)ltscriptgt)

Output

Helloltscriptgtalert(youhavebeenpwned)ltscriptgt

OryoucanusethetemplateHTMLtypeVariablecontentwillnotbeescapedifitstypeistemplateHTML

importhtmltemplate

terr=templateNew(foo)Parse(`defineTHelloend`)

err=tExecuteTemplate(outTtemplateHTML(ltscriptgtalert(youhavebeenpwned)ltscriptgt))

Output

Helloltscriptgtalert(youhavebeenpwned)ltscriptgt

Crosssitescripting

102

Onemoreexampleofescaping

importhtmltemplate

terr=templateNew(foo)Parse(`defineTHelloend`)

err=tExecuteTemplate(outTltscriptgtalert(youhavebeenpwned)ltscriptgt)

Output

Helloampltscriptampgtalert(amp39youhavebeenpwnedamp39)ampltscriptampgt

LinksDirectoryPrevioussectionVerificationofinputsNextsectionDuplicatesubmissions

Crosssitescripting

103

44DuplicatesubmissionsIdontknowifyouveeverseensomeblogsorBBSthathavemorethanonepostthatareexactlythesamebutIcantellyouthatitsbecauseuserssubmittedduplicatepostformsTherearemanythingsthatcancauseduplicatesubmissionssometimesusersjustdoubleclickthesubmitbuttonortheywanttomodifysomecontentafterpostingandpressthebackbuttonInsomecasesitisbytheintentionalactionsofmalicioususersItseasytoseehowduplicatesubmissionscanleadtomanyproblemsThuswehavetouseeffectivemeanstopreventit

ThesolutionistoaddahiddenfieldwithauniquetokentoyourformandtoalwayscheckthistokenbeforeprocessingtheincomingdataAlsoifyouareusingAjaxtosubmitaformuseJavaScripttodisablethesubmitbuttononcetheformhasbeensubmitted

Letsimprovetheexamplefromsection42

ltinputtype=checkboxname=interestvalue=footballgtFootball

ltinputtype=checkboxname=interestvalue=basketballgtBasketball

ltinputtype=checkboxname=interestvalue=tennisgtTennis

Usernameltinputtype=textname=usernamegt

Passwordltinputtype=passwordname=passwordgt

ltinputtype=hiddenname=tokenvalue=gt

ltinputtype=submitvalue=Logingt

WeuseanMD5hash(timestamp)togeneratethetokenandaddedittobothahiddenfieldontheclientsideformandasessioncookieontheserverside(Chapter6)Wecanthenusethistokentocheckwhetherornotthisformwassubmitted

funclogin(whttpResponseWriterrhttpRequest)

fmtPrintln(methodrMethod)getrequestmethod

ifrMethod==GET

crutime=timeNow()Unix()

h=md5New()

ioWriteString(hstrconvFormatInt(crutime10))

token=fmtSprintf(xhSum(nil))

t_=templateParseFiles(logingtpl)

tExecute(wtoken)

else

loginrequest

rParseForm()

token=rFormGet(token)

iftoken=

checktokenvalidity

else

giveerrorifnotoken

fmtPrintln(usernamelengthlen(rForm[username][0]))

fmtPrintln(usernametemplateHTMLEscapeString(rFormGet(username)))printinserverside

fmtPrintln(passwordtemplateHTMLEscapeString(rFormGet(password)))

templateHTMLEscape(w[]byte(rFormGet(username)))respondtoclient

Figure44Thecontentinbrowserafteraddingatoken

YoucanrefreshthispageandyouwillseeadifferenttokeneverytimeThisensuresthateveryformisunique

FornowyoucanpreventmanyduplicatesubmissionattacksbyaddingtokenstoyourformsbutitcannotpreventalldeceptiveattacksofthistypeThereismuchmoreworkthatneedstobedone

Duplicatesubmissions

104

LinksDirectoryPrevioussectionCrosssitescriptingNextsectionFileupload

Duplicatesubmissions

105

45FileuploadSupposeyouhaveawebsitelikeInstagramandyouwantuserstouploadtheirbeautifulphotosHowwouldyouimplementthatfunctionality

YouhavetoaddpropertyenctypetotheformthatyouwanttouseforuploadingphotosTherearethreepossiblevaluesforthisproperty

applicationx-www-form-urlencodedTranscodeallcharactersbeforeuploading(default)

multipartform-dataNotranscodingYoumustusethisvaluewhenyourformhasfileuploadcontrols

textplainConvertspacesto+butnotranscodingforspecialcharacters

ThereforetheHTMLcontentofafileuploadformshouldlooklikethis

lthtmlgt

ltheadgt

lttitlegtUploadfilelttitlegt

ltheadgt

ltbodygt

ltformenctype=multipartform-dataaction=http1270019090uploadmethod=postgt

ltinputtype=filename=uploadfilegt

ltinputtype=hiddenname=tokenvalue=gt

ltinputtype=submitvalue=uploadgt

ltformgt

ltbodygt

lthtmlgt

Weneedtoaddafunctionontheserversidetohandlethisform

httpHandleFunc(uploadupload)

uploadlogic

funcupload(whttpResponseWriterrhttpRequest)

fmtPrintln(methodrMethod)

ifrMethod==GET

crutime=timeNow()Unix()

h=md5New()

ioWriteString(hstrconvFormatInt(crutime10))

token=fmtSprintf(xhSum(nil))

t_=templateParseFiles(uploadgtpl)

tExecute(wtoken)

else

rParseMultipartForm(32ltlt20)

filehandlererr=rFormFile(uploadfile)

iferr=nil

fmtPrintln(err)

return

deferfileClose()

fmtFprintf(wvhandlerHeader)

ferr=osOpenFile(test+handlerFilenameosO_WRONLY|osO_CREATE0666)

iferr=nil

fmtPrintln(err)

return

deferfClose()

ioCopy(ffile)

Fileupload

106

AsyoucanseeweneedtocallrParseMultipartFormforuploadingfilesThefunctionParseMultipartFormtakesthemaxMemoryargumentAfteryoucallParseMultipartFormthefilewillbesavedintheservermemorywithmaxMemorysizeIfthefilesizeislargerthanmaxMemorytherestofthedatawillbesavedinasystemtemporaryfileYoucanuserFormFiletogetthefilehandleanduseioCopytosavetoyourfilesystem

YoudontneedtocallrParseFormwhenyouaccessothernon-filefieldsintheformbecauseGowillcallitwhenitsnecessaryAlsocallingParseMultipartFormonceisenough-multiplecallsmakenodifference

Weusethreestepsforuploadingfilesasfollows

1 Addenctype=multipartform-datatoyourform2 CallrParseMultipartFormontheserversidetosavethefileeithertomemoryortoatemporaryfile3 CallrFormFiletogetthefilehandleandsavetothefilesystem

ThefilehandleristhemultipartFileHeaderItusesthefollowingstruct

typeFileHeaderstruct

Filenamestring

HeadertextprotoMIMEHeader

containsfilteredorunexportedfields

Figure45Printinformationonserverafterreceivingfile

ClientsuploadfilesIshowedanexampleofusingaformtoauploadafileWecanimpersonateaclientformtouploadfilesinGoaswell

Fileupload

107

packagemain

import(

bytes

fmt

io

ioioutil

mimemultipart

nethttp

os

)

funcpostFile(filenamestringtargetUrlstring)error

bodyBuf=ampbytesBuffer

bodyWriter=multipartNewWriter(bodyBuf)

thisstepisveryimportant

fileWritererr=bodyWriterCreateFormFile(uploadfilefilename)

iferr=nil

fmtPrintln(errorwritingtobuffer)

returnerr

openfilehandle

fherr=osOpen(filename)

iferr=nil

fmtPrintln(erroropeningfile)

returnerr

deferfhClose()

iocopy

_err=ioCopy(fileWriterfh)

iferr=nil

returnerr

contentType=bodyWriterFormDataContentType()

bodyWriterClose()

resperr=httpPost(targetUrlcontentTypebodyBuf)

iferr=nil

returnerr

deferrespBodyClose()

resp_bodyerr=ioutilReadAll(respBody)

iferr=nil

returnerr

fmtPrintln(respStatus)

fmtPrintln(string(resp_body))

returnnil

sampleusage

funcmain()

target_url=httplocalhost9090upload

filename=astaxiepdf

postFile(filenametarget_url)

TheaboveexampleshowsyouhowtouseaclienttouploadfilesItusesmultipartWritetowritefilesintocacheandsendsthemtotheserverthroughthePOSTmethod

IfyouhaveotherfieldsthatneedtowriteintodatalikeusernamecallmultipartWriteFieldasneeded

Links

Fileupload

108

DirectoryPrevioussectionDuplicatesubmissionsNextsectionSummary

Fileupload

109

46SummaryInthischapterwemainlylearnedhowtoprocessformdatainGothroughseveralexampleslikelogginginusersanduploadingfilesWealsoemphasizedthatvalidatinguserdataisextremelyimportantforwebsitesecurityandweusedonesectiontotalkabouthowtofilterdatawithregularexpressions

Ihopethatyounowknowmoreaboutthecommunicationprocessbetweenclientandserver

LinksDirectoryPrevioussectionFileuploadNextchapterDatabase

Summary

110

5DatabaseForwebdevelopersthedatabaseisatthecoreofwebdevelopmentYoucansavealmostanythingintoadatabaseandqueryorupdatedatainsideitlikeuserinformationproductsornewsarticles

GodoesntprovideanydatabasedriversbutitdoeshaveadriverinterfacedefinedinthedatabasesqlpackagePeoplecandevelopdatabasedriversbasedonthatinterfaceInsection51wearegoingtotalkaboutdatabasedriverinterfacedesigninGoInsections52to54IwillintroducesomeSQLdatabasedriverstoyouInsection55IwillpresenttheORM thatIhavedevelopedwhichisbasedonthedatabasesqlinterfacestandardItiscompatiblewithmostdriversthathaveimplementedthedatabasesqlinterfaceanditmakesiteasytoaccessdatabasesidiomaticallyinGo

NoSQLhasbeenahottopicinrecentyearsMorewebsitesaredecidingtouseNoSQLdatabasesastheirmaindatabaseinsteadofjustforthepurposeofcachingIwillintroduceyoutotwoNoSQLdatabaseswhichareMongoDBandRedisinsection56

LinksDirectoryPreviousChapterChapter4SummaryNextsectiondatabasesqlinterface

Database

111

51databasesqlinterfaceGodoesntprovideanyofficialdatabasedriversunlikeotherlanguageslikePHPwhichdoHoweveritdoeshavesomedatabasedriverinterfacestandardsfordeveloperstodevelopdatabasedriverswithTheadvantageisthatifyourcodeisdevelopedaccordingtotheseinterfacestandardsyouwillnotneedtochangeanycodeifyourdatabasechangesLetsseewhatthesedatabaseinterfacestandardsare

sqlRegisterThisfunctionisinthedatabasesqlpackageforregisteringdatabasedriverswhenyouusethird-partydatabasedriversAlloftheseshouldcalltheRegister(namestringdriverdriverDriver)functionininit()inordertoregisterthemselves

Letstakealookatthecorrespondingmymysqlandsqlite3drivercode

httpsgithubcommattngo-sqlite3driver

funcinit()

sqlRegister(sqlite3ampSQLiteDriver)

httpsgithubcommikespookmymysqldriver

Driverautomaticallyregisteredindatabasesql

vard=Driverprototcpraddr1270013306

funcinit()

Register(SETNAMESutf8)

sqlRegister(mymysqlampd)

Weseethatallthird-partydatabasedriversimplementthisfunctiontoregisterthemselvesandGousesamaptosaveuserdriversinsideofdatabasesql

vardrivers=make(map[string]driverDriver)

drivers[name]=driver

Thereforethisregistrationfunctioncanregisterasmanydriversasyoumayrequireeachwithdifferentnames

Wealwaysseethefollowingcodewhenweusethird-partydrivers

import(

databasesql

_githubcommattngo-sqlite3

)

Heretheunderscore(alsoknownasablank)_canbequiteconfusingformanybeginnersbutthisisagreatfeatureinGoWealreadyknowthatthisunderscoreidentifierisusedfordiscardingvaluesfromfunctionreturnsandalsothatyoumustuseallpackagesthatyouveimportedinyourcodeinGoSowhentheblankisusedwithimportitmeansthatyouneedtoexecutetheinit()functionofthatpackagewithoutdirectlyusingitwhichisaperfectfitfortheuse-caseofregisteringdatabasedrivers

driverDriverDriverisaninterfacecontaininganOpen(namestring)methodthatreturnsaConninterface

databasesqlinterface

112

typeDriverinterface

Open(namestring)(Connerror)

Thisisaone-timeConnwhichmeansitcanonlybeusedoncepergoroutineThefollowingcodewillcauseerrorstooccur

gogoroutineA(Conn)query

gogoroutineB(Conn)insert

BecauseGohasnoideawhichgoroutinedoeswhichoperationthequeryoperationmaygettheresultoftheinsertoperationandvice-versa

Allthird-partydriversshouldhavethisfunctiontoparsethenameofConnandreturnthecorrectresults

driverConnThisisadatabaseconnectioninterfacewithsomemethodsandasivesaidabovethesameConncanonlybeusedoncepergoroutine

typeConninterface

Prepare(querystring)(Stmterror)

Close()error

Begin()(Txerror)

PreparereturnsthepreparestatusofcorrespondingSQLcommandsforqueryinganddeletingetcCloseclosesthecurrentconnectionandcleansresourcesMostthird-partydriversimplementsomekindofconnectionpoolsoyoudontneedtocacheconnectionswhichcancauseunexpectederrorsBeginreturnsaTxthatrepresentsatransactionhandleYoucanuseitforqueryingupdatingrollingbacktransactionsetc

driverStmtThisisareadystatusthatcorrespondswithConnsoitcanonlybeusedoncepergoroutine(asisthecasewithConn)

typeStmtinterface

Close()error

NumInput()int

Exec(args[]Value)(Resulterror)

Query(args[]Value)(Rowserror)

CloseclosesthecurrentconnectionbutstillreturnsrowdataifitisexecutingaqueryoperationNumInputreturnsthenumberofobligateargumentsDatabasedriversshouldchecktheircallersargumentswhentheresultisgreaterthan0anditreturns-1whendatabasedriversdontknowanyobligateargumentExecexecutestheupdateinsertSQLcommandspreparedinPreparereturnsResultQueryexecutestheselectSQLcommandpreparedinPreparereturnsrowdata

driverTx

databasesqlinterface

113

Generallytransactionhandlesonlyhavesubmitorrollbackmethodsanddatabasedriversonlyneedtoimplementthesetwomethods

typeTxinterface

Commit()error

Rollback()error

driverExecerThisisanoptionalinterface

typeExecerinterface

Exec(querystringargs[]Value)(Resulterror)

IfthedriverdoesntimplementthisinterfacewhenyoucallDBExecitwillautomaticallycallPreparethenreturnStmtAfterthatitexecutestheExecmethodofStmtthenclosesStmt

driverResultThisistheinterfaceforresultsofupdateinsertoperations

typeResultinterface

LastInsertId()(int64error)

RowsAffected()(int64error)

LastInsertIdreturnsauto-incrementIdnumberafteradatabaseinsertoperationRowsAffectedreturnsrowsthatwereaffectedbyqueryoperations

driverRowsThisistheinterfacefortheresultofaqueryoperation

typeRowsinterface

Columns()[]string

Close()error

Next(dest[]Value)error

ColumnsreturnsfieldinformationofdatabasetablesTheslicehasaone-to-onecorrespondencewithSQLqueryfieldsonlyanddoesnotreturnallfieldsofthatdatabasetableCloseclosesRowsiteratorNextreturnsnextdataandassignstodestconvertingallstringsintobytearraysandgetsioEOFerrorifnomoredataisavailable

driverRowsAffectedThisisanaliasofint64butitimplementstheResultinterface

databasesqlinterface

114

typeRowsAffectedint64

func(RowsAffected)LastInsertId()(int64error)

func(vRowsAffected)RowsAffected()(int64error)

driverValueThisisanemptyinterfacethatcancontainanykindofdata

typeValueinterface

TheValuemustbesomethingthatdriverscanoperateonornilsoitshouldbeoneofthefollowingtypes

int64

float64

bool

[]byte

string[]ExceptRowsNextwhichcannotreturnstring

timeTime

driverValueConverterThisdefinesaninterfaceforconvertingnormalvaluestodriverValue

typeValueConverterinterface

ConvertValue(vinterface)(Valueerror)

Thisinterfaceiscommonlyusedindatabasedriversandhasmanyusefulfeatures

ConvertsdriverValuetoacorrespondingdatabasefieldtypeforexampleconvertsint64touint16ConvertsdatabasequeryresultstodriverValueConvertsdriverValuetoauserdefinedvalueinthescanfunction

driverValuerThisdefinesaninterfaceforreturningdriverValue

typeValuerinterface

Value()(Valueerror)

ManytypesimplementthisinterfaceforconversionbetweendriverValueanditself

AtthispointyoushouldknowabitaboutdevelopingdatabasedriversinGoOnceyoucanimplementinterfacesforoperationslikeadddeleteupdateetcthereareonlyafewproblemsleftrelatedtocommunicatingwithspecificdatabases

databasesqldatabasesqldefinesevenmorehigh-levelmethodsontopofdatabasesqldriverformoreconvenientdatabaseoperationsanditsuggeststhatyouimplementaconnectionpool

databasesqlinterface

115

typeDBstruct

driverdriverDriver

dsnstring

musyncMutexprotectsfreeConnandclosed

freeConn[]driverConn

closedbool

AsyoucanseetheOpenfunctionreturnsaDBthathasafreeConnandthisisasimpleconnectionpoolItsimplementationisverysimpleanduglyItusesdeferdbputConn(cierr)intheDbpreparefunctiontoputaconnectionintotheconnectionpoolEverytimeyoucalltheConnfunctionitchecksthelengthoffreeConnIfitsgreaterthan0thatmeansthereisareusableconnectionanditdirectlyreturnstoyouOtherwiseitcreatesanewconnectionandreturns

LinksDirectoryPrevioussectionDatabaseNextsectionMySQL

databasesqlinterface

116

52MySQLTheLAMPstackhasbeenverypopularontheinternetinrecentyearsandtheMinLAMPstandforMySQLMySQLisfamousbecauseitsopensourceandeasytouseAssuchithasbecomethede-factodatabaseintheback-endsofmanywebsites

MySQLdriversThereareacoupleofdriversthatsupportMySQLinGoSomeofthemimplementthedatabasesqlinterfaceandothersusetheirowninterfacestandards

httpsgithubcomgo-sql-drivermysqlsupportsdatabasesqlwritteninpureGohttpsgithubcomziutekmymysqlsupportsdatabasesqlanduserdefinedinterfaceswritteninpureGo

Illusethefirstdriverinthefollowingexamples(Iusethisoneinmypersonalprojectstoo)andIalsorecommendthatyouuseitforthefollowingreasons

ItsanewdatabasedriverandsupportsmorefeaturesItfullysupportsdatabasesqlinterfacestandardsSupportskeep-alivelongconnectionswiththread-safety

SamplesInthefollowingsectionsIllusethesamedatabasetablestructurefordifferentdatabasesthencreateSQLasfollows

CREATETABLE`userinfo`(

`uid`INT(10)NOTNULLAUTO_INCREMENT

`username`VARCHAR(64)NULLDEFAULTNULL

`departname`VARCHAR(64)NULLDEFAULTNULL

`created`DATENULLDEFAULTNULL

PRIMARYKEY(`uid`)

)

Thefollowingexampleshowshowtooperateonadatabasebasedonthedatabasesqlinterfacestandards

packagemain

import(

_githubcomgo-sql-drivermysql

databasesql

fmt

)

funcmain()

dberr=sqlOpen(mysqlastaxieastaxietestcharset=utf8)

checkErr(err)

insert

stmterr=dbPrepare(INSERTuserinfoSETusername=departname=created=)

checkErr(err)

reserr=stmtExec(astaxie研发部门2012-12-09)

checkErr(err)

iderr=resLastInsertId()

checkErr(err)

fmtPrintln(id)

update

HowtouseMySQL

117

stmterr=dbPrepare(updateuserinfosetusername=whereuid=)

checkErr(err)

reserr=stmtExec(astaxieupdateid)

checkErr(err)

affecterr=resRowsAffected()

checkErr(err)

fmtPrintln(affect)

query

rowserr=dbQuery(SELECTFROMuserinfo)

checkErr(err)

forrowsNext()

varuidint

varusernamestring

vardepartmentstring

varcreatedstring

err=rowsScan(ampuidampusernameampdepartmentampcreated)

checkErr(err)

fmtPrintln(uid)

fmtPrintln(username)

fmtPrintln(department)

fmtPrintln(created)

delete

stmterr=dbPrepare(deletefromuserinfowhereuid=)

checkErr(err)

reserr=stmtExec(id)

checkErr(err)

affecterr=resRowsAffected()

checkErr(err)

fmtPrintln(affect)

dbClose()

funccheckErr(errerror)

iferr=nil

panic(err)

Letmeexplainafewoftheimportantfunctionshere

sqlOpen()opensaregistereddatabasedriverTheGo-MySQL-DriverregisteredthemysqldriverhereThesecondargumentistheDSN(DataSourceName)thatdefinesinformationpertainingtothedatabaseconnectionItsupportsfollowingformats

userunix(pathtosocket)dbnamecharset=utf8

userpasswordtcp(localhost5555)dbnamecharset=utf8

userpassworddbname

userpasswordtcp([deadbeefcafe]80)dbname

dbPrepare()returnsaSQLoperationthatisgoingtobeexecutedItalsoreturnstheexecutionstatusafterexecutingSQL

dbQuery()executesSQLandreturnsaRowsresultstmtExec()executesSQLthathasbeenpreparedandstoredinStmt

Notethatweusetheformat=topassargumentsThisisnecessaryforpreventingSQLinjectionattacks

HowtouseMySQL

118

LinksDirectoryPrevioussectiondatabasesqlinterfaceNextsectionSQLite

HowtouseMySQL

119

53SQLiteSQLiteisanopensourceembeddedrelationaldatabaseIthasaself-containedzero-configurationandtransaction-supporteddatabaseengineItscharacteristicsarehighlyportableeasytousecompactefficientandreliableInmostofcasesyouonlyneedabinaryfileofSQLitetocreateconnectandoperateadatabaseIfyouarelookingforanembeddeddatabasesolutionSQLiteisworthconsideringYoucansaySQLiteistheopensourceversionofAccess

SQLitedriversTherearemanydatabasedriversforSQLiteinGobutmanyofthemdonotsupportthedatabasesqlinterfacestandards

httpsgithubcommattngo-sqlite3supportsdatabasesqlbasedoncgohttpsgithubcomfeyeleanorgosqlite3doesntsupportdatabasesqlbasedoncgohttpsgithubcomphfgo-sqlite3doesntsupportdatabasesqlbasedoncgo

ThefirstdriveristheonlyonethatsupportsthedatabasesqlinterfacestandardinitsSQLitedriversoIusethisinmyprojects-itwillmakeiteasytomigratemycodeinthefutureifIneedto

SamplesWecreatethefollowingSQL

CREATETABLE`userinfo`(

`uid`INTEGERPRIMARYKEYAUTOINCREMENT

`username`VARCHAR(64)NULL

`departname`VARCHAR(64)NULL

`created`DATENULL

)

Anexample

packagemain

import(

databasesql

fmt

time

_githubcommattngo-sqlite3

)

funcmain()

dberr=sqlOpen(sqlite3foodb)

checkErr(err)

insert

stmterr=dbPrepare(INSERTINTOuserinfo(usernamedepartnamecreated)values())

checkErr(err)

reserr=stmtExec(astaxie研发部门2012-12-09)

checkErr(err)

iderr=resLastInsertId()

checkErr(err)

fmtPrintln(id)

update

stmterr=dbPrepare(updateuserinfosetusername=whereuid=)

checkErr(err)

HowtouseSQLite

120

reserr=stmtExec(astaxieupdateid)

checkErr(err)

affecterr=resRowsAffected()

checkErr(err)

fmtPrintln(affect)

query

rowserr=dbQuery(SELECTFROMuserinfo)

checkErr(err)

varuidint

varusernamestring

vardepartmentstring

varcreatedtimeTime

forrowsNext()

err=rowsScan(ampuidampusernameampdepartmentampcreated)

checkErr(err)

fmtPrintln(uid)

fmtPrintln(username)

fmtPrintln(department)

fmtPrintln(created)

rowsClose()goodhabittoclose

delete

stmterr=dbPrepare(deletefromuserinfowhereuid=)

checkErr(err)

reserr=stmtExec(id)

checkErr(err)

affecterr=resRowsAffected()

checkErr(err)

fmtPrintln(affect)

dbClose()

funccheckErr(errerror)

iferr=nil

panic(err)

YoumayhavenoticedthatthecodeisalmostthesameasintheprevioussectionandthatweonlychangedthenameoftheregistereddriverandcalledsqlOpentoconnecttoSQLiteinadifferentway

Notethatsometimesyoucantusetheforstatementbecauseyoudonthavemorethanonerowthenyoucanusetheifstatement

ifrowsNext()

err=rowsScan(ampuidampusernameampdepartmentampcreated)

checkErr(err)

fmtPrintln(uid)

fmtPrintln(username)

fmtPrintln(department)

fmtPrintln(created)

AlsoyouhavetodoarowsNext()withoutusingthatyoucantfetchdataintheScanfunction

Transactions

HowtouseSQLite

121

TheaboveexampleshowshowyoufetchdatafromthedatabasebutwhenyouwanttowriteawebapplicationthenitwillnotonlybenecessarytofetchdatafromthedbbutitwillalsoberequiredtowritedataintoitForthatpurposeyoushouldusetransactionsbecauseforvariousreasonssuchashavingmultiplegoroutineswhichaccessthedatabasethedatabasemightgetlockedThisisundesirableinyourwebapplicationandtheuseoftransactionsiseffectiveinensuringyourdatabaseactivitieseitherpassorfailcompletelydependingoncircumstancesItisclearthatusingtransactionscanpreventalotofthingsfromgoingwrongwiththewebapp

trashSQLerr=databasePrepare(updatetasksetis_deleted=Ylast_modified_at=datetime()whereid=)

iferr=nil

fmtPrintln(err)

txerr=databaseBegin()

iferr=nil

fmtPrintln(err)

_err=txStmt(trashSQL)Exec(id)

iferr=nil

fmtPrintln(doingrollback)

txRollback()

else

txCommit()

Asitisclearfromtheaboveblockofcodeyoufirstprepareastatementafterwhichyouexecuteitdependingontheoutputofthatexecutionthenyoueitherrollitbackorcommitit

AsafinalnoteonthissectionthereisausefulSQLitemanagementtoolavailablehttpsqlitebrowserorg

LinksDirectoryPrevioussectionMySQLNextsectionPostgreSQL

HowtouseSQLite

122

54PostgreSQLPostgreSQLisanobject-relationaldatabasemanagementsystemavailableformanyplatformsincludingLinuxFreeBSDSolarisMicrosoftWindowsandMacOSXItisreleasedunderanMIT-stylelicenseandisthusfreeandopensourcesoftwareItslargerthanMySQLbecauseitsdesignedforenterpriseusageasanalternativetoOraclePostgresqlisagoodchoiceforenterprisetypeprojects

PostgreSQLdriversTherearemanydatabasedriversavailableforPostgreSQLHerearethreeexamplesofthem

httpsgithubcomlibpqsupportsdatabasesqlwritteninpureGohttpsgithubcomjbarhamgopgsqldriversupportsdatabasesqlwritteninpureGohttpsgithubcomlxngo-pgsqlsupportsdatabasesqlwritteninpureGo

Iwillusethefirstoneintheexamplesthatfollow

SamplesWecreatethefollowingSQL

CREATETABLEuserinfo

(

uidserialNOTNULL

usernamecharactervarying(100)NOTNULL

departnamecharactervarying(500)NOTNULL

Createddate

CONSTRAINTuserinfo_pkeyPRIMARYKEY(uid)

)

WITH(OIDS=FALSE)

Anexample

packagemain

import(

databasesql

fmt

_githubcomlibpq

time

)

const(

DB_USER=postgres

DB_PASSWORD=postgres

DB_NAME=test

)

funcmain()

dbinfo=fmtSprintf(user=spassword=sdbname=ssslmode=disable

DB_USERDB_PASSWORDDB_NAME)

dberr=sqlOpen(postgresdbinfo)

checkErr(err)

deferdbClose()

fmtPrintln(Insertingvalues)

varlastInsertIdint

err=dbQueryRow(INSERTINTOuserinfo(usernamedepartnamecreated)VALUES($1$2$3)returninguidastax

ie研发部门2012-12-09)Scan(amplastInsertId)

HowtousePostgreSQL

123

checkErr(err)

fmtPrintln(lastinsertedid=lastInsertId)

fmtPrintln(Updating)

stmterr=dbPrepare(updateuserinfosetusername=$1whereuid=$2)

checkErr(err)

reserr=stmtExec(astaxieupdatelastInsertId)

checkErr(err)

affecterr=resRowsAffected()

checkErr(err)

fmtPrintln(affectrowschanged)

fmtPrintln(Querying)

rowserr=dbQuery(SELECTFROMuserinfo)

checkErr(err)

forrowsNext()

varuidint

varusernamestring

vardepartmentstring

varcreatedtimeTime

err=rowsScan(ampuidampusernameampdepartmentampcreated)

checkErr(err)

fmtPrintln(uid|username|department|created)

fmtPrintf(3v|8v|6v|6vnuidusernamedepartmentcreated)

fmtPrintln(Deleting)

stmterr=dbPrepare(deletefromuserinfowhereuid=$1)

checkErr(err)

reserr=stmtExec(lastInsertId)

checkErr(err)

affecterr=resRowsAffected()

checkErr(err)

fmtPrintln(affectrowschanged)

funccheckErr(errerror)

iferr=nil

panic(err)

NotethatPostgreSQLusesthe$1$2formatinsteadofthethatMySQLusesandithasadifferentDSNformatinsqlOpenAnotherthingisthatthePostgreSQLdriverdoesnotsupportsqlResultLastInsertId()Soinsteadofthis

stmterr=dbPrepare(INSERTINTOuserinfo(usernamedepartnamecreated)VALUES($1$2$3))

reserr=stmtExec(astaxie研发部门2012-12-09)

fmtPrintln(resLastInsertId())

usedbQueryRow()andScan()togetthevalueforthelastinsertedid

err=dbQueryRow(INSERTINTOTABLE_NAMEvalues($1)returninguidVALUE1)Scan(amplastInsertId)

fmtPrintln(lastInsertId)

LinksDirectoryPrevioussectionSQLite

HowtousePostgreSQL

124

NextsectionDevelopORMbasedonbeedb

HowtousePostgreSQL

125

55DevelopORMbasedonbeedb(Projectbeedbisnolongermaintainedbutthecodesstillthere)

beedbisanORM(object-relationalmapper)developedinGobymeItusesidiomaticGotooperateondatabasesimplementingstruct-to-databasemappingandactsasalightweightGoORMframeworkThepurposeofdevelopingthisORMisnotonlytohelppeoplelearnhowtowriteanORMbutalsotofindagoodbalancebetweenfunctionalityandperformancewhenitcomestodatapersistence

beedbisanopensourceprojectthatsupportsbasicORMfunctionalitybutdoesntsupportassociationqueries

BecausebeedbsupportsdatabasesqlinterfacestandardsanydriverthatimplementsthisinterfacecanbeusedwithbeedbIvetestedthefollowingdrivers

Mysqlgithubgo-mysql-drivermysql

PostgreSQLgithubcomlibpq

SQLitegithubcommattngo-sqlite3

Mysqlgithubcomziutekmymysqlgodrv

MSADODBgithubcommattngo-adodb

Oraclegithubcommattngo-oci8

ODBCbitbucketorgmiquellamgodbc

InstallationYoucanusegogettoinstallbeedblocally

gogetgithubcomastaxiebeedb

InitializationFirstyouhavetoimportallthenecessarypackages

import(

databasesql

githubcomastaxiebeedb

_githubcomziutekmymysqlgodrv

)

Thenyouneedtoopenadatabaseconnectionandcreateabeedbobject(MySQLinthisexample)

dberr=sqlOpen(mymysqltestxiemengjun123456)

iferr=nil

panic(err)

orm=beedbNew(db)

beedbNew()actuallyhastwoargumentsThefirstisthedatabaseobjectandthesecondisforindicatingwhichdatabaseengineyoureusingIfyoureusingMySQLSQLiteyoucanjustskipthesecondargument

OtherwisethisargumentmustbesuppliedForinstanceinthecaseofSQLServer

HowtousebeedbORM

126

orm=beedbNew(dbmssql)

PostgreSQL

orm=beedbNew(dbpg)

beedbsupportsdebuggingUsethefollowingcodetoenableit

beedbOnDebug=true

NextwehaveastructfortheUserinfodatabasetablethatweusedinprevioussections

typeUserinfostruct

Uidint`PK`iftheprimarykeyisnotidyouneedtoaddtag`PK`foryourcustomizedprimarykey

Usernamestring

Departnamestring

CreatedtimeTime

Beawarethatbeedbauto-convertscamelcasenamestolowersnakecaseForexampleifwehaveUserInfoasthestructnamebeedbwillconvertittouser_infointhedatabaseThesameruleappliestostructfieldnames

InsertdataThefollowingexampleshowsyouhowtousebeedbtosaveastructinsteadofusingrawSQLcommandsWeusethebeedbSavemethodtoapplythechange

varsaveoneUserinfo

saveoneUsername=TestAddUser

saveoneDepartname=TestAddDepartname

saveoneCreated=timeNow()

ormSave(ampsaveone)

YoucanchecksaveoneUidaftertherecordisinserteditsvalueisaself-incrementedIDwhichtheSavemethodtakescareofforyou

beedbprovidesanotherwayofinsertingdatathisisviaGosmaptype

add=make(map[string]interface)

add[username]=astaxie

add[departname]=clouddevelop

add[created]=2012-12-02

ormSetTable(userinfo)Insert(add)

Insertmultipledata

addslice=make([]map[string]interface10)

add=make(map[string]interface)

add2=make(map[string]interface)

add[username]=astaxie

add[departname]=clouddevelop

add[created]=2012-12-02

add2[username]=astaxie2

add2[departname]=clouddevelop2

add2[created]=2012-12-02

addslice=append(addsliceaddadd2)

ormSetTable(userinfo)InsertBatch(addslice)

HowtousebeedbORM

127

ThemethodshownaboveissimilartoachainedquerywhichyoushouldbefamiliarwithifyouveeverusedjqueryItreturnstheoriginalORMobjectaftercallsthencontinuesdoingotherjobs

ThemethodSetTabletellstheORMwewanttoinsertourdataintotheuserinfotable

UpdatedataLetscontinueworkingwiththeaboveexampletoseehowtoupdatedataNowthatwehavetheprimarykeyofsaveone(Uid)beedbexecutesanupdateoperationinsteadofinsertinganewrecord

saveoneUsername=UpdateUsername

saveoneDepartname=UpdateDepartname

saveoneCreated=timeNow()

ormSave(ampsaveone)update

Likebeforeyoucanalsousemapforupdatingdata

t=make(map[string]interface)

t[username]=astaxie

ormSetTable(userinfo)SetPK(uid)Where(2)Update(t)

Letmeexplainsomeofthemethodsusedabove

SetPK()tellstheORMthatuidistheprimarykeyrecordsintheuserinfotableWhere()setsconditionsandsupportsmultipleargumentsIfthefirstargumentisanintegeritsashortformforWhere(ltprimarykeygt=ltvaluegt)Update()methodacceptsamapandupdatesthedatabase

QuerydataThebeedbqueryinterfaceisveryflexibleLetsseesomeexamples

Example1querybyprimarykey

varuserUserinfo

Whereacceptstwoargumentssupportsintegers

ormWhere(uid=27)Find(ampuser)

Example2

varuser2Userinfo

ormWhere(3)Find(ampuser2)shortformthatomitsprimarykey

Example3otherqueryconditions

varuser3Userinfo

Wheretwoargumentsareacceptedwithsupportforchartype

ormWhere(name=john)Find(ampuser3)

Example4morecomplexconditions

varuser4Userinfo

Wherethreeargumentsareaccepted

ormWhere(name=andageltjohn88)Find(ampuser4)

Examplestogetmultiplerecords

HowtousebeedbORM

128

Example1gets10recordswithidgt3thatstartswithposition20

varallusers[]Userinfo

err=ormWhere(idgt3)Limit(1020)FindAll(ampallusers)

Example2omitsthesecondargumentoflimitsoitstartswith0andgets10records

vartenusers[]Userinfo

err=ormWhere(idgt3)Limit(10)FindAll(amptenusers)

Example3getsallrecords

vareveryone[]Userinfo

err=ormOrderBy(uiddescusernameasc)FindAll(ampeveryone)

AsyoucanseetheLimitmethodisforlimitingthenumberofresults

Limit()supportstwoargumentsthenumberofresultsandthestartingposition0isthedefaultvalueofthestartingpositionOrderBy()isfororderingresultsTheargumentistheordercondition

AlltheexamplesherearesimplymappingrecordstostructsYoucanalsojustputthedataintoamapasfollows

a_=ormSetTable(userinfo)SetPK(uid)Where(2)Select(uidusername)FindMap()

Select()tellsbeedbhowmanyfieldsyouwanttogetfromthedatabasetableIfunspecifiedallfieldsarereturnedbydefaultFindMap()returnsthe[]map[string][]bytetypesoyouneedtoconverttoothertypesyourself

Deletedatabeedbprovidesrichmethodstodeletedata

Example1deleteasinglerecord

saveoneistheoneinaboveexample

ormDelete(ampsaveone)

Example2deletemultiplerecords

alluseristheslicewhichgetsmultiplerecords

ormDeleteAll(ampalluser)

Example3deleterecordsbySQL

ormSetTable(userinfo)Where(uidgt3)DeleteRow()

AssociationqueriesbeedbdoesntsupportjoiningbetweenstructsHoweversincesomeapplicationsneedthisfeaturehereisanimplementation

a_=ormSetTable(userinfo)Join(LEFTuserdetailuserinfouid=userdetailuid)

Where(userinfouid=1)Select(userinfouiduserinfousernameuserdetailprofile)FindMap()

HowtousebeedbORM

129

WeseeanewmethodcalledJoin()thathasthreearguments

ThefirstargumentTypeofJoinINNERLEFTOUTERCROSSetcThesecondargumentthetableyouwanttojoinwithThethirdargumentjoincondition

GroupByandHavingbeedbalsohasanimplementationofgroupbyandhaving

a_=ormSetTable(userinfo)GroupBy(username)Having(username=astaxie)FindMap()

GroupBy()indicatesthefieldthatisforgroupbyHaving()indicatesconditionsofhaving

FutureIhavereceivedalotoffeedbackonbeedbfrommanypeopleallaroundtheworldandImthinkingaboutreconfiguringthefollowingaspects

ImplementaninterfacedesignsimilartodatabasesqldriverinordertofacilitateCRUDoperationsImplementrelationaldatabaseassociationslikeonetooneonetomanyandmanytomanyHeresasample

typeProfilestruct

Nicknamestring

Mobilestring

typeUserinfostruct

Uidint

PK_Usernamestring

Departnamestring

CreatedtimeTime

ProfileHasOne

Auto-createtablesandindexesImplementaconnectionpoolusinggoroutines

LinksDirectoryPrevioussectionPostgreSQLNextsectionNoSQLdatabase

HowtousebeedbORM

130

56NoSQLdatabaseANoSQLdatabaseprovidesamechanismforthestorageandretrievalofdatathatuseslooserconsistencymodelsthantypicalrelationaldatabasesinordertoachievehorizontalscalingandhigheravailabilitySomeauthorsrefertothemasNotonlySQLtoemphasizethatsomeNoSQLsystemsdoallowSQL-likequerylanguagestobeused

AstheClanguageofthe21stcenturyGohasgoodsupportforNoSQLdatabasesincludingthepopularredismongoDBCassandraandMembaseNoSQLdatabases

redisredisisakey-valuestoragesystemlikeMemcachedthatsupportsthestringlistsetandzset(orderedset)valuetypes

TherearesomeGodatabasedriversforredis

httpsgithubcomgaryburdredigohttpsgithubcomgo-redisredishttpsgithubcomhoisieredishttpsgithubcomalphazeroGo-Redishttpsgithubcomsimonz05godis

Letsseehowtousethedriverthatredigotooperateonadatabase

packagemain

import(

fmt

githubcomgaryburdredigoredis

os

ossignal

syscall

time

)

var(

PoolredisPool

)

funcinit()

redisHost=6379

Pool=newPool(redisHost)

close()

funcnewPool(serverstring)redisPool

returnampredisPool

MaxIdle3

IdleTimeout240timeSecond

Dialfunc()(redisConnerror)

cerr=redisDial(tcpserver)

iferr=nil

returnnilerr

returncerr

TestOnBorrowfunc(credisConnttimeTime)error

_err=cDo(PING)

returnerr

NOSQL

131

funcclose()

c=make(chanosSignal1)

signalNotify(cosInterrupt)

signalNotify(csyscallSIGTERM)

signalNotify(csyscallSIGKILL)

gofunc()

lt-c

PoolClose()

osExit(0)

()

funcGet(keystring)([]byteerror)

conn=PoolGet()

deferconnClose()

vardata[]byte

dataerr=redisBytes(connDo(GETkey))

iferr=nil

returndatafmtErrorf(errorgetkeysvkeyerr)

returndataerr

funcmain()

testerr=Get(test)

fmtPrintln(testerr)

IforkedthelastofthesepackagesfixedsomebugsanduseditinmyshortURLservice(2millionPVeveryday)

httpsgithubcomastaxiegoredis

LetsseehowtousethedriverthatIforkedtooperateonadatabase

packagemain

import(

githubcomastaxiegoredis

fmt

)

funcmain()

varclientgoredisClient

SetthedefaultportinRedis

clientAddr=1270016379

stringmanipulation

clientSet(a[]byte(hello))

val_=clientGet(a)

fmtPrintln(string(val))

clientDel(a)

listoperation

vals=[]stringabcde

for_v=rangevals

clientRpush(l[]byte(v))

dbvals_=clientLrange(l04)

foriv=rangedbvals

println(istring(v))

clientDel(l)

NOSQL

132

WecanseethatitisquiteeasytooperateredisinGoandithashighperformanceItsclientcommandsarealmostthesameasredisbuilt-incommands

mongoDBmongoDB(fromhumongous)isanopensourcedocument-orienteddatabasesystemdevelopedandsupportedby10genItispartoftheNoSQLfamilyofdatabasesystemsInsteadofstoringdataintablesasisdoneinaclassicalrelationaldatabaseMongoDBstoresstructureddataasJSON-likedocumentswithdynamicschemas(MongoDBcallstheformatBSON)makingtheintegrationofdataincertaintypesofapplicationseasierandfaster

Figure51MongoDBcomparedtoMysql

ThebestdriverformongoDBiscalledmgoanditispossiblethatitwillbeincludedinthestandardlibraryinthefuture

Installmgo

gogetgopkginmgov2

Hereistheexample

packagemain

import(

fmt

gopkginmgov2

gopkginmgov2bson

log

)

typePersonstruct

Namestring

Phonestring

funcmain()

sessionerr=mgoDial(server1examplecomserver2examplecom)

iferr=nil

panic(err)

defersessionClose()

OptionalSwitchthesessiontoamonotonicbehavior

sessionSetMode(mgoMonotonictrue)

c=sessionDB(test)C(people)

err=cInsert(ampPersonAle+555381169639

ampPersonCla+555384028510)

iferr=nil

logFatal(err)

result=Person

err=cFind(bsonMnameAle)One(ampresult)

iferr=nil

logFatal(err)

fmtPrintln(PhoneresultPhone)

NOSQL

133

WecanseethattherearenobigdifferenceswhenitcomestooperatingonmgoorbeedbdatabasestheyarebothbasedonstructsThisistheGowayofdoingthings

LinksDirectoryPrevioussectionDevelopORMbasedonbeedbNextsectionSummary

NOSQL

134

57SummaryInthischapteryoufirstlearnedaboutthedesignofthedatabasesqlinterfaceandmanythird-partydatabasedriversforvariousdatabasetypesThenIintroducedbeedbanORMforrelationaldatabasestoyouIalsoshowedyousomesampledatabaseoperationsIntheendItalkedaboutafewNoSQLdatabasesWesawthatGoprovidesverygoodsupportforthoseNoSQLdatabases

AfterreadingthischapterIhopethatyouhaveabetterunderstandingofhowtooperatedatabasesinGoThisisthemostimportantpartofwebdevelopmentsoIwantyoutocompletelyunderstandthedesignconceptsofthedatabasesqlinterface

LinksDirectoryPrevioussectionNoSQLdatabaseNextsectionDatastorageandsession

Summary

135

6DatastorageandsessionsAnimportanttopicinwebdevelopmentisprovidingagooduserexperiencebutthefactthatHTTPisastatelessprotocolseemscontrarytothisspiritHowcanwecontrolthewholeprocessofviewingwebsitesforusersTheclassicsolutionsareusingcookiesandsessionswherecookiesserveastheclientsidemechanismandsessionsaresavedontheserversidewithauniqueidentifierforeverysingleuserNotethatsessionscanbepassedinURLsorcookiesoreveninyourdatabase(whichismuchmoresecurebutmayhamperyourapplicationperformance)

Insection61wearegoingtotalkaboutdifferencesbetweencookiesandsessionsInsection62youlllearnhowtousesessionsinGowithanimplementationofasessionmanagerInsection63wewilltalkaboutsessionhijackingandhowtopreventitwhenyouknowthatsessionscanbesavedanywhereThesessionmanagerwewillimplementinsection63willsavesessionsinmemorybutifweneedtoexpandourapplicationtoallowforsessionsharingitsalwaysbettertosavethesesessionsdirectlyintoourdatabaseWelltalkmoreaboutthisinsection64

LinksDirectoryPreviousChapterChapter5SummaryNextsectionSessionandcookies

Datastorageandsession

136

61SessionandcookiesSessionsandcookiesaretwoverycommonwebconceptsandarealsoveryeasytomisunderstandHowevertheyareextremelyimportantfortheauthorizationofpagesaswellasforgatheringpagestatisticsLetstakealookatthesetwousecases

SupposeyouwanttocrawlapagethatrestrictspublicaccesslikeatwitterusershomepageforinstanceOfcourseyoucanopenyourbrowserandtypeinyourusernameandpasswordtologinandaccessthatinformationbutso-calledwebcrawlingmeansthatweuseaprogramtoautomatethisprocesswithoutanyhumaninterventionThereforewehavetofindoutwhatisreallygoingonbehindthesceneswhenweuseabrowsertologin

WhenwefirstreceivealoginpageandtypeinausernameandpasswordafterwepresstheloginbuttonthebrowsersendsaPOSTrequesttotheremoteserverTheBrowserredirectstotheuserhomepageaftertheserververifiesthelogininformationandreturnsanHTTPresponseThequestionhereishowdoestheserverknowthatwehaveaccessprivilegesforthedesiredwebpageBecauseHTTPisstatelesstheserverhasnowayofknowingwhetherornotwepassedtheverificationinlaststepTheeasiestandperhapsthemostnaivesolutionistoappendtheusernameandpasswordtotheURLThisworksbutputstoomuchpressureontheserver(theservermustvalidateeveryrequestagainstthedatabase)andcanbedetrimentaltotheuserexperienceAnalternativewayofachievingthisgoalistosavetheusersidentityeitherontheserversideorclientsideusingcookiesandsessions

Cookiesinshortstorehistoricalinformation(includinguserlogininformation)ontheclientscomputerTheclientsbrowsersendsthesecookieseverytimetheuservisitsthesamewebsiteautomaticallycompletingtheloginstepfortheuser

Figure61cookieprinciple

SessionsontheotherhandstorehistoricalinformationontheserversideTheserverusesasessionidtoidentifydifferentsessionsandthesessionidthatisgeneratedbytheservershouldalwaysberandomanduniqueYoucanusecookiesorURLargumentstogettheclientsidentity

Figure62sessionprinciple

CookiesCookiesaremaintainedbybrowsersTheycanbemodifiedduringcommunicationbetweenwebserversandbrowsersWebapplicationscanaccesscookieinformationwhenusersvisitthecorrespondingwebsitesWithinmostbrowsersettingsthereisonesettingpertainingtocookieprivacyYoushouldbeabletoseesomethingsimilartothefollowingwhenyouopenit

Figure63cookieinbrowsers

Cookieshaveanexpirytimeandtherearetwotypesofcookiesdistinguishedbytheirlifecylessessioncookiesandpersistentcookies

IfyourapplicationdoesntsetacookieexpirytimethebrowserwillnotsaveitintothelocalfilesystemafterthebrowserisclosedThesecookiesarecalledsessioncookiesandthistypeofcookieisusuallysavedinmemoryinsteadoftothelocalfilesystem

Ifyourapplicationdoessetanexpirytime(forexamplesetMaxAge(606024))thebrowserwillsavethiscookietothelocalfilesystemanditwillnotbedeleteduntilreachingtheallottedexpirytimeCookiesthataresavedtothelocalfilesystemcanbesharedbydifferentbrowserprocesses-forexamplebytwoIEwindowsdifferentbrowsersusedifferentprocessesfordealingwithcookiesthataresavedinmemory  

Sessionandcookies

137

SetcookiesinGoGousestheSetCookiefunctioninthenethttppackagetosetcookies

httpSetCookie(wResponseWritercookieCookie)

wistheresponseoftherequestandcookieisastructLetsseewhatitlookslike

typeCookiestruct

Namestring

Valuestring

Pathstring

Domainstring

ExpirestimeTime

RawExpiresstring

MaxAge=0meansnoMax-Ageattributespecified

MaxAgelt0meansdeletecookienowequivalentlyMax-Age0

MaxAgegt0meansMax-Ageattributepresentandgiveninseconds

MaxAgeint

Securebool

HttpOnlybool

Rawstring

Unparsed[]stringRawtextofunparsedattribute-valuepairs

Hereisanexampleofsettingacookie

expiration=timeNow()Add(36524timeHour)

cookie=httpCookieNameusernameValueastaxieExpiresexpiration

httpSetCookie(wampcookie)

FetchcookiesinGoTheaboveexampleshowshowtosetacookieNowletsseehowtogetacookiethathasbeenset

cookie_=rCookie(username)

fmtFprint(wcookie)

Hereisanotherwaytogetacookie

for_cookie=rangerCookies()

fmtFprint(wcookieName)

Asyoucanseeitsveryconvenienttogetcookiesfromrequests

SessionsAsessionisaseriesofactionsormessagesForexampleyoucanthinkoftheactionsyoubetweenpickingupyourtelephonetohanginguptobeatypeofsessionWhenitcomestonetworkprotocolssessionshavemoretodowithconnectionsbetweenbrowsersandservers

Sessionshelptostoretheconnectionstatusbetweenserverandclientandthiscansometimesbeintheformofadatastoragestruct

Sessionandcookies

138

Sessionsareaserver-sidemechanismandusuallyemployhashtables(orsomethingsimilar)tosaveincominginformation

WhenanapplicationneedstoassignanewsessiontoaclienttheservershouldcheckifthereareanyexistingsessionsforthesameclientwithauniquesessionidIfthesessionidalreadyexiststheserverwilljustreturnthesamesessiontotheclientOntheotherhandifasessioniddoesntexistfortheclienttheservercreatesabrandnewsession(thisusuallyhappenswhentheserverhasdeletedthecorrespondingsessionidbuttheuserhasappendedtheoldsessionmanually)

Thesessionitselfisnotcomplexbutitsimplementationanddeploymentaresoyoucannotuseonewaytorulethemall

SummaryInconclusionthepurposeofsessionsandcookiesarethesameTheyarebothforovercomingthestatelessnessofHTTPbuttheyusedifferentmethodsSessionsusecookiestosavesessionidsontheclientsideandsaveallotherinformationontheserversideCookiessaveallclientinformationontheclientsideYoumayhavenoticedthatcookieshavesomesecurityproblemsForexampleusernamesandpasswordscanpotentiallybecrackedandcollectedbymaliciousthirdpartywebsites

Herearetwocommonexploits

1 appAsettinganunexpectedcookieforappB2 XSSattackappAusestheJavaScriptdocumentcookietoaccessthecookiesofappB

AfterfinishingthissectionyoushouldknowsomeofthebasicconceptsofcookiesandsessionsYoushouldbeabletounderstandthedifferencesbetweenthemsothatyouwontkillyourselfwhenbugsinevitablyemergeWelldiscusssessionsinmoredetailinthefollowingsections

LinksDirectoryPrevioussectionDatastorageandsessionNextsectionHowtousesessioninGo

Sessionandcookies

139

62HowtousesessionsinGoInsection61welearnedthatsessionsareonesolutionforverifyingusersandthatfornowtheGostandardlibrarydoesnothavebaked-insupportforsessionsorsessionhandlingSoweregoingtoimplementourownversionofasessionmanagerinGo

CreatingsessionsThebasicprinciplebehindsessionsisthataservermaintainsinformationforeverysingleclientandclientsrelyonuniquesessionidstoaccessthisinformationWhenusersvisitthewebapplicationtheserverwillcreateanewsessionwiththefollowingthreestepsasneeded

CreateauniquesessionidOpenupadatastoragespacenormallywesavesessionsinmemorybutyouwillloseallsessiondataifthesystemisaccidentallyinterruptedThiscanbeaveryseriousissueifwebapplicationdealswithsensitivedatalikeinelectroniccommerceforinstanceInordertosolvethisproblemyoucaninsteadsaveyoursessiondatainadatabaseorfilesystemThismakesdatapersistencemorereliableandeasytosharewithotherapplicationsalthoughthetradeoffisthatmoreserver-sideIOisneededtoreadandwritethesesessionsSendtheuniquesessionidtotheclient

ThekeystephereistosendtheuniquesessionidtotheclientInthecontextofastandardHTTPresponseyoucaneitherusetheresponselineheaderorbodytoaccomplishthisthereforewehavetwowaystosendsessionidstoclientsbycookiesorURLrewrites

CookiestheservercaneasilyuseSet-cookieinsideofaresponseheadertosendasessionidtoaclientandaclientcanthenusethiscookieforfuturerequestsweoftensettheexpirytimeforcookiescontainingsessioninformationto0whichmeansthecookiewillbesavedinmemoryandonlydeletedafterusershaveclosetheirbrowsersURLrewriteappendthesessionidasargumentsintheURLforallpagesThiswayseemsmessybutitsthebestchoiceifclientshavedisabledcookiesintheirbrowsers

UseGotomanagesessionsWevetalkedaboutconstructingsessionsandyoushouldnowhaveageneraloverviewofitbuthowcanweusesessionsondynamicpagesLetstakeacloserlookatthelifecycleofasessionsowecancontinueimplementingourGosessionmanager

Sessionmanagementdesign

Hereisalistofsomeofthekeyconsiderationsinsessionmanagementdesign

GlobalsessionmanagerKeepsessioniduniqueHaveonesessionforeveryuserSessionstorageinmemoryfileordatabaseDealwithexpiredsessions

NextwellexamineacompleteexampleofaGosessionmanagerandtherationalebehindsomeofitsdesigndecisions

Sessionmanager

Defineaglobalsessionmanager

HowtousesessioninGo

140

typeManagerstruct

cookieNamestringprivatecookiename

locksyncMutexprotectssession

providerProvider

maxlifetimeint64

funcNewManager(provideNamecookieNamestringmaxlifetimeint64)(Managererror)

providerok=provides[provideName]

ifok

returnnilfmtErrorf(sessionunknownprovideq(forgottenimport)provideName)

returnampManagerproviderprovidercookieNamecookieNamemaxlifetimemaxlifetimenil

Createaglobalsessionmanagerinthemain()function

varglobalSessionssessionManager

Theninitializethesessionmanager

funcinit()

globalSessions=NewManager(memorygosessionid3600)

WeknowthatwecansavesessionsinmanywaysincludinginmemorythefilesystemordirectlyintothedatabaseWeneedtodefineaProviderinterfaceinordertorepresenttheunderlyingstructureofoursessionmanager

typeProviderinterface

SessionInit(sidstring)(Sessionerror)

SessionRead(sidstring)(Sessionerror)

SessionDestroy(sidstring)error

SessionGC(maxLifeTimeint64)

SessionInitimplementstheinitializationofasessionandreturnsanewsessionifitsucceedsSessionReadreturnsasessionrepresentedbythecorrespondingsidCreatesanewsessionandreturnsitifitdoesnotalreadyexistSessionDestroygivenansiddeletesthecorrespondingsessionSessionGCdeletesexpiredsessionvariablesaccordingtomaxLifeTime

SowhatmethodsshouldoursessioninterfacehaveIfyouhaveanyexperienceinwebdevelopmentyoushouldknowthatthereareonlyfouroperationsforsessionssetvaluegetvaluedeletevalueandgetcurrentsessionidSooursessioninterfaceshouldhavefourmethodstoperformtheseoperations

typeSessioninterface

Set(keyvalueinterface)errorsetsessionvalue

Get(keyinterface)interfacegetsessionvalue

Delete(keyinterface)errordeletesessionvalue

SessionID()stringbackcurrentsessionID

ThisdesigntakesitsrootsfromthedatabasesqldriverwhichdefinestheinterfacefirstthenregistersspecificstructureswhenwewanttouseitThefollowingcodeistheinternalimplementationofasessionregisterfunction

HowtousesessioninGo

141

varprovides=make(map[string]Provider)

Registermakesasessionprovideravailablebytheprovidedname

IfaRegisteriscalledtwicewiththesamenameorifthedriverisnil

itpanics

funcRegister(namestringproviderProvider)

ifprovider==nil

panic(sessionRegisterproviderisnil)

if_dup=provides[name]dup

panic(sessionRegistercalledtwiceforprovider+name)

provides[name]=provider

UniquesessionidsSessionidsareforidentifyingusersofwebapplicationssotheymustbeuniqueThefollowingcodeshowshowtoachievethisgoal

func(managerManager)sessionId()string

b=make([]byte32)

if_err=ioReadFull(randReaderb)err=nil

return

returnbase64URLEncodingEncodeToString(b)

CreatingasessionWeneedtoallocateorgetanexistingsessioninordertovalidateuseroperationsTheSessionStartfunctionisforcheckingtheexistenceofanysessionsrelatedtothecurrentuserandcreatinganewsessionifnoneisfound

func(managerManager)SessionStart(whttpResponseWriterrhttpRequest)(sessionSession)

managerlockLock()

defermanagerlockUnlock()

cookieerr=rCookie(managercookieName)

iferr=nil||cookieValue==

sid=managersessionId()

session_=managerproviderSessionInit(sid)

cookie=httpCookieNamemanagercookieNameValueurlQueryEscape(sid)PathHttpOnlytrueM

axAgeint(managermaxlifetime)

httpSetCookie(wampcookie)

else

sid_=urlQueryUnescape(cookieValue)

session_=managerproviderSessionRead(sid)

return

Hereisanexamplethatusessessionsforaloginoperation

funclogin(whttpResponseWriterrhttpRequest)

sess=globalSessionsSessionStart(wr)

rParseForm()

ifrMethod==GET

t_=templateParseFiles(logingtpl)

wHeader()Set(Content-Typetexthtml)

tExecute(wsessGet(username))

else

sessSet(usernamerForm[username])

httpRedirect(wr302)

HowtousesessioninGo

142

Operationvaluesetgetanddelete

TheSessionStartfunctionreturnsavariablethatimplementsasessioninterfaceHowdoweuseit

YousawsessionGet(uid)intheaboveexampleforabasicoperationNowletsexamineamoredetailedexample

funccount(whttpResponseWriterrhttpRequest)

sess=globalSessionsSessionStart(wr)

createtime=sessGet(createtime)

ifcreatetime==nil

sessSet(createtimetimeNow()Unix())

elseif(createtime(int64)+360)lt(timeNow()Unix())

globalSessionsSessionDestroy(wr)

sess=globalSessionsSessionStart(wr)

ct=sessGet(countnum)

ifct==nil

sessSet(countnum1)

else

sessSet(countnum(ct(int)+1))

t_=templateParseFiles(countgtpl)

wHeader()Set(Content-Typetexthtml)

tExecute(wsessGet(countnum))

AsyoucanseeoperatingonsessionssimplyinvolvesusingthekeyvaluepatternintheSetGetandDeleteoperations

BecausesessionshavetheconceptofanexpirytimewedefinetheGCtoupdatethesessionslatestmodifytimeThiswaytheGCwillnotdeletesessionsthathaveexpiredbutarestillbeingused

ResetsessionsWeknowthatwebapplicationshavealogoutoperationWhenuserslogoutweneedtodeletethecorrespondingsessionWevealreadyusedtheresetoperationinaboveexample-nowletstakealookatthefunctionbody

Destroysessionid

func(managerManager)SessionDestroy(whttpResponseWriterrhttpRequest)

cookieerr=rCookie(managercookieName)

iferr=nil||cookieValue==

return

else

managerlockLock()

defermanagerlockUnlock()

managerproviderSessionDestroy(cookieValue)

expiration=timeNow()

cookie=httpCookieNamemanagercookieNamePathHttpOnlytrueExpiresexpirationMaxAge-1

httpSetCookie(wampcookie)

Deletesessions

LetsseehowtoletthesessionmanagerdeleteasessionWeneedtostarttheGCinthemain()function

HowtousesessioninGo

143

funcinit()

goglobalSessionsGC()

func(managerManager)GC()

managerlockLock()

defermanagerlockUnlock()

managerproviderSessionGC(managermaxlifetime)

timeAfterFunc(timeDuration(managermaxlifetime)func()managerGC())

WeseethattheGCmakesfulluseofthetimerfunctioninthetimepackageItautomaticallycallsGCwhenthesessiontimesoutensuringthatallsessionsareusableduringmaxLifeTimeAsimilarsolutioncanbeusedtocountonlineusers

SummarySofarweimplementedasessionmanagertomanageglobalsessionsinthewebapplicationanddefinedtheProviderinterfaceasthestorageimplementationofSessionInthenextsectionwearegoingtotalkabouthowtoimplementProviderforadditionalsessionstoragestructureswhichyouwillbeabletoreferenceinthefuture

LinksDirectoryPrevioussectionSessionandcookiesNextsectionSessionstorage

HowtousesessioninGo

144

63SessionstorageWeintroducedasimplesessionmanagersworkingprinciplesintheprevioussectionandamongotherthingswedefinedasessionstorageinterfaceInthissectionImgoingtoshowyouanexampleofamemorybasedsessionstorageenginethatimplementsthisinterfaceYoucantailorthistootherformsofsessionstorageaswell

packagememory

import(

containerlist

githubcomastaxiesession

sync

time

)

varpder=ampProviderlistlistNew()

typeSessionStorestruct

sidstringuniquesessionid

timeAccessedtimeTimelastaccesstime

valuemap[interface]interfacesessionvaluestoredinside

func(stSessionStore)Set(keyvalueinterface)error

stvalue[key]=value

pderSessionUpdate(stsid)

returnnil

func(stSessionStore)Get(keyinterface)interface

pderSessionUpdate(stsid)

ifvok=stvalue[key]ok

returnv

else

returnnil

returnnil

func(stSessionStore)Delete(keyinterface)error

delete(stvaluekey)

pderSessionUpdate(stsid)

returnnil

func(stSessionStore)SessionID()string

returnstsid

typeProviderstruct

locksyncMutexlock

sessionsmap[string]listElementsaveinmemory

listlistListgc

func(pderProvider)SessionInit(sidstring)(sessionSessionerror)

pderlockLock()

deferpderlockUnlock()

v=make(map[interface]interface0)

newsess=ampSessionStoresidsidtimeAccessedtimeNow()valuev

element=pderlistPushBack(newsess)

pdersessions[sid]=element

returnnewsessnil

func(pderProvider)SessionRead(sidstring)(sessionSessionerror)

ifelementok=pdersessions[sid]ok

Sessionstorage

145

returnelementValue(SessionStore)nil

else

sesserr=pderSessionInit(sid)

returnsesserr

returnnilnil

func(pderProvider)SessionDestroy(sidstring)error

ifelementok=pdersessions[sid]ok

delete(pdersessionssid)

pderlistRemove(element)

returnnil

returnnil

func(pderProvider)SessionGC(maxlifetimeint64)

pderlockLock()

deferpderlockUnlock()

for

element=pderlistBack()

ifelement==nil

break

if(elementValue(SessionStore)timeAccessedUnix()+maxlifetime)lttimeNow()Unix()

pderlistRemove(element)

delete(pdersessionselementValue(SessionStore)sid)

else

break

func(pderProvider)SessionUpdate(sidstring)error

pderlockLock()

deferpderlockUnlock()

ifelementok=pdersessions[sid]ok

elementValue(SessionStore)timeAccessed=timeNow()

pderlistMoveToFront(element)

returnnil

returnnil

funcinit()

pdersessions=make(map[string]listElement0)

sessionRegister(memorypder)

TheaboveexampleimplementsamemorybasedsessionstoragemechanismItusesitsinit()functiontoregisterthisstorageenginetothesessionmanagerSohowdoweregisterthisenginefromourmainprogram

import(

githubcomastaxiesession

_githubcomastaxiesessionprovidersmemory

)

Weusetheblankimportmechanism(whichwillinvokethepackagesinit()functionautomatically)toregisterthisenginetoasessionmanagerWethenusethefollowingcodetoinitializethesessionmanager

Sessionstorage

146

varglobalSessionssessionManager

initializeininit()function

funcinit()

globalSessions_=sessionNewManager(memorygosessionid3600)

goglobalSessionsGC()

LinksDirectoryPrevioussectionHowtousesessionsinGoNextsectionPreventsessionhijacking

Sessionstorage

147

64PreventingsessionhijackingSessionhijackingisacommonyetserioussecuritythreatClientsusesessionidsforvalidationandotherpurposeswhencommunicatingwithserversUnfortunatelymaliciousthirdpartiescansometimestrackthesecommunicationsandfigureouttheclientsessionid

Inthissectionwearegoingtoshowyouhowtohijackasessionforeducationalpurposes

ThesessionhijackingprocessThefollowingcodeisacounterforthecountvariable

funccount(whttpResponseWriterrhttpRequest)

sess=globalSessionsSessionStart(wr)

ct=sessGet(countnum)

ifct==nil

sessSet(countnum1)

else

sessSet(countnum(ct(int)+1))

t_=templateParseFiles(countgtpl)

wHeader()Set(Content-Typetexthtml)

tExecute(wsessGet(countnum))

Thecontentofcountgtplisasfollows

HiNowcount

Wecanseethefollowingcontentinthebrowser

Figure64countinbrowser

Keeprefreshinguntilthenumberbecomes6thenopenthebrowserscookiemanager(Iusechromehere)Youshouldbeabletoseethefollowinginformation

Figure65cookiessavedinabrowser

Thisstepisveryimportantopenanotherbrowser(Iusefirefoxhere)copytheURLtothenewbrowseropenacookiesimulatortocreateanewcookieandinputexactlythesamevalueasthecookiewesawinourfirstbrowser

Figure66Simulateacookie

Refreshthepageandyoullseethefollowing

Figure67hijackingthesessionhassucceeded

HereweseethatwecanhijacksessionsbetweendifferentbrowsersandactionsperformedinonebrowsercanaffectthestateofapageinanotherbrowserBecauseHTTPisstatelessthereisnowayofknowingthatthesessionidfromfirefoxissimulatedandchromeisalsonotabletoknowthatitssessionidhasbeenhijacked

Preventhijackofsession

148

preventsessionhijacking

cookieonlyandtoken

ThroughthissimpleexampleofhijackingasessionyoucanseethatitsverydangerousbecauseitallowsattackerstodowhatevertheywantSohowcanwepreventsessionhijacking

ThefirststepistoonlysetsessionidsincookiesinsteadofinURLrewritesAlsoweshouldsetthehttponlycookiepropertytotrueThisrestrictsclient-sidescriptsfromgainingaccesstothesessionidUsingthesetechniquescookiescannotbeaccessedbyXSSanditwontbeaseasyaswedemonstratedtogetasessionidfromacookiemanager

ThesecondstepistoaddatokentoeveryrequestSimilartothemannerinwhichwedealtwithrepeatingformsubmissionsinprevioussectionsweaddahiddenfieldthatcontainsatokenWhenarequestissenttotheserverwecanverifythistokentoprovethattherequestisunique

h=md5New()

salt=astaxie^7amp8888

ioWriteString(hsalt+timeNow()String())

token=fmtSprintf(xhSum(nil))

ifrForm[token]=token

asktologin

sessSet(tokentoken)

SessionidtimeoutAnothersolutionistoaddacreatetimeforeverysessionandtoreplaceexpiredsessionidswithnewonesThiscanpreventsessionhijackingundercertaincircumstancessuchaswhenthehijackisattemptedtoolate

createtime=sessGet(createtime)

ifcreatetime==nil

sessSet(createtimetimeNow()Unix())

elseif(createtime(int64)+60)lt(timeNow()Unix())

globalSessionsSessionDestroy(wr)

sess=globalSessionsSessionStart(wr)

Wesetavaluetosavethecreatetimeandcheckifitsexpired(Iset60secondshere)Thisstepcanoftenthwartsessionhijackingattempts

BycombiningthetwosolutionssetoutaboveyouwillbeabletopreventmostsessionhijackingattemptsfromsucceedingOntheonehandsessionidsthatarefrequentlyresetwillresultinanattackeralwaysgettingexpiredanduselesssessionidsontheotherhandbysettingthehttponlypropertyoncookiesandensuringthatsessionidscanonlybepassedviacookiesallURLbasedattacksaremitigatedFinallywesetMaxAge=0onourcookieswhichmeansthatthesessionidswillnotbesavedinthebrowserhistory

LinksDirectoryPrevioussectionSessionstorageNextsectionSummary

Preventhijackofsession

149

65SummaryInthischapterwelearnedaboutthedefinitionandpurposeofsessionsandcookiesandtherelationshipbetweenthetwoSinceGodoesntsupportsessionsinitsstandardlibrarywealsodesignedourownsessionmanagerWewentthrougheverythingfromcreatingclientsessionstodeletingthemWethendefinedaninterfacecalledProviderwhichsupportsallsessionstoragestructuresInsection63weimplementedamemorybasedsessionmanagertopersistclientdataacrosssessionsInsection64IdemonstratedonewayofhijackingasessionThenwelookedathowtopreventyourownsessionsfrombeinghijackedIhopethatyounowunderstandmostoftheworkingprinciplesbehindsessionssothatyoureabletosafelyusetheminyourapplications

LinksDirectoryPrevioussectionPreventsessionhijackingNextchapterTextfiles

Summary

150

7TextfilesHandlingtextfilesisabigpartofwebdevelopmentWeoftenneedtoproduceorhandlereceivedtextcontentincludingstringsnumbersJSONXMLetcAsahighperformancelanguageGohasgoodsupportforthisinitsstandardlibraryYoullfindthatthesesupportinglibrariesarejustawesomeandwillallowyoutoeasilydealwithanytextcontentyoumayencounterThischaptercontains4sectionsandwillgiveyouafullintroductiontotextprocessinginGo

XMLisaninteractivelanguagethatiscommonlyusedinmanyAPIsmanywebserverswritteninJavauseXMLastheirstandardinteractionlanguageWellmoretalkaboutXMLinsection71Insection72welltakealookatJSONwhichhasbeenverypopularinrecentyearsandismuchmoreconvenientthanXMLInsection73wearegoingtotalkaboutregularexpressionswhich(forthemajorityofpeople)lookslikealanguageusedbyaliensInsection74youwillseehowtheMVCpatternisusedtodevelopapplicationsinGoandalsohowtouseGostemplatepackagefortemplatingyourviewsInsection75wellintroduceyoutofileandfolderoperationsFinallywewillexplainsomeGostringoperationsinsection76

LinksDirectoryPreviousChapterChapter6SummaryNextsectionXML

Textfiles

151

71XMLXMLisacommonlyuseddatacommunicationformatinwebservicesTodayitsassumingamoreandmoreimportantroleinwebdevelopmentInthissectionweregoingtointroducehowtoworkwithXMLthroughGosstandardlibrary

IwillnotmakeanyattemptstoteachXMLssyntaxorconventionsForthatpleasereadmoredocumentationaboutXMLitselfWewillonlyfocusonhowtoencodeanddecodeXMLfilesinGo

SupposeyouworkinITandyouhavetodealwiththefollowingXMLconfigurationfile

ltxmlversion=10encoding=utf-8gt

ltserversversion=1gt

ltservergt

ltserverNamegtShanghai_VPNltserverNamegt

ltserverIPgt127001ltserverIPgt

ltservergt

ltservergt

ltserverNamegtBeijing_VPNltserverNamegt

ltserverIPgt127002ltserverIPgt

ltservergt

ltserversgt

TheaboveXMLdocumentcontainstwokindsofinformationaboutyourservertheservernameandIPWewillusethisdocumentinourfollowingexamples

ParseXMLHowdoweparsethisXMLdocumentWecanusetheUnmarshalfunctioninGosxmlpackagetodothis

funcUnmarshal(data[]bytevinterface)error

thedataparameterreceivesadatastreamfromanXMLsourceandvisthestructureyouwanttooutputtheparsedXMLtoItisaninterfacewhichmeansyoucanconvertXMLtoanystructureyoudesireHerewellonlytalkabouthowtoconvertfromXMLtothestructtypesincetheysharesimilartreestructures

Samplecode

XML

152

packagemain

import(

encodingxml

fmt

ioioutil

os

)

typeRecurlyserversstruct

XMLNamexmlName`xmlservers`

Versionstring`xmlversionattr`

Svs[]server`xmlserver`

Descriptionstring`xmlinnerxml`

typeserverstruct

XMLNamexmlName`xmlserver`

ServerNamestring`xmlserverName`

ServerIPstring`xmlserverIP`

funcmain()

fileerr=osOpen(serversxml)Forreadaccess

iferr=nil

fmtPrintf(errorverr)

return

deferfileClose()

dataerr=ioutilReadAll(file)

iferr=nil

fmtPrintf(errorverr)

return

v=Recurlyservers

err=xmlUnmarshal(dataampv)

iferr=nil

fmtPrintf(errorverr)

return

fmtPrintln(v)

XMLisactuallyatreedatastructureandwecandefineaverysimilarstructureusingstructsinGothenusexmlUnmarshaltoconvertfromXMLtoourstructobjectThesamplecodewillprintthefollowingcontent

servers1[serverShanghai_VPN127001serverBeijing_VPN127002]

ltservergt

ltserverNamegtShanghai_VPNltserverNamegt

ltserverIPgt127001ltserverIPgt

ltservergt

ltservergt

ltserverNamegtBeijing_VPNltserverNamegt

ltserverIPgt127002ltserverIPgt

ltservergt

WeusexmlUnmarshaltoparsetheXMLdocumenttothecorrespondingstructobjectYoushouldseethatwehavesomethinglikexmlserverNameinourstructThisisafeatureofstructscalledstructtagsforhelpingwithreflectionLetsseethedefinitionofUnmarshalagain

funcUnmarshal(data[]bytevinterface)error

XML

153

ThefirstargumentisanXMLdatastreamThesecondargumentisstoragetypeandsupportsthestructsliceandstringtypesGosXMLpackageusesreflectionfordatamappingsoallfieldsinvshouldbeexportedHoweverthiscausesaproblemhowdoesitknowwhichXMLfieldcorrespondstothemappedstructfieldTheansweristhattheXMLparserparsesdatainacertainorderThelibrarywilltrytofindthematchingstructtagfirstIfamatchcannotbefoundthenitsearchesthroughthestructfieldnamesBeawarethatalltagsfieldnamesandXMLelementsarecasesensitivesoyouhavetomakesurethatthereisaone-to-onecorrespondenceforthemappingtosucceed

GosreflectionmechanismallowsyoutousethistaginformationtoreflectXMLdatatoastructobjectIfyouwanttoknowmoreaboutreflectioninGopleasereadthepackagedocumentationonstructtagsandreflection

HerearesomeruleswhenusingthexmlpackagetoparseXMLdocumentstostructs

Ifthefieldtypeisastringor[]bytewiththetaginnerxmlUnmarshalwillassignrawXMLdatatoitlikeDescriptionintheaboveexample

Shanghai_VPN127001Beijing_VPN127002

IfafieldiscalledXMLNameanditstypeisxmlNamethenitgetstheelementnamelikeserversinaboveexample

IfafieldstagcontainsthecorrespondingelementnamethenitgetstheelementnameaswelllikeservernameandserveripintheaboveexampleIfafieldstagcontainsattrthenitgetsthecorrespondingelementsattributelikeversioninaboveexampleIfafieldstagcontainssomethinglikeagtbgtcitgetsthevalueoftheelementcofnodebofnodeaIfafieldstagcontains=thenitgetsnothingIfafieldstagcontainsanythenitgetsallchildelementswhichdonotfittheotherrulesIftheXMLelementshaveoneormorecommentsallofthesecommentswillbeaddedtothefirstfieldthathasthetagthatcontainscommentsThisfieldtypecanbeastringor[]byteIfthiskindoffielddoesnotexistallcommentsarediscarded

TheserulestellyouhowtodefinetagsinstructsOnceyouunderstandtheserulesmappingXMLtostructswillbeaseasyasthesamplecodeaboveBecausetagsandXMLelementshaveaone-to-onecorrespondencewecanalsouseslicestorepresentmultipleelementsonthesamelevel

Notethatallfieldsinstructsshouldbeexported(capitalized)inordertoparsedatacorrectly

ProduceXMLWhatifwewanttoproduceanXMLdocumentinsteadofparsingoneHowdowedothisinGoUnsurprisinglythexmlpackageprovidestwofunctionswhichareMarshalandMarshalIndentwherethesecondfunctionautomaticallyindentsthemarshalledXMLdocumentTheirdefinitionasfollows

funcMarshal(vinterface)([]byteerror)

funcMarshalIndent(vinterfaceprefixindentstring)([]byteerror)

ThefirstargumentinbothofthesefunctionsisforstoringamarshalledXMLdatastream

Letslookatanexampletoseehowthisworks

XML

154

packagemain

import(

encodingxml

fmt

os

)

typeServersstruct

XMLNamexmlName`xmlservers`

Versionstring`xmlversionattr`

Svs[]server`xmlserver`

typeserverstruct

ServerNamestring`xmlserverName`

ServerIPstring`xmlserverIP`

funcmain()

v=ampServersVersion1

vSvs=append(vSvsserverShanghai_VPN127001)

vSvs=append(vSvsserverBeijing_VPN127002)

outputerr=xmlMarshalIndent(v)

iferr=nil

fmtPrintf(errorvnerr)

osStdoutWrite([]byte(xmlHeader))

osStdoutWrite(output)

Theaboveexampleprintsthefollowinginformation

ltxmlversion=10encoding=UTF-8gt

ltserversversion=1gt

ltservergt

ltserverNamegtShanghai_VPNltserverNamegt

ltserverIPgt127001ltserverIPgt

ltservergt

ltservergt

ltserverNamegtBeijing_VPNltserverNamegt

ltserverIPgt127002ltserverIPgt

ltservergt

ltserversgt

AswevepreviouslydefinedthereasonwehaveosStdoutWrite([]byte(xmlHeader))isbecausebothxmlMarshalIndentandxmlMarshaldonotoutputXMLheadersontheirownsowehavetoexplicitlyprinttheminordertoproduceXMLdocumentscorrectly

HerewecanseethatMarshalalsoreceivesavparameteroftypeinterfaceSowhataretheruleswhenmarshallingtoanXMLdocument

IfvisanarrayorsliceitprintsallelementslikeavalueIfvisapointeritprintsthecontentthatvispointingtoprintingnothingwhenvisnilIfvisainterfaceitdealwiththeinterfaceaswellIfvisoneoftheothertypesitprintsthevalueofthattype

SohowdoesxmlMarshaldecidetheelementsnameItfollowstheensuingrules

IfvisastructitdefinesthenameinthetagofXMLNameThefieldnameisXMLNameandthetypeisxmlNameFieldtaginstructFieldnameinstructTypenameofmarshal

XML

155

ThenweneedtofigureouthowtosettagsinordertoproducethefinalXMLdocument

XMLNamewillnotbeprintedFieldsthathavetagscontaining-willnotbeprintedIfatagcontainsnameattritusesnameastheattributenameandthefieldvalueasthevaluelikeversionintheaboveexampleIfatagcontainsattritusesthefieldsnameastheattributenameandthefieldvalueasitsvalueIfatagcontainschardataitprintscharacterdatainsteadofelementIfatagcontainsinnerxmlitprintstherawvalueIfatagcontainscommentitprintsitasacommentwithoutescapingsoyoucannothave--initsvalueIfatagcontainsomitemptyitomitsthisfieldifitsvalueiszero-valueincludingfalse0nilpointerornilinterfacezerolengthofarrayslicemapandstringIfatagcontainsagtbgtcitprintsthreeelementswhereacontainsbandbcontainsclikeinthefollowingcode `xmlFirstNamestringxmlnamegtfirstLastNamestringxmlnamegtlast`

Asta

Xieltnamegt```YoumayhavenoticedthatstructtagsareveryusefulfordealingwithXMLandthesamegoesfortheotherdataformatswellbediscussinginthefollowingsectionsIfyoustillfindthatyouhaveproblemswithworkingwithstructtagsyoushouldprobablyreadmoredocumentationaboutthembeforedivingintothenextsection

LinksDirectoryPrevioussectionTextfilesNextsectionJSON

XML

156

72JSONJSON(JavaScriptObjectNotation)isalightweightdataexchangelanguagewhichisbasedontextdescriptionItsadvantagesincludebeingself-descriptiveeasytounderstandetcEventhoughitisasubsetofJavaScriptJSONusesadifferenttextformattheresultbeingthatitcanbeconsideredasanindependentlanguageJSONbearssimilaritytoC-familylanguages

ThebiggestdifferencebetweenJSONandXMListhatXMLisacompletemarkuplanguagewhereasJSONisnotJSONissmallerandfasterthanXMLthereforeitsmucheasierandquickertoparseinbrowserswhichisoneofthereasonswhymanyopenplatformschoosetouseJSONastheirdataexchangeinterfacelanguage

SinceJSONisbecomingmoreandmoreimportantinwebdevelopmentletstakealookatthelevelofsupportGohasforJSONYoullfindthatGosstandardlibraryhasverygoodsupportforencodinganddecodingJSON

HereweuseJSONtorepresenttheexampleintheprevioussection

servers[serverNameShanghai_VPNserverIP127001serverNameBeijing_VPNserverIP127002]

TherestofthissectionwillusethisJSONdatatointroduceJSONconceptsinGo

ParseJSON

Parsetostruct

SupposewehavetheJSONintheaboveexampleHowcanweparsethisdataandmapittoastructinGoGoprovidesthefollowingfunctionforjustthispurpose

funcUnmarshal(data[]bytevinterface)error

Wecanusethisfunctionlikeso

packagemain

import(

encodingjson

fmt

)

typeServerstruct

ServerNamestring

ServerIPstring

typeServerslicestruct

Servers[]Server

funcmain()

varsServerslice

str=`servers[serverNameShanghai_VPNserverIP127001serverNameBeijing_VPNserverIP

127002]`

jsonUnmarshal([]byte(str)amps)

fmtPrintln(s)

JSON

157

IntheaboveexamplewedefinedacorrespondingstructsinGoforourJSONusingsliceforanarrayofJSONobjectsandfieldnameasourJSONkeysButhowdoesGoknowwhichJSONobjectcorrespondstowhichspecificstructfiledSupposewehaveakeycalledFooinJSONHowdowefinditscorrespondingfield

FirstGotriestofindthe(capitalised)exportedfieldwhosetagcontainsFooIfnomatchcanbefoundlookforthefieldwhosenameisFooIftherearestillnotmatcheslookforsomethinglikeFOOorFoOignoringcasesensitivity

YoumayhavenoticedthatallfieldsthataregoingtobeassignedshouldbeexportedandGoonlyassignsfieldsthatcanbefoundignoringallothersThiscanbeusefulifyouneedtodealwithlargechunksofJSONdatabutyouonlyaspecificsubsetofitthedatayoudontneedcaneasilybediscarded

ParsetointerfaceWhenweknowwhatkindofJSONtoexpectinadvancewecanparseittoaspecificstructButwhatifwedontknow

WeknowthataninterfacecanbeanythinginGosoitisthebestcontainertosaveourJSONofunknownformatTheJSONpackageusesmap[string]interfaceand[]interfacetosaveallkindsofJSONobjectsandarraysHereisalistofJSONmappingrelations

boolrepresentsJSONbooleansfloat64representsJSONnumbersstringrepresentsJSONstringsnilrepresentsJSONnull

SupposewehavethefollowingJSONdata

b=[]byte(`NameWednesdayAge6Parents[GomezMorticia]`)

NowweparsethisJSONtoaninterface

varfinterface

err=jsonUnmarshal(bampf)

Thefstoresamapwherekeysarestringsandvaluesareinterfaces

f=map[string]interface

NameWednesday

Age6

Parents[]interface

Gomez

Morticia

SohowdoweaccessthisdataTypeassertion

m=f(map[string]interface)

Afterassertedyoucanusethefollowingcodetoaccessdata

JSON

158

forkv=rangem

switchvv=v(type)

casestring

fmtPrintln(kisstringvv)

caseint

fmtPrintln(kisintvv)

casefloat64

fmtPrintln(kisfloat64vv)

case[]interface

fmtPrintln(kisanarray)

foriu=rangevv

fmtPrintln(iu)

default

fmtPrintln(kisofatypeIdontknowhowtohandle)

AsyoucanseewecannowparseJSONofanunknownformatthroughinterfaceandtypeassertion

TheaboveexampleistheofficialsolutionbuttypeassertingisnotalwaysconvenientSoIrecommendanopensourceprojectcalledsimplejsoncreatedandmaintainedbybitlyHereisanexampleofhowtousethisprojecttodealwithJSONofanunknownformat

jserr=NewJson([]byte(`

test

array[123]

int10

float5150

bignum9223372036854775807

stringsimplejson

booltrue

`))

arr_=jsGet(test)Get(array)Array()

i_=jsGet(test)Get(int)Int()

ms=jsGet(test)Get(string)MustString()

ItsnothardtoseehowconvenientthisisCheckouttherepositorytoseemoreinformationhttpsgithubcombitlygo-simplejson

ProducingJSONInmanysituationsweneedtoproduceJSONdataandrespondtoclientsInGotheJSONpackagehasafunctioncalledMarshaltodojustthat

funcMarshal(vinterface)([]byteerror)

SupposeweneedtoproduceaserverinformationlistWehavefollowingsample

JSON

159

packagemain

import(

encodingjson

fmt

)

typeServerstruct

ServerNamestring

ServerIPstring

typeServerslicestruct

Servers[]Server

funcmain()

varsServerslice

sServers=append(sServersServerServerNameShanghai_VPNServerIP127001)

sServers=append(sServersServerServerNameBeijing_VPNServerIP127002)

berr=jsonMarshal(s)

iferr=nil

fmtPrintln(jsonerrerr)

fmtPrintln(string(b))

Output

Servers[ServerNameShanghai_VPNServerIP127001ServerNameBeijing_VPNServerIP127002]

AsyouknowallfieldnamesarecapitalizedbutifyouwantyourJSONkeynamestostartwithalowercaseletteryoushouldusestructtagsOtherwiseGowillnotproducedataforinternalfields

typeServerstruct

ServerNamestring`jsonserverName`

ServerIPstring`jsonserverIP`

typeServerslicestruct

Servers[]Server`jsonservers`

AfterthismodificationwecanproducethesameJSONdataasbefore

HerearesomepointsyouneedtokeepinmindwhentryingtoproduceJSON

Fieldtagscontaining-willnotbeoutputtedIfatagcontainsacustomizednameGousesthisinsteadofthefieldnamelikeserverNameintheaboveexampleIfatagcontainsomitemptythisfieldwillnotbeoutputtedifitiszero-valueIfthefieldtypeisboolstringintint64etcanditstagcontainsstringGoconvertsthisfieldtoitscorrespondingJSONtype

Example

JSON

160

typeServerstruct

IDwillnotbeoutputed

IDint`json-`

ServerName2willbeconvertedtoJSONtype

ServerNamestring`jsonserverName`

ServerName2string`jsonserverName2string`

IfServerIPisemptyitwillnotbeoutputted

ServerIPstring`jsonserverIPomitempty`

s=Server

ID3

ServerName`Go10`

ServerName2`Go10`

ServerIP``

b_=jsonMarshal(s)

osStdoutWrite(b)

Output

serverNameGo10serverName2Go10

TheMarshalfunctiononlyreturnsdatawhenithassucceededsoherearesomepointsweneedtokeepinmind

JSONonlysupportsstringsaskeyssoifyouwanttoencodeamapitstypehastobemap[string]TwhereTisthetypeinGoTypeslikechannelcomplextypesandfunctionsarenotcapableofbeingencodedtoJSONDonottrytoencodecyclicdataitleadstoaninfiniterecursionIfthefieldisapointerGooutputsthedatathatitpointstoorelseoutputsnullifitpointstonil

InthissectionweintroducedhowtodecodeandencodeJSONdatainGoWealsolookedatonethird-partyprojectcalledsimplejsonwhichisusefulforparsingJSONorunknownformatTheseareallusefulconceptsfordevelopingwebapplicationsinGo

LinksDirectoryPrevioussectionXMLNextsectionRegexp

JSON

161

73RegexpRegularExpressions(Regexp)isacomplicatedbutpowerfultoolforpatternmatchingandtextmanipulationAlthoughitdoesnotperformaswellaspuretextmatchingitsmoreflexibleBasedonitssyntaxyoucanfilteralmostanykindoftextfromyoursourcecontentIfyouneedtocollectdatainwebdevelopmentitsnotdifficulttouseRegexptoretrievemeaningfuldata

GohastheregexppackagewhichprovidesofficialsupportforregexpIfyouvealreadyusedregexpinotherprogramminglanguagesyoushouldbefamiliarwithitNotethatGoimplementedRE2standardexceptforCFormoredetailsfollowthislinkhttpcodegooglecompre2wikiSyntax

Gosstringspackagecanactuallydomanyjobslikesearching(ContainsIndex)replacing(Replace)parsing(SplitJoin)etcanditsfasterthanRegexpHoweverthesearealltrivialoperationsIfyouwanttosearchacaseinsensitivestringRegexpshouldbeyourbestchoiceSoifthestringspackageissufficientforyourneedsjustuseitsinceitseasytouseandreadifyouneedtoperformmoreadvancedoperationsuseRegexp

IfyourecallformvalidationfromprevioussectionsweusedRegexptoverifythevalidityofuserinputinformationBeawarethatallcharactersareUTF-8LetslearnmoreabouttheGoregexppackage

MatchTheregexppackagehas3functionstomatchifitmatchesapatternthenitreturnstruereturningfalseotherwise

funcMatch(patternstringb[]byte)(matchedboolerrorerror)

funcMatchReader(patternstringrioRuneReader)(matchedboolerrorerror)

funcMatchString(patternstringsstring)(matchedboolerrorerror)

All3functionscheckifpatternmatchestheinputsourcereturningtrueifitmatchesHoweverifyourRegexhassyntaxerrorsitwillreturnanerrorThe3inputsourcesofthesefunctionsaresliceofbyteRuneReaderandstring

HereisanexampleofhowtoverifyanIPaddress

funcIsIP(ipstring)(bbool)

ifm_=regexpMatchString(^[0-9]13[0-9]13[0-9]13[0-9]13$ip)m

returnfalse

returntrue

AsyoucanseeusingpatternintheregexppackageisnotthatdifferentHeresonemoreexampleonverifyingwhetheruserinputisvalid

funcmain()

iflen(osArgs)==1

fmtPrintln(Usageregexp[string])

osExit(1)

elseifm_=regexpMatchString(^[0-9]+$osArgs[1])m

fmtPrintln(Number)

else

fmtPrintln(Notnumber)

IntheaboveexamplesweuseMatch(Reader|String)tocheckifcontentisvalidbuttheyarealleasytouse

Regexp

162

FilterMatchmodecanverifycontentbutitcannotcutfilterorcollectdatafromitIfyouwanttodothatyouhavetousethecomplexmodeofRegexp

LetssayweneedtowriteacrawlerHereisanexampleforwhenyoumustuseRegexptofilterandcutdata

packagemain

import(

fmt

ioioutil

nethttp

regexp

strings

)

funcmain()

resperr=httpGet(httpwwwbaiducom)

iferr=nil

fmtPrintln(httpgeterror)

deferrespBodyClose()

bodyerr=ioutilReadAll(respBody)

iferr=nil

fmtPrintln(httpreaderror)

return

src=string(body)

ConvertHTMLtagstolowercase

re_=regexpCompile(lt[Ss]+gt)

src=reReplaceAllStringFunc(srcstringsToLower)

RemoveSTYLE

re_=regexpCompile(ltstyle[Ss]+ltstylegt)

src=reReplaceAllString(src)

RemoveSCRIPT

re_=regexpCompile(ltscript[Ss]+ltscriptgt)

src=reReplaceAllString(src)

RemoveallHTMLcodeinanglebracketsandreplacewithnewline

re_=regexpCompile(lt[Ss]+gt)

src=reReplaceAllString(srcn)

Removecontinuousnewline

re_=regexpCompile(s2)

src=reReplaceAllString(srcn)

fmtPrintln(stringsTrimSpace(src))

InthisexampleweuseCompileasthefirststepforcomplexmodeItverifiesthatyourRegexsyntaxiscorrectthenreturnsaRegexpforparsingcontentinotheroperations

HerearesomefunctionstoparseyourRegexpsyntax

funcCompile(exprstring)(Regexperror)

funcCompilePOSIX(exprstring)(Regexperror)

funcMustCompile(strstring)Regexp

funcMustCompilePOSIX(strstring)Regexp

Regexp

163

ThedifferencebetweenComplePOSIXandCompileisthattheformerhastousePOSIXsyntaxwhichisleftmostlongestsearchandthelatterisonlyleftmostsearchForinstanceforRegexp[a-z]24andcontentaa09aaa88aaaaCompilePOSIXreturnsaaaabutCompilereturnsaaMustprefixmeanspanicwhentheRegexpsyntaxisnotcorrectreturningerrorotherwise

NowthatweknowhowtocreateanewRegexpletsseehowthemethodsprovidedbythisstructcanhelpustooperateoncontent

func(reRegexp)Find(b[]byte)[]byte

func(reRegexp)FindAll(b[]bytenint)[][]byte

func(reRegexp)FindAllIndex(b[]bytenint)[][]int

func(reRegexp)FindAllString(sstringnint)[]string

func(reRegexp)FindAllStringIndex(sstringnint)[][]int

func(reRegexp)FindAllStringSubmatch(sstringnint)[][]string

func(reRegexp)FindAllStringSubmatchIndex(sstringnint)[][]int

func(reRegexp)FindAllSubmatch(b[]bytenint)[][][]byte

func(reRegexp)FindAllSubmatchIndex(b[]bytenint)[][]int

func(reRegexp)FindIndex(b[]byte)(loc[]int)

func(reRegexp)FindReaderIndex(rioRuneReader)(loc[]int)

func(reRegexp)FindReaderSubmatchIndex(rioRuneReader)[]int

func(reRegexp)FindString(sstring)string

func(reRegexp)FindStringIndex(sstring)(loc[]int)

func(reRegexp)FindStringSubmatch(sstring)[]string

func(reRegexp)FindStringSubmatchIndex(sstring)[]int

func(reRegexp)FindSubmatch(b[]byte)[][]byte

func(reRegexp)FindSubmatchIndex(b[]byte)[]int

These18methodsincludeidenticalfunctionsfordifferentinputsources(byteslicestringandioRuneReader)sowecanreallysimplifythislistbyignoringinputsourcesasfollows

func(reRegexp)Find(b[]byte)[]byte

func(reRegexp)FindAll(b[]bytenint)[][]byte

func(reRegexp)FindAllIndex(b[]bytenint)[][]int

func(reRegexp)FindAllSubmatch(b[]bytenint)[][][]byte

func(reRegexp)FindAllSubmatchIndex(b[]bytenint)[][]int

func(reRegexp)FindIndex(b[]byte)(loc[]int)

func(reRegexp)FindSubmatch(b[]byte)[][]byte

func(reRegexp)FindSubmatchIndex(b[]byte)[]int

Codesample

Regexp

164

packagemain

import(

fmt

regexp

)

funcmain()

a=IamlearningGolanguage

re_=regexpCompile([a-z]24)

Findthefirstmatch

one=reFind([]byte(a))

fmtPrintln(Findstring(one))

Findallmatchesandsavetoaslicenlessthan0meansreturnallmatchesindicateslengthofsliceifit

sgreaterthan0

all=reFindAll([]byte(a)-1)

fmtPrintln(FindAllall)

Findindexoffirstmatchstartandendposition

index=reFindIndex([]byte(a))

fmtPrintln(FindIndexindex)

Findindexofallmatchesthendoessamejobasabove

allindex=reFindAllIndex([]byte(a)-1)

fmtPrintln(FindAllIndexallindex)

re2_=regexpCompile(am()lang())

Findfirstsubmatchandreturnarraythefirstelementcontainsallelementsthesecondelementcontainsthe

resultoffirst()thethirdelementcontainstheresultofsecond()

Output

thefirstelementamlearningGolanguage

thesecondelementlearningGonoticespaceswillbeoutputedaswell

thethirdelementuage

submatch=re2FindSubmatch([]byte(a))

fmtPrintln(FindSubmatchsubmatch)

for_v=rangesubmatch

fmtPrintln(string(v))

SameasFindIndex()

submatchindex=re2FindSubmatchIndex([]byte(a))

fmtPrintln(submatchindex)

FindAllSubmatchfindallsubmatches

submatchall=re2FindAllSubmatch([]byte(a)-1)

fmtPrintln(submatchall)

FindAllSubmatchIndexfindindexofallsubmatches

submatchallindex=re2FindAllSubmatchIndex([]byte(a)-1)

fmtPrintln(submatchallindex)

AswevepreviouslymentionedRegexpalsohas3methodsformatchingTheydotheexactsamethingastheexportedfunctionsInfactthoseexportedfunctionsactuallycallthesemethodsunderthehood

func(reRegexp)Match(b[]byte)bool

func(reRegexp)MatchReader(rioRuneReader)bool

func(reRegexp)MatchString(sstring)bool

NextletsseehowtoreplacestringsusingRegexp

Regexp

165

func(reRegexp)ReplaceAll(srcrepl[]byte)[]byte

func(reRegexp)ReplaceAllFunc(src[]bytereplfunc([]byte)[]byte)[]byte

func(reRegexp)ReplaceAllLiteral(srcrepl[]byte)[]byte

func(reRegexp)ReplaceAllLiteralString(srcreplstring)string

func(reRegexp)ReplaceAllString(srcreplstring)string

func(reRegexp)ReplaceAllStringFunc(srcstringreplfunc(string)string)string

Theseareusedinthecrawlingexamplesowewillnotexplainanyfurtherhere

LetstakealookatthedefinitionofExpand

func(reRegexp)Expand(dst[]bytetemplate[]bytesrc[]bytematch[]int)[]byte

func(reRegexp)ExpandString(dst[]bytetemplatestringsrcstringmatch[]int)[]byte

SohowdoweuseExpand

funcmain()

src=[]byte(`

callhelloalice

hellobob

callhelloeve

`)

pat=regexpMustCompile(`(m)(call)s+(Pltcmdgtw+)s+(Pltarggt+)s$`)

res=[]byte

for_s=rangepatFindAllSubmatchIndex(src-1)

res=patExpand(res[]byte($cmd($arg)n)srcs)

fmtPrintln(string(res))

AtthispointyouvelearntthewholeregexppackageinGoIhopethatyoucanunderstandmorebystudyingexamplesofkeymethodssothatyoucandosomethinginterestingonyourown

LinksDirectoryPrevioussectionJSONNextsectionTemplates

Regexp

166

74Templates

WhatisatemplateHopefullyyoureawareoftheMVC(ModelViewController)designmodelwheremodelsprocessdataviewsshowtheresultsandfinallycontrollershandleuserrequestsForviewsmanydynamiclanguagesgeneratedatabywritingcodeinstaticHTMLfilesForinstanceJSPisimplementedbyinsertinglt==gtPHPbyinsertingltphpgtetc

Thefollowingdemonstratesthetemplatemechanism

Figure71Templatemechanism

MostofthecontentthatwebapplicationsrespondtoclientswithisstaticandthedynamicpartsareusuallyverysmallForexampleifyouneedtodisplayalistuserswhohavevisitedapageonlytheusernamewouldbedynamicThestyleofthelistremainsthesameAsyoucanseetemplatesareusefulforreusingstaticcontent

TemplatinginGoInGowehavethetemplatepackagetohelphandletemplatesWecanusefunctionslikeParseParseFileandExecutetoloadtemplatesfromplaintextorfilesthenevaluatethedynamicpartsasshowninfigure71

Example

funchandler(whttpResponseWriterrhttpRequest)

t=templateNew(sometemplate)Createatemplate

t_=tParseFiles(tmplwelcomehtmlnil)Parsetemplatefile

user=GetUser()Getcurrentuserinfomration

tExecute(wuser)merge

AsyoucanseeitsveryeasytouseloadandrenderdataintemplatesinGojustasinotherprogramminglanguages

Forthesakeofconveniencewewillusethefollowingrulesinourexamples

UseParsetoreplaceParseFilesbecauseParsecantestcontentdirectlyfromstringssowedontneedanyextrafilesUsemainforeveryexampleanddonotusehandlerUseosStdouttoreplacehttpResponseWritersinceosStdoutalsoimplementstheioWriterinterface

InsertingdataintoatemplateWevejustshownyouhowtoparseandrendertemplatesLetstakeitonestepfurtherandrenderdatatoourtemplatesEverytemplateisanobjectinGosohowdoweinsertfieldstotemplates

Fields

InGoEveryfieldthatyouintendtoberenderedwithinatemplateshouldbeputinsideofisshorthandforthecurrentobjectwhichissimilartoitsJavaorC++counterpartIfyouwanttoaccessthefieldsofthecurrentobjectyoushoulduseFieldNameNoticethatonlyexportedfieldscanbeaccessedintemplatesHereisanexample

Templates

167

packagemain

import(

htmltemplate

os

)

typePersonstruct

UserNamestring

funcmain()

t=templateNew(fieldnameexample)

t_=tParse(helloUserName)

p=PersonUserNameAstaxie

tExecute(osStdoutp)

TheaboveexampleoutputshelloAstaxiecorrectlybutifwemodifyourstructalittlebitthefollowingerroremerges

typePersonstruct

UserNamestring

emailstringFieldisnotexported

t_=tParse(helloUserNameemail)

ThispartofthecodewillnotbecompiledbecausewetrytoaccessafieldthathasnotbeenexportedHoweverifwetrytouseafieldthatdoesnotexistGosimplyoutputsanemptystringinsteadofanerror

IfyouprintinatemplateGooutputsaformattedstringofthisobjectcallingfmtunderthecovers

Nestedfields

WeknowhowtooutputafieldnowWhatifthefieldisanobjectanditalsohasitsownfieldsHowdoweprintthemallinoneloopWecanusewithhelliphellipendandrangehellipendforexactlythatpurpose

rangejustlikerangeinGowithletsyouwritethesameobjectnameonceanduseasshorthandforit(SimilartowithinVB)

Moreexamples

Templates

168

packagemain

import(

htmltemplate

os

)

typeFriendstruct

Fnamestring

typePersonstruct

UserNamestring

Emails[]string

Friends[]Friend

funcmain()

f1=FriendFnameminuxma

f2=FriendFnamexushiwei

t=templateNew(fieldnameexample)

t_=tParse(`helloUserName

rangeEmails

anemail

end

withFriends

range

myfriendnameisFname

end

end

`)

p=PersonUserNameAstaxie

Emails[]stringastaxiebeegomeastaxiegmailcom

Friends[]Friendampf1ampf2

tExecute(osStdoutp)

ConditionsIfyouneedtocheckforconditionsintemplatesyoucanusetheif-elsesyntaxjustlikeyoudoinregularGoprogramsIfthepipelineisemptythedefaultvalueofifisfalseThefollowingexampleshowshowtouseif-elseintemplates

packagemain

import(

os

texttemplate

)

funcmain()

tEmpty=templateNew(templatetest)

tEmpty=templateMust(tEmptyParse(Emptypipelineifdemoif``willnotbeoutputtedendn))

tEmptyExecute(osStdoutnil)

tWithValue=templateNew(templatetest)

tWithValue=templateMust(tWithValueParse(Notemptypipelineifdemoif`anything`willbeoutputtede

ndn))

tWithValueExecute(osStdoutnil)

tIfElse=templateNew(templatetest)

tIfElse=templateMust(tIfElseParse(if-elsedemoif`anything`ifpartelseelsepartendn))

tIfElseExecute(osStdoutnil)

Asyoucanseeitseasytouseif-elseintemplates

Templates

169

AttentionYouCANNOTuseconditionalexpressionsinifforinstanceMail==astaxiegmailcomOnlybooleanvaluesareacceptable

pipelines

Unixusersshouldbefamiliarwiththepipeoperatorlikels|grepbeegoThiscommandfiltersfilesandonlyshowsthosethatcontainthewordbeegoOnethingthatIlikeaboutGotemplatesisthattheysupportpipesAnythingincanbethedataofpipelinesThee-mailweusedabovecanrenderourapplicationvulnerabletoXSSattacksHowcanweaddressthisissueusingpipes

|html

Wecanusethismethodtoescapethee-mailbodytoHTMLItsquitesimilartowritingaUnixcommandanditisconvenientforuseintemplatefunctions

TemplatevariablesSometimesweneedtouselocalvariablesintemplatesWecanusethemwiththewithrangeandifkeywordsandtheirscopeisbetweenthesekeywordsandendHeresanexampleofdeclaringaglobalvariable

$variable=pipeline

Moreexamples

with$x=output|printfq$xend

with$x=outputprintfq$xend

with$x=output$x|printfqend

Templatefunctions

GousesthefmtpackagetoformatoutputintemplatesbutsometimesweneedtodosomethingelseForexampleconsiderthefollowingscenarioletssaywewanttoreplacewithatinoure-mailaddresslikeastaxieatbeegomeAtthispointwehavetowriteacustomizedfunction

EverytemplatefunctionhasauniquenameandisassociatedwithonefunctioninyourGoprogramasfollows

typeFuncMapmap[string]interface

SupposewehaveanemailDealtemplatefunctionassociatedwithitsEmailDealWithcounterpartfunctioninourGoprogramWecanusethefollowingcodetoregisterthisfunction

t=tFuncs(templateFuncMapemailDealEmailDealWith)

EmailDealWithdefinition

funcEmailDealWith(argshellipinterface)string

Example

Templates

170

packagemain

import(

fmt

htmltemplate

os

strings

)

typeFriendstruct

Fnamestring

typePersonstruct

UserNamestring

Emails[]string

Friends[]Friend

funcEmailDealWith(argsinterface)string

ok=false

varsstring

iflen(args)==1

sok=args[0](string)

ifok

s=fmtSprint(args)

findthesymbol

substrs=stringsSplit(s)

iflen(substrs)=2

returns

replacethebyat

return(substrs[0]+at+substrs[1])

funcmain()

f1=FriendFnameminuxma

f2=FriendFnamexushiwei

t=templateNew(fieldnameexample)

t=tFuncs(templateFuncMapemailDealEmailDealWith)

t_=tParse(`helloUserName

rangeEmails

anemails|emailDeal

end

withFriends

range

myfriendnameisFname

end

end

`)

p=PersonUserNameAstaxie

Emails[]stringastaxiebeegomeastaxiegmailcom

Friends[]Friendampf1ampf2

tExecute(osStdoutp)

Hereisalistofbuilt-intemplatefunctions

Templates

171

varbuiltins=FuncMap

andand

callcall

htmlHTMLEscaper

indexindex

jsJSEscaper

lenlength

notnot

oror

printfmtSprint

printffmtSprintf

printlnfmtSprintln

urlqueryURLQueryEscaper

MustThetemplatepackagehasafunctioncalledMustwhichisforvalidatingtemplateslikethematchingofbracescommentsandvariablesLetstakealookatanexampleofMust

packagemain

import(

fmt

texttemplate

)

funcmain()

tOk=templateNew(first)

templateMust(tOkParse(somestatictextandacomment))

fmtPrintln(ThefirstoneparsedOK)

templateMust(templateNew(second)Parse(somestatictextName))

fmtPrintln(ThesecondoneparsedOK)

fmtPrintln(Thenextoneoughttofail)

tErr=templateNew(checkparseerrorwithMust)

templateMust(tErrParse(somestatictextName))

Output

ThefirstoneparsedOK

ThesecondoneparsedOK

Thenextoneoughttofail

panictemplatecheckparseerrorwithMust1unexpectedincommand

NestedtemplatesJustlikeinmostwebapplicationscertainpartsoftemplatescanbereusedacrossothertemplatesliketheheadersandfootersofablogWecandeclareheadercontentandfooterassub-templatesanddeclaretheminGousingthefollowingsyntax

definesub-templatecontentend

Thesub-templateiscalledusingthefollowingsyntax

templatesub-template

Templates

172

Heresacompleteexamplesupposingthatwehavethefollowingthreefilesheadertmplcontenttmplandfootertmplinthefoldertemplateswewillreadthefolderandstorethefilenamesinastringarraywhichwewillthenusetoparsefiles

Maintemplate

raw

headertmpl

defineheader

lthtmlgt

ltheadgt

lttitlegtSomethingherelttitlegt

ltheadgt

ltbodygt

end

contenttmpl

definecontent

templateheader

lth1gtNestedherelth1gt

ltulgt

ltligtNestedusagltligt

ltligtCalltemplateltligt

ltulgt

templatefooter

end

footertmpl

definefooter

ltbodygt

lthtmlgt

end

Whenusingsubtemplatingmakesurethatyouhaveparsedeachsubtemplatefile

otherwisethecompilerwouldntunderstandwhattosubstitutewhenitreadsthetemplateheader

endraw

Code

Templates

173

packagemain

import(

fmt

os

ioioutil

texttemplate

)

vartemplatestemplateTemplate

funcmain()

varallFiles[]string

fileserr=ioutilReadDir(templates)

iferr=nil

fmtPrintln(err)

for_file=rangefiles

filename=fileName()

ifstringsHasSuffix(filenametmpl)

allFiles=append(allFilestemplates+filename)

templateserr=templateParseFiles(allFiles)parsesalltmplfilesinthetemplatesfolder

s1=templatesLookup(headertmpl)

s1ExecuteTemplate(osStdoutheadernil)

fmtPrintln()

s2=templatesLookup(contenttmpl)

s2ExecuteTemplate(osStdoutcontentnil)

fmtPrintln()

s3=templatesLookup(footertmpl)

s3ExecuteTemplate(osStdoutfooternil)

fmtPrintln()

s3Execute(osStdoutnil)

HerewecanseethattemplateParseFilesparsesallnestedtemplatesintocacheandthateverytemplatedefinedbydefineareindependentofeachotherTheyarepersistedinsomethinglikeamapwherethetemplatenamesarekeysandthevaluesarethetemplatebodiesWecanthenuseExecuteTemplatetoexecutethecorrespondingsub-templatessothattheheaderandfooterareindependentandcontentcontainsthembothNotethatifwetrytoexecutes1Executenothingwillbeoutputtedbecausethereisnodefaultsub-templateavailable

Whenyoudontwanttousedefinethenyoucanjustcreateatextfilewiththenameofthesubtemplateforinstance_headtmplisasubtemplatewhichyoulluseacrossyourprojectthencreatethisfileinthetemplatesfolderandusethenormalsyntaxLookupcacheisbasicallycreatedsothatyoudontreadthefileeverytimeyouservearequestbecauseifyoudothenyouarewastingalotofresourcesforreadingafilewhichwontchangeunlessthecodebaseisbeingrewrittenitdoesntmakesensetoparsethetemplatefilesduringeachHTTPGETrequestsothetechniqueisusedwhereweparsethefilesonceandthendoaLookup()onthecachetoexecutethetemplatewhenweneedittodisplaydata

Templatesinonesetknoweachotherbutyoumustparsethemforeverysingleset

Sometimesyouwanttocontextualizetemplatesforinstanceyouhavea_headhtmlyoumighthaveaheaderwhosvalueyouhavetopopulatebasedonwhichdatayouareloadingforinstanceforatodolistmanageryoucanhavethreecategoriespendingcompleteddeletedforthissupposeyouhaveanifstatementlikethis

lttitlegtifeqNavigationpendingTasks

elseifeqNavigationcompletedCompleted

elseifeqNavigationdeletedDeleted

elseifeqNavigationeditEdit

end

lttitlegt

Templates

174

NoteGotemplatesfollowthePolishnotationwhileperformingthecomparisonwhereyougivetheoperatorfirstandthecomparisonvalueandthevaluetobecomparedwithTheelseifpartisprettystraightforward

Typicallyweusearangeoperatortoloopthroughthecontextvariablewhichwepasstothetemplatewhileexecutionlikethis

presentinviewspackage

context=dbGetTasks(pending)truewhenyouwantnondeletednotes

homeTemplateExecute(wcontext)

Wegetthecontextobjectfromthedatabaseasastructobjectthedefinitionisasbelow

Taskisthestructusedtoidentifytasks

typeTaskstruct

Idint

Titlestring

Contentstring

Createdstring

Contextisthestructpassedtotemplates

typeContextstruct

Tasks[]Task

Navigationstring

Searchstring

Messagestring

presentindatabasepackage

vartask[]typesTask

varcontexttypesContext

context=typesContextTaskstaskNavigationstatus

Thislineisinthedatabasepackagewherethecontextisreturnedbacktotheview

WeusethetaskarrayandtheNavigationinourtemplateswesawhowweusetheNavigationinthetemplatewellseehowwellusetheactualtaskarrayinourtemplate

HereintheifTaskswefirstcheckiftheTasksfieldofourcontextobjectwhichwepassedtothetemplatewhileexecutingisemptyornotIfitisnotemptythenwewillrangethroughthatarraytopopulatethetitleandcontentofTaskThebelowexampleisveryimportantwhenitcomestoloopingthroughanarrayinatemplatewestartwiththeRangeoperatorthenwecangiveanymemberofthatstructasNamemyTaskstructurehasaTitleandaContent(pleasenotethecapitalTandCtheyareexportednamesandtheyneedtobecapitalisedunlessyouwanttomakethemprivate)

rangeTasks

Title

Content

end

ThisblockofcodewillprinteachtitleandcontentoftheTaskarrayBelowisafullexamplefromgithubcomthewhitetulipTaskshomehtmltemplate

Templates

175

ltdivclass=timelinegt

ifTasksrangeTasks

ltdivclass=notegt

ltpclass=noteHeadinggtTitleltpgt

lthrgt

ltpclass=noteContentgtContentltpgt

ltulgt

ltspangt

ltdivgt

endelse

ltdivclass=notegt

ltpclass=noteHeadinggtNoTaskshereltpgt

ltpclass=notefootergt

Createnewtaskltbuttonclass=floating-action-icon-addgthereltbuttongtltpgt

ltdivgt

end

SummaryInthissectionyoulearnedhowtocombinedynamicdatawithtemplatesusingtechniquesincludingprintingdatainloopstemplatefunctionsandnestedtemplatesBylearningabouttemplateswecanconcludediscussingtheV(View)partoftheMVCarchitectureInthefollowingchapterswewillcovertheM(Model)andC(Controller)aspectsofMVC

LinksDirectoryPrevioussectionRegexpNextsectionFiles

Templates

176

75FilesFilesareessentialobjectsoneverysinglecomputerdeviceItwontcomeasanysurprisetoyouthatwebapplicationsalsomakeheavyuseofthemInthissectionweregoingtolearnhowtooperateonfilesinGo

DirectoriesInGomostofthefileoperationfunctionsarelocatedintheospackageHerearesomedirectoryfunctions

funcMkdir(namestringpermFileMode)error

Createadirectorywithnamepermisthedirectorypermissionsie0777

funcMkdirAll(pathstringpermFileMode)error

Createmultipledirectoriesaccordingtopathlikeastaxietest1test2

funcRemove(namestring)error

RemovesdirectorywithnameReturnserrorifitsnotadirectoryornotempty

funcRemoveAll(pathstring)error

RemovesmultipledirectoriesaccordingtopathDirectorieswillnotbedeletedifpathisasinglepath

Codesample

packagemain

import(

fmt

os

)

funcmain()

osMkdir(astaxie0777)

osMkdirAll(astaxietest1test20777)

err=osRemove(astaxie)

iferr=nil

fmtPrintln(err)

osRemoveAll(astaxie)

Files

Createandopenfiles

Therearetwofunctionsforcreatingfiles

funcCreate(namestring)(fileFileerrError)

Createafilewithnameandreturnaread-writablefileobjectwithpermission0666

funcNewFile(fduintptrnamestring)File

Createafileandreturnafileobject

Therearealsotwofunctionstoopenfiles

funcOpen(namestring)(fileFileerrError)

Files

177

Opensafilecallednamewithread-onlyaccesscallingOpenFileunderthecovers

funcOpenFile(namestringflagintpermuint32)(fileFileerrError)

Opensafilecallednameflagisopenmodelikeread-onlyread-writeetcpermarethefilepermissions

WritefilesFunctionsforwritingfiles

func(fileFile)Write(b[]byte)(ninterrError)

Writebytetypecontenttoafile

func(fileFile)WriteAt(b[]byteoffint64)(ninterrError)

Writebytetypecontenttoaspecificpositionofafile

func(fileFile)WriteString(sstring)(retinterrError)

Writeastringtoafile

Codesample

packagemain

import(

fmt

os

)

funcmain()

userFile=astaxietxt

fouterr=osCreate(userFile)

iferr=nil

fmtPrintln(userFileerr)

return

deferfoutClose()

fori=0ilt10i++

foutWriteString(Justatestrn)

foutWrite([]byte(Justatestrn))

ReadfilesFunctionsforreadingfiles

func(fileFile)Read(b[]byte)(ninterrError)

Readdatatob

func(fileFile)ReadAt(b[]byteoffint64)(ninterrError)

Readdatafrompositionofftob

Codesample

Files

178

packagemain

import(

fmt

os

)

funcmain()

userFile=asatxietxt

flerr=osOpen(userFile)

iferr=nil

fmtPrintln(userFileerr)

return

deferflClose()

buf=make([]byte1024)

for

n_=flRead(buf)

if0==n

break

osStdoutWrite(buf[n])

DeletefilesGousesthesamefunctionforremovingfilesanddirectories

funcRemove(namestring)Error

Removeafileordirectorycalledname(anameendingwithsignifiesthatitsadirectory)

LinksDirectoryPrevioussectionTemplatesNextsectionStrings

Files

179

76StringsOnthewebalmosteverythingwesee(includinguserinputsdatabaseaccessetc)isrepresentedbystringsTheyareaveryimportantpartofwebdevelopmentInmanycaseswealsoneedtosplitjoinconvertandotherwisemanipulatestringsInthissectionwearegoingtointroducethestringsandstrconvpackagesfromtheGostandardlibrary

stringsThefollowingfunctionsarefromthestringspackageSeetheofficialdocumentationformoredetails

funcContains(ssubstrstring)bool

Checkifstringscontainsstringsubstrreturnsabooleanvalue```GofmtPrintln(stringsContains(seafoodfoo))fmtPrintln(stringsContains(seafoodbar))fmtPrintln(stringsContains(seafood))fmtPrintln(stringsContains())

Outputtruefalsetruetrue

-funcJoin(a[]stringsepstring)string

Combinestringsfromslicewithseparator`sep`

```Go

s=[]stringfoobarbaz

fmtPrintln(stringsJoin(s))

Outputfoobarbaz

funcIndex(ssepstring)int

Findindexofsepinstringsreturns-1ifitsnotfound

fmtPrintln(stringsIndex(chickenken))

fmtPrintln(stringsIndex(chickendmr))

Output4

-1

funcRepeat(sstringcountint)string

Repeatstringscounttimes

fmtPrintln(ba+stringsRepeat(na2))

Outputbanana

funcReplace(soldnewstringnint)string

ReplacestringoldwithstringnewinstringsnisthenumberofreplacementsIfnislessthan0replaceallinstances

fmtPrintln(stringsReplace(oinkoinkoinkkky2))

fmtPrintln(stringsReplace(oinkoinkoinkoinkmoo-1))

Outputoinkyoinkyoink

moomoomoo

funcSplit(ssepstring)[]string

Splitstringswithseparatorsepintoaslice

Strings

180

fmtPrintf(qnstringsSplit(abc))

fmtPrintf(qnstringsSplit(amanaplanacanalpanamaa))

fmtPrintf(qnstringsSplit(xyz))

fmtPrintf(qnstringsSplit(BernardoOHiggins))

Output[abc]

[manplancanalpanama]

[xyz]

[]

funcTrim(sstringcutsetstring)string

Removecutsetofstringsifitsleftmostorrightmost

fmtPrintf([q]stringsTrim(Achtung))

Output[Achtung]

funcFields(sstring)[]string

Removespaceitemsandsplitstringwithspaceintoaslice

fmtPrintf(FieldsareqstringsFields(foobarbaz))

OutputFieldsare[foobarbaz]

strconvThefollowingfunctionsarefromthestrconvpackageAsusualpleaseseeofficialdocumentationformoredetails

Appendseriesconvertdatatostringandappendtocurrentbyteslice```Gopackagemain

import(fmtstrconv)

funcmain()str=make([]byte0100)str=strconvAppendInt(str456710)str=strconvAppendBool(strfalse)str=strconvAppendQuote(strabcdefg)str=strconvAppendQuoteRune(str单)fmtPrintln(string(str))

-Formatseriesconvertotherdatatypesintostring

```Go

packagemain

import(

fmt

strconv

)

funcmain()

a=strconvFormatBool(false)

b=strconvFormatFloat(12323g1264)

c=strconvFormatInt(123410)

d=strconvFormatUint(1234510)

e=strconvItoa(1023)

fmtPrintln(abcde)

Parseseriesconvertstringstoothertypes```Gopackagemain

import(fmtstrconv)

funcmain()aerr=strconvParseBool(false)iferr=nilfmtPrintln(err)berr=strconvParseFloat(1232364)iferr=nilfmtPrintln(err)cerr=strconvParseInt(12341064)iferr=nilfmtPrintln(err)derr=strconvParseUint(123451064)iferr=nilfmtPrintln(err)eerr=strconvItoa(1023)iferr=nilfmtPrintln(err)fmtPrintln(abcde)```

Strings

181

LinksDirectoryPrevioussectionFilesNextsectionSummary

Strings

182

77SummaryInthischapterweintroducedsometextprocessingtoolslikeXMLJSONRegexpandwealsotalkedabouttemplatesXMLandJSONaredataexchangetoolsYoucanrepresentalmostanykindofinformationusingthesetwoformatsRegexpisapowerfultoolforsearchingreplacingandcuttingtextcontentWithtemplatesyoucaneasilycombinedynamicdatawithstaticfilesThesetoolsareallusefulwhendevelopingwebapplicationsIhopethatyounowhaveabetterunderstandingofprocessinganddisplayingcontentusingGo

LinksDirectoryPrevioussectionStringsNextchapterWebservices

Summary

183

8WebservicesWebservicesallowyouuseformatslikeXMLorJSONtoexchangeinformationthroughHTTPForexampleifyouwanttoknowtheweatherinShanghaitomorrowthecurrentsharepriceofAppleorproductinformationonAmazonyoucanwriteapieceofcodetofetchthatinformationfromopenplatformsInGothisprocesscanbecomparabletocallingalocalfunctionandgettingitsreturnvalue

ThekeypointisthatwebservicesareplatformindependentThisallowsyoutodeployyourapplicationsonLinuxandinteractwithASPNETapplicationsinWindowsforexamplejustlikeyouwouldnthaveaprobleminteractingwithJSPonFreeBSDeither

TheRESTarchitectureandSOAPprotocolarethemostpopularstylesinwhichwebservicescanbeimplementedthesedays

RESTrequestsareprettystraightforwardbecauseitsbasedonHTTPEveryRESTrequestisactuallyanHTTPrequestandservershandlerequestsusingdifferentmethodsBecausemanydevelopersarefamiliarwithHTTPalreadyRESTshouldfeellikeitsalreadyintheirbackpocketsWearegoingtoshowyouhowtoimplementRESTinGoinsection83SOAPisastandardforcross-networkinformationtransmissionandremotecomputerfunctioncallslaunchedbyW3CTheproblemwithSOAPisthatitsspecificationisverylongandcomplicatedanditsstillgettinglongerGobelievesthatthingsshouldbesimplesowerenotgoingtotalkaboutSOAPFortunatelyGoprovidessupportforRPC(RemoteProcedureCalls)whichhasgoodperformanceandiseasytodevelopwithsowewillintroducehowtoimplementRPCinGoinsection84

GoistheClanguageofthe21stcenturyaspiringtobesimpleyetperformantWiththesequalitiesinmindwellintroduceyoutosocketprogramminginGoinsection81Nowadaysmanyreal-timeserversusesocketstoovercomethelowperformanceofHTTPAlongwiththerapiddevelopmentofHTML5websocketsarenowusedbymanywebbasedgamecompaniesandwewilltalkaboutthismoreinsection82

LinksDirectoryPreviousChapterChapter7SummaryNextsectionSockets

Webservices

184

81SocketsSomenetworkapplicationdeveloperssaythatthelowerapplicationlayersareallaboutsocketprogrammingThismaynotbetrueforallcasesbutmanymodernwebapplicationsdoindeedusesocketstotheiradvantageHaveyoueverwonderedhowbrowserscommunicatewithwebserverswhenyouaresurfingtheinternetOrHowMSNconnectsyouandyourfriendstogetherinachatroomrelayingeachmessageinreal-timeManyservicesliketheseusesocketstotransferdataAsyoucanseesocketsoccupyanimportantpositioninnetworkprogrammingtodayandweregoingtolearnaboutusingsocketsinGointhissection

WhatisasocketSocketsoriginatefromUnixandgiventhebasiceverythingisafilephilosophyofUnixeverythingcanbeoperatedonwithopen-gtwriteread-gtcloseSocketsareoneimplementationofthisphilosophySocketshaveafunctioncallforopeningasocketjustlikeyouwouldopenafileThisreturnsanintdescriptorofthesocketwhichcanthenbeusedforoperationslikecreatingconnectionstransferringdataetc

Twotypesofsocketsthatarecommonlyusedarestreamsockets(SOCK_STREAM)anddatagramsockets(SOCK_DGRAM)Streamsocketsareconnection-orientedlikeTCPwhiledatagramsocketsdonotestablishconnectionslikeUDP

SocketcommunicationBeforeweunderstandhowsocketscommunicatewithoneanotherweneedtofigureouthowtomakesurethateverysocketisuniqueotherwiseestablishingareliablecommunicationchannelisalreadyoutofthequestionWecangiveeveryprocessauniquePIDwhichservesourpurposelocallyhoweverthatsnotabletoworkoveranetworkFortunatelyTCPIPhelpsussolvethisproblemTheIPaddressesofthenetworklayerareuniqueinanetworkofhostsandprotocol+portisalsouniqueamonghostapplicationsSowecanusetheseprinciplestomakesocketswhichareunique

Figure81networkprotocollayers

ApplicationsthatarebasedonTCPIPallusesocketAPIsintheircodeinonewayoranotherGiventhatnetworkedapplicationsarebecomingmoreandmoreprevalentinthemoderndayitsnowondersomedevelopersaresayingthateverythingisaboutsockets

SocketbasicknowledgeWeknowthatsocketshavetwotypeswhichareTCPsocketsandUDPsocketsTCPandUDPareprotocolsandasmentionedwealsoneedanIPaddressandportnumbertohaveauniquesocket

IPv4TheglobalinternetusesTCPIPasitsprotocolwhereIPisthenetworklayerandacorepartofTCPIPIPv4signifiesthatitsversionis4infrastructuredevelopmenttodatehasspannedover30years

ThenumberofbitsinanIPv4addressis32whichmeansthat2^32devicesareabletouniquelyconnecttotheinternetDuetotherapiddevelopoftheinternetIPaddressesarealreadyrunningoutofstockinrecentyears

Addressformat127001172122121111

IPv6

Sockets

185

IPv6isthenextversionornextgenerationoftheinternetItsbeingdevelopedforsolvingmanyoftheproblemsinherentwithIPv4DevicesusingIPv6haveanaddressthats128bitslongsowellneverneedtoworryaboutashortageofuniqueaddressesToputthisintoperspectiveyoucouldhavemorethan1000IPaddressesforeverysquaremeteronearthwithIPv6Otherproblemslikepeertopeerconnectionservicequality(QoS)securitymultiplebroadcastetcarealsobeimproved

Addressformat2002c0e882e7000c0e882e7

IPtypesinGo

ThenetpackageinGoprovidesmanytypesfunctionsandmethodsfornetworkprogrammingThedefinitionofIPasfollows

typeIP[]byte

FunctionParseIP(sstring)IPistoconverttheIPv4orIPv6formattoanIP

packagemain

import(

net

os

fmt

)

funcmain()

iflen(osArgs)=2

fmtFprintf(osStderrUsagesip-addrnosArgs[0])

osExit(1)

name=osArgs[1]

addr=netParseIP(name)

ifaddr==nil

fmtPrintln(Invalidaddress)

else

fmtPrintln(TheaddressisaddrString())

osExit(0)

ItreturnsthecorrespondingIPformatforagivenIPaddress

TCPsocketWhatcanwedowhenweknowhowtovisitawebservicethroughanetworkportAsaclientwecansendarequesttoanappointednetworkportandgetsitsresponseasaserverweneedtobindaservicetoanappointednetworkportwaitforclientsrequestsandsupplyaresponse

InGosnetpackagetheresatypecalledTCPConnthatfacilitatesthiskindofclientsserversinteractionThistypehastwokeyfunctions

func(cTCPConn)Write(b[]byte)(ninterrosError)

func(cTCPConn)Read(b[]byte)(ninterrosError)

TCPConncanbeusedbyeitherclientorserverforreadingandwritingdata

WealsoneedaTCPAddrtorepresentTCPaddressinformation

Sockets

186

typeTCPAddrstruct

IPIP

Portint

WeusetheResolveTCPAddrfunctiontogetaTCPAddrinGo

funcResolveTCPAddr(netaddrstring)(TCPAddrosError)

Argumentsofnetcanbeoneoftcp4tcp6ortcpwhicheachsignifyIPv4-onlyIPv6-onlyandeitherIPv4orIPv6respectivelyaddrcanbeadomainnameorIPaddresslikewwwgooglecom80or12700122

TCPclientGoclientsusetheDialTCPfunctioninthenetpackagetocreateaTCPconnectionwhichreturnsaTCPConnobjectafteraconnectionisestablishedtheserverhasthesametypeofconnectionobjectforthecurrentconnectionandclientandservercanbeginexchangingdatawithoneanotherIngeneralclientssendrequeststoserversthroughaTCPConnandreceiveinformationfromtheserverresponseserversreadandparseclientrequeststhenreturnfeedbackThisconnectionwillremainvaliduntileithertheclientorserverclosesitThefunctionforcreatingaconnectionisasfollows

funcDialTCP(netstringladdrraddrTCPAddr)(cTCPConnerrosError)

Argumentsofnetcanbeoneoftcp4tcp6ortcpwhicheachsignifyIPv4-onlyIPv6-onlyandeitherIPv4orIPv6respectivelyladdrrepresentsthelocaladdresssetittonilinmostcasesraddrrepresentstheremoteaddress

LetswriteasimpleexampletosimulateaclientrequestingaconnectiontoaserverbasedonanHTTPrequestWeneedasimpleHTTPrequestheader

HEADHTTP10rnrn

Serverresponseinformationformatmaylooklikethefollowing

HTTP10200OK

ETag-9985996

Last-ModifiedThu25Mar2010175110GMT

Content-Length18074

Connectionclose

DateSat28Aug2010004348GMT

Serverlighttpd1423

Clientcode

Sockets

187

packagemain

import(

fmt

ioioutil

net

os

)

funcmain()

iflen(osArgs)=2

fmtFprintf(osStderrUsageshostportosArgs[0])

osExit(1)

service=osArgs[1]

tcpAddrerr=netResolveTCPAddr(tcp4service)

checkError(err)

connerr=netDialTCP(tcpniltcpAddr)

checkError(err)

_err=connWrite([]byte(HEADHTTP10rnrn))

checkError(err)

resulterr=ioutilReadAll(conn)

checkError(err)

fmtPrintln(string(result))

osExit(0)

funccheckError(errerror)

iferr=nil

fmtFprintf(osStderrFatalerrorserrError())

osExit(1)

IntheaboveexampleweuseuserinputastheserviceargumentofnetResolveTCPAddrtogetatcpAddrPassingtcpAddrtotheDialTCPfunctionwecreateaTCPconnectionconnWecanthenuseconntosendrequestinformationtotheserverFinallyweuseioutilReadAlltoreadallthecontentfromconnwhichcontainstheserverresponse

TCPserver

WehaveaTCPclientnowWecanalsousethenetpackagetowriteaTCPserverOntheserversideweneedtobindourservicetoaspecificinactiveportandlistenforanyincomingclientrequests

funcListenTCP(netstringladdrTCPAddr)(lTCPListenererrosError)

func(lTCPListener)Accept()(cConnerrosError)

TheargumentsrequiredhereareidenticaltothoserequiredbytheDialTCPfunctionweusedearlierLetsimplementatimesyncingserviceusingport7777

Sockets

188

packagemain

import(

fmt

net

os

time

)

funcmain()

service=7777

tcpAddrerr=netResolveTCPAddr(tcp4service)

checkError(err)

listenererr=netListenTCP(tcptcpAddr)

checkError(err)

for

connerr=listenerAccept()

iferr=nil

continue

daytime=timeNow()String()

connWrite([]byte(daytime))dontcareaboutreturnvalue

connClose()werefinishedwiththisclient

funccheckError(errerror)

iferr=nil

fmtFprintf(osStderrFatalerrorserrError())

osExit(1)

AftertheserviceisstarteditwaitsforclientrequestsWhenitreceivesaclientrequestitAcceptsitandreturnsaresponsetotheclientcontaininginformationaboutthecurrenttimeItsworthnotingthatwhenerrorsoccurintheforlooptheservicecontinuesrunninginsteadofexitingInsteadofcrashingtheserverwillrecordtheerrortoaservererrorlog

TheabovecodeisstillnotgoodenoughhoweverWedidntmakeuseofgoroutineswhichwouldhaveallowedustoacceptsimultaneousrequestsLetsdothisnow

Sockets

189

packagemain

import(

fmt

net

os

time

)

funcmain()

service=1200

tcpAddrerr=netResolveTCPAddr(tcp4service)

checkError(err)

listenererr=netListenTCP(tcptcpAddr)

checkError(err)

for

connerr=listenerAccept()

iferr=nil

continue

gohandleClient(conn)

funchandleClient(connnetConn)

deferconnClose()

daytime=timeNow()String()

connWrite([]byte(daytime))dontcareaboutreturnvalue

werefinishedwiththisclient

funccheckError(errerror)

iferr=nil

fmtFprintf(osStderrFatalerrorserrError())

osExit(1)

ByseparatingoutourbusinessprocessfromthehandleClientfunctionandbyusingthegokeywordwevealreadyimplementedconcurrencyinourserviceThisisagooddemonstrationofthepowerandsimplicityofgoroutines

SomeofyoumaybethinkingthefollowingthisserverdoesnotdoanythingmeaningfulWhatifweneededtosendmultiplerequestsfordifferenttimeformatsoverasingleconnectionHowwouldwedothat

Sockets

190

packagemain

import(

fmt

net

os

time

strconv

)

funcmain()

service=1200

tcpAddrerr=netResolveTCPAddr(tcp4service)

checkError(err)

listenererr=netListenTCP(tcptcpAddr)

checkError(err)

for

connerr=listenerAccept()

iferr=nil

continue

gohandleClient(conn)

funchandleClient(connnetConn)

connSetReadDeadline(timeNow()Add(2timeMinute))set2minutestimeout

request=make([]byte128)setmaximumrequestlengthto128Btopreventfloodbasedattacks

deferconnClose()closeconnectionbeforeexit

for

read_lenerr=connRead(request)

iferr=nil

fmtPrintln(err)

break

ifread_len==0

breakconnectionalreadyclosedbyclient

elseifstring(request[read_len])==timestamp

daytime=strconvFormatInt(timeNow()Unix()10)

connWrite([]byte(daytime))

else

daytime=timeNow()String()

connWrite([]byte(daytime))

funccheckError(errerror)

iferr=nil

fmtFprintf(osStderrFatalerrorserrError())

osExit(1)

InthisexampleweuseconnRead()toconstantlyreadclientrequestsWecannotclosetheconnectionbecauseclientsmayissuemorethanonerequestDuetothetimeoutwesetusingconnSetReadDeadline()theconnectionclosesautomaticallyafterourallottedtimeperiodWhentheexpirytimehaselapsedourprogrambreaksfromtheforloopNoticethatrequestneedstobecreatedwithamaxsizelimitationinordertopreventfloodattacks

ControllingTCPconnections

ControllingTCPfunctions

funcDialTimeout(netaddrstringtimeouttimeDuration)(Connerror)

Sockets

191

SettingthetimeoutofconnectionsThesearesuitableforuseonbothclientsandservers

func(cTCPConn)SetReadDeadline(ttimeTime)error

func(cTCPConn)SetWriteDeadline(ttimeTime)error

Settingthewritereadtimeoutofoneconnection

func(cTCPConn)SetKeepAlive(keepalivebool)osError

ItsworthtakingsometimetothinkabouthowlongyouwantyourconnectiontimeoutstobeLongconnectionscanreducetheamountofoverheadinvolvedincreatingconnectionsandaregoodforapplicationsthatneedtoexchangedatafrequently

FormoredetailedinformationjustlookuptheofficialdocumentationforGosnetpackage

UDPsocketsTheonlydifferencebetweenaUDPsocketandaTCPsocketistheprocessingmethodfordealingwithmultiplerequestsonserversideThisarisesfromthefactthatUDPdoesnothaveafunctionlikeAcceptAlloftheotherfunctionshaveUDPcounterpartsjustreplaceTCPwithUDPinthefunctionsmentionedabove

funcResolveUDPAddr(netaddrstring)(UDPAddrosError)

funcDialUDP(netstringladdrraddrUDPAddr)(cUDPConnerrosError)

funcListenUDP(netstringladdrUDPAddr)(cUDPConnerrosError)

func(cUDPConn)ReadFromUDP(b[]byte)(nintaddrUDPAddrerrosError

func(cUDPConn)WriteToUDP(b[]byteaddrUDPAddr)(ninterrosError)

UDPclientcodesample

packagemain

import(

fmt

net

os

)

funcmain()

iflen(osArgs)=2

fmtFprintf(osStderrUsageshostportosArgs[0])

osExit(1)

service=osArgs[1]

udpAddrerr=netResolveUDPAddr(udp4service)

checkError(err)

connerr=netDialUDP(udpniludpAddr)

checkError(err)

_err=connWrite([]byte(anything))

checkError(err)

varbuf[512]byte

nerr=connRead(buf[0])

checkError(err)

fmtPrintln(string(buf[0n]))

osExit(0)

funccheckError(errerror)

iferr=nil

fmtFprintf(osStderrFatalerrorerrError())

osExit(1)

Sockets

192

UDPservercodesample

packagemain

import(

fmt

net

os

time

)

funcmain()

service=1200

udpAddrerr=netResolveUDPAddr(udp4service)

checkError(err)

connerr=netListenUDP(udpudpAddr)

checkError(err)

for

handleClient(conn)

funchandleClient(connnetUDPConn)

varbuf[512]byte

_addrerr=connReadFromUDP(buf[0])

iferr=nil

return

daytime=timeNow()String()

connWriteToUDP([]byte(daytime)addr)

funccheckError(errerror)

iferr=nil

fmtFprintf(osStderrFatalerrorerrError())

osExit(1)

SummaryThroughdescribingandcodingsomesimpleprogramsusingTCPandUDPsocketswecanseethatGoprovidesexcellentsupportforsocketprogrammingandthattheyarefunandeasytouseGoalsoprovidesmanyfunctionsforbuildinghighperformancesocketapplications

LinksDirectoryPrevioussectionWebservicesNextsectionWebSocket

Sockets

193

82WebSocketsWebSocketsareanimportantfeatureofHTML5Itimplementsbrowserbasedremotesocketswhichallowsbrowserstohavefull-duplexcommunicationswithserversMainstreambrowserslikeFirefoxGoogleChromeandSafariprovidesupportforthisWebSockets

PeopleoftenusedrollpollingforinstantmessagingservicesbeforeWebSocketswerebornwhichallowclientstosendHTTPrequestsperiodicallyTheserverthenreturnsthelatestdatatoclientsThedownsidetothismethodisthatitrequiresclientstokeepsendingmanyrequeststotheserverwhichcanconsumealargeamountofbandwidth

WebSocketsuseaspecialkindofheaderthatreducesthenumberofhandshakesrequiredbetweenbrowserandservertoonlyoneforestablishingaconnectionThisconnectionwillremainactivethroughoutitslifetimeandyoucanuseJavaScripttowriteorreaddatafromthisconnectionasinthecaseofaconventionalTCPsocketsItsolvesmanyoftheheadacheinvolvedwithreal-timewebdevelopmentandhasthefollowingadvantagesovertraditionalHTTP

OnlyoneTCPconnectionforasinglewebclientWebSocketserverscanpushdatatowebclientsLightweightheadertoreducedatatransmissionoverhead

WebSocketURLsbeginwithwsorwss(SSL)ThefollowingfigureshowsthecommunicationprocessofWebSocketsAparticularHTTPheaderissenttotheserveraspartofthehandshakingprotocolandtheconnectionisestablishedThenserversorclientsareabletosendorreceivedatathroughJavaScriptviaWebSocketThissocketcanthenbeusedbyaneventhandlertoreceivedataasynchronously

Figure82WebSocketprinciple

WebSocketprinciplesTheWebSocketprotocolisactuallyquitesimpleAftersuccessfullycompletingtheinitialhandshakeaconnectionisestablishedSubsequentdatacommunicationswillallbeginwithx00andendwithxFFThisprefixandsuffixwillbevisibletoclientsbecausetheWebSocketwillbreakoffbothendyieldingtherawdataautomatically

WebSocketconnectionsarerequestedbybrowsersandrespondedtobyserversafterwhichtheconnectionisestablishedThisprocessisoftencalledhandshaking

Considerthefollowingrequestsandresponses

Figure83WebSocketrequestandresponse

Sec-WebSocket-keyisgeneratedrandomlyasyoumayhavealreadyguessedanditsbase64encodedServersneedtoappendthiskeytoafixedstringafteracceptingarequest

258EAFA5-E914-47DA-95CA-C5AB0DC85B11

Supposewehavef7cb4ezEAl6C3wRaU6JORA==thenwehave

f7cb4ezEAl6C3wRaU6JORA==258EAFA5-E914-47DA-95CA-C5AB0DC85B11

Usesha1tocomputethebinaryvalueandusebase64toencodeitWewillthenwehave

rE91AJhfC+6JdVcVXOGJEADEJdQ=

WebSocket

194

UsethisasthevalueoftheSec-WebSocket-Acceptresponseheader

WebSocketinGoTheGostandardlibrarydoesnotsupportWebSocketsHoweverthewebsocketpackagewhichisasub-packageofgonetdoesandisofficiallymaintainedandsupported

Usegogettoinstallthispackage

gogetgolangorgxnetwebsocket

WebSocketshavebothclientandserversidesLetsseeasimpleexamplewhereauserinputssomeinformationontheclientsideandsendsittotheserverthroughaWebSocketfollowedbytheserverpushinginformationbacktotheclient

Clientcode

lthtmlgt

ltheadgtltheadgt

ltbodygt

ltscripttype=textjavascriptgt

varsock=null

varwsuri=ws1270011234

windowonload=function()

consolelog(onload)

sock=newWebSocket(wsuri)

sockonopen=function()

consolelog(connectedto+wsuri)

sockonclose=function(e)

consolelog(connectionclosed(+ecode+))

sockonmessage=function(e)

consolelog(messagereceived+edata)

functionsend()

varmsg=documentgetElementById(message)value

socksend(msg)

ltscriptgt

lth1gtWebSocketEchoTestlth1gt

ltformgt

ltpgt

Messageltinputid=messagetype=textvalue=Helloworldgt

ltpgt

ltformgt

ltbuttononclick=send()gtSendMessageltbuttongt

ltbodygt

lthtmlgt

AsyoucanseeitsveryeasytousetheclientsideJavaScriptfunctionstoestablishaconnectionTheonopeneventgetstriggeredaftersuccessfullycompletingtheaforementionedhandshakingprocessIttellstheclientthattheconnectionhasbeencreatedsuccessfullyClientsattemptingtoopenaconnectiontypicallybindtofourevents

1)onopentriggeredafterconnectionhasbeenestablished2)onmessagetriggeredafterreceivingamessage3)onerrortriggeredafteranerrorhasoccurred

WebSocket

195

4)onclosetriggeredaftertheconnectionhasclosed

Servercode

packagemain

import(

golangorgxnetwebsocket

fmt

log

nethttp

)

funcEcho(wswebsocketConn)

varerrerror

for

varreplystring

iferr=websocketMessageReceive(wsampreply)err=nil

fmtPrintln(Cantreceive)

break

fmtPrintln(Receivedbackfromclient+reply)

msg=Received+reply

fmtPrintln(Sendingtoclient+msg)

iferr=websocketMessageSend(wsmsg)err=nil

fmtPrintln(Cantsend)

break

funcmain()

httpHandle(websocketHandler(Echo))

iferr=httpListenAndServe(1234nil)err=nil

logFatal(ListenAndServeerr)

WhenaclientSendsuserinputinformationtheserverReceivesitandusesSendonceagaintoreturnaresponse

Figure84WebSocketserverreceivedinformation

ThroughtheexampleabovewecanseethattheclientandserversideimplementationofWebSocketsisveryconvenientWecanusethenetpackagedirectlyinGoWiththerapiddevelopmentofHTML5IthinkthatWebSocketswilltakeonamuchmoreimportantroleinmoderndaywebdevelopmentweshouldallbeatleastalittlebitfamiliarwiththem

LinksDirectoryPrevioussectionSocketsNextsectionREST

WebSocket

196

83RESTRESTisthemostpopularsoftwarearchitectureontheinternettodaybecauseitisfoundedonwelldefinedstrictstandardsanditseasytounderstandandexpandMoreandmorewebsitesarebasingtheirdesignsontopofRESTInthissectionwearegoingtohaveacloselookatimplementingtheRESTarchitectureinGoand(hopefully)learnhowtoleverageittoourbenefit

WhatisRESTThefirstdeclarationoftheconceptofREST(REpresentationalStateTransfer)wasintheyear2000inRoyThomasFieldingsdoctoraldissertationwhoalsojusthappenstobetheco-founderoftheHTTPprotocolItspecifiesthearchitecturesconstraintsandprinciplesandanythingimplementedwiththisarchitecturecanbecalledaRESTfulsystem

BeforeweunderstandwhatRESTisweneedtocoverthefollowingconcepts

Resources

RESTisthePresentationLayerStateTransferwherethepresentationlayerisactuallytheresourcepresentatio

nlayer

SowhatareresourcesPicturesdocumentsorvideosetcareallexamplesofresourcesandcanbelocatedby

URI

Representation

ResourcesarespecificinformationentitiesthatcanbeshowninavarietyofwayswithinthepresentationlayerForinstanceaTXTdocumentcanberepresentedasHTMLJSONXMLetcanimagecanberepresentedasjpgpngetc

URIsareusedtoidentifyresourcesbuthowdowedetermineitsspecificmanifestationsYouarereferredtotheAcceptandContent-TypeinanHTTPrequestheaderthesetwofieldsdescribethepresentationlayer

StateTransfer

AninteractiveprocessisinitiatedbetweenclientandservereachtimeyouvisitanypageofawebsiteDuringthisprocesscertaindatarelatedtothecurrentpagestateneedtobesavedHoweveryoullrecallthatHTTPisastatelessprotocolItsobviousthatweneedtosavethisclientstateonourserversideItfollowsthatifaclientmodifiessomedataandwantstopersistthechangestheremustbeawaytoinformtheserversideaboutthenewstate

MostofthetimeclientsinformserversofstatechangesusingHTTPTheyhavefouroperationswithwhichtodothis

-GETisusedtoobtainresources-POSTsisusedtocreateorupdateresources-PUTupdatesresources-DELETEdeletesresources

Tosummarizetheabove

(1)EveryURIrepresentsaresource(2)Thereisarepresentationlayerfortransferringresourcesbetweenclientsandservers(3)ClientsusefourHTTPmethodstoimplementPresentationLayerStateTransferallowingthemtooperateonremoteresources

ThemostimportantprincipleofwebapplicationsthatimplementRESTisthattheinteractionbetweenclientsandserversarestatelesseveryrequestshouldencapsulatealloftherequiredinformationServersshouldbeabletorestartatanytimewithouttheclientsbeingnotifiedInadditionrequestscanberespondedbyanyserverofthesameservicewhichisidealforcloudcomputingLastlybecauseitsstatelessclientscancachedataforimprovingperformance

REST

197

AnotherimportantprincipleofRESTissystemdelaminationwhichmeansthatcomponentsinonelayerhavenowayofinteractingdirectlywithcomponentsinotherlayersThiscanlimitsystemcomplexityandencourageindependenceintheunderlyingcomponents

Figure85RESTarchitecture

WhenRESTfulconstraintsarejudiciouslyabidedbywebapplicationscanbescaledtoaccommodatemassivenumbersofclientsUsingtheRESTarchitecturecanalsohelpreducedelaysbetweenclientsandserverssimplifysystemarchitectureandimprovethevisibilityofsub-systemendpoints

Figure86RESTsexpansibility

RESTfulimplementationGodoesnthavedirectsupportforRESTbutsinceRESTfulwebapplicationsareallHTTP-basedwecanusethenethttppackagetoimplementitonourownOfcoursewewillfirstneedtomakesomemodificationsbeforeweareabletofullyimplementREST

RESTusesdifferentmethodstohandleresourcesdependingontheinteractionthatsrequiredwiththatresourceManyexistingapplicationsclaimtobeRESTfulbuttheydonotactuallyimplementRESTImgoingtocategorizetheseapplicationsintoseverallevelsdependsonwhichHTTPmethodstheyimplement

Figure87RESTslevel

ThepictureaboveshowsthreelevelsthatarecurrentlyimplementedinRESTYoumaynotchoosetofollowalltherulesandconstraintsofRESTwhendevelopingyourownapplicationsbecausesometimesitsrulesarenotagoodfitforallsituationsRESTfulwebapplicationsuseeverysingleHTTPmethodincludingDELETEandPUTbutinmanycasesHTTPclientscanonlysendGETandPOSTrequests

HTMLstandardallowsclientssendGETandPOSTrequeststhroughlinksandformsItsnotpossibletosendPUTorDELETErequestswithoutAJAXsupportSomefirewallsinterceptPUTandDELETErequestsandclientshavetousePOSTinordertoimplementthemFullyRESTfulservicesareinchargeoffindingtheoriginalHTTPmethodsandrestoringthem

WecansimulatePUTandDELETErequestsbyaddingahidden_methodfieldinourPOSTrequestshowevertheserequestsmustbeconvertedontheserversidebeforetheyareprocessedMypersonalapplicationsusethisworkflowtoimplementRESTinterfacesStandardRESTfulinterfacesareeasilyimplementedinGoasthefollowingexampledemonstrates

REST

198

packagemain

import(

fmt

githubcomjulienschmidthttprouter

log

nethttp

)

funcIndex(whttpResponseWriterrhttpRequest_httprouterParams)

fmtFprint(wWelcomen)

funcHello(whttpResponseWriterrhttpRequestpshttprouterParams)

fmtFprintf(whellosnpsByName(name))

funcgetuser(whttpResponseWriterrhttpRequestpshttprouterParams)

uid=psByName(uid)

fmtFprintf(wyouaregetusersuid)

funcmodifyuser(whttpResponseWriterrhttpRequestpshttprouterParams)

uid=psByName(uid)

fmtFprintf(wyouaremodifyusersuid)

funcdeleteuser(whttpResponseWriterrhttpRequestpshttprouterParams)

uid=psByName(uid)

fmtFprintf(wyouaredeleteusersuid)

funcadduser(whttpResponseWriterrhttpRequestpshttprouterParams)

uid=rFormValue(uid)

uid=psByName(uid)

fmtFprintf(wyouareaddusersuid)

funcmain()

router=httprouterNew()

routerGET(Index)

routerGET(hellonameHello)

routerGET(useruidgetuser)

routerPOST(adduseruidadduser)

routerDELETE(deluseruiddeleteuser)

routerPUT(moduseruidmodifyuser)

logFatal(httpListenAndServe(8080router))

ThissamplecodeshowsyouhowtowriteaverybasicRESTapplicationOurresourcesareusersandweusedifferentfunctionsfordifferentmethodsHereweimportedathird-partypackagecalledgithubcomjulienschmidthttprouterWevealreadycoveredhowtoimplementacustomrouterinpreviouschapters-thejulienschmidthttprouterpackageimplementssomeveryconvenientroutermappingrulesthatmakeitveryconvenientforimplementingRESTfularchitectureAsyoucanseeRESTrequiresyoutoimplementdifferentlogicfordifferentHTTPmethodsofthesameresource

SummaryRESTisastyleofwebarchitecturebuildingonpastsuccessfulexperienceswithWWWstatelessnessresource-centricfulluseofHTTPandURIprotocolsandtheprovisionofunifiedinterfacesThesesuperiordesignconsiderationshaveallowedRESTtobecomethemostpopularwebservicesstandardInasensebyemphasizingtheURIandleveraging

REST

199

earlyInternetstandardssuchasHTTPRESThaspavedthewayforlargeandscalablewebapplicationsCurrentlythesupportthatGohasForRESTisstillverybasicHoweverbyimplementingcustomroutingrulesanddifferentrequesthandlersforeachtypeofHTTPrequestwecanachieveRESTfularchitectureinourGowebapps

LinksDirectoryPrevioussectionWebSocketNextsectionRPC

REST

200

84RPCInprevioussectionswetalkedabouthowtowritenetworkapplicationsbasedonSocketsandHTTPWelearnedthatbothofthemusetheinformationexchangemodelinwhichclientssendrequestsandserversrespondtothemThiskindofdataexchangeisbasedonaspecificformatsothatbothsidesareabletocommunicatewithoneanotherHowevermanyindependentapplicationsdonotusethismodelbutinsteadcallservicesjustliketheywouldcallnormalfunctions

RPCwasintendedtobethefunctioncallmodefornetworkedsystemsClientsexecuteRPCsliketheycallnativefunctionsexcepttheypackagethefunctionparametersandsendthemthroughthenetworktotheserverTheservercanthenunpacktheseparametersandprocesstherequestexecutingtheresultsbacktotheclient

Incomputersciencearemoteprocedurecall(RPC)isatypeofinter-processcommunicationthatallowsacomputerprogramtocauseasubroutineorproceduretoexecuteinanotheraddressspace(commonlyonanothercomputeronasharednetwork)withouttheprogrammerexplicitlycodingthedetailsforthisremoteinteractionThatistheprogrammerwritesessentiallythesamecodewhetherthesubroutineislocaltotheexecutingprogramorremoteWhenthesoftwareinquestionusesobject-orientedprinciplesRPCiscalledremoteinvocationorremotemethodinvocation

RPCworkingprinciple

Figure88RPCworkingprinciple

NormallyanRPCcallfromclienttoserverhasthefollowingtensteps

1 Calltheclienthandleexecutetransferarguments

1 Calllocalsystemkerneltosendnetworkmessages

1 Sendmessagestoremotehosts

1 Theserverreceiveshandleandarguments

1 Executeremoteprocesses

1 Returnexecutionresulttocorrespondinghandle

1 Theserverhandlecallsremotesystemkernel

1 Messagessentbacktolocalsystemkernel

1 Theclienthandlereceivesmessagesfromsystemkernel

1 Theclientgetsresultsfromcorrespondinghandle

GoRPCGohasofficialsupportforRPCinitsstandardlibraryonthreelevelswhichareTCPHTTPandJSONRPCNotethatGoRPCisnotlikeothertraditionalRPCsystemsItrequiresyoutouseGoapplicationsonbothclientandserversidesbecauseitencodescontentusingGob

RPC

201

FunctionsofGoRPCmustabidebythefollowingrulesforremoteaccessotherwisethecorrespondingcallswillbeignored

Functionsareexported(capitalized)FunctionsmusthavetwoargumentswithexportedtypesThefirstargumentisforreceivingfromtheclientandthesecondonehastobeapointerandisforreplyingtotheclientFunctionsmusthaveareturnvalueoferrortype

Forexample

func(tT)MethodName(argTypeT1replyTypeT2)error

WhereTT1andT2mustbeabletobeencodedbythepackagegobpackage

AnykindofRPChastogothroughanetworktotransferdataGoRPCcaneitheruseHTTPorTCPThebenefitsofusingHTTPisthatyoucanreusesomefunctionsfromthenethttppackage

HTTPRPCHTTPserversidecode

RPC

202

packagemain

import(

errors

fmt

nethttp

netrpc

)

typeArgsstruct

ABint

typeQuotientstruct

QuoRemint

typeArithint

func(tArith)Multiply(argsArgsreplyint)error

reply=argsAargsB

returnnil

func(tArith)Divide(argsArgsquoQuotient)error

ifargsB==0

returnerrorsNew(dividebyzero)

quoQuo=argsAargsB

quoRem=argsAargsB

returnnil

funcmain()

arith=new(Arith)

rpcRegister(arith)

rpcHandleHTTP()

err=httpListenAndServe(1234nil)

iferr=nil

fmtPrintln(errError())

WeregisteredaRPCserviceofAriththenregisteredthisserviceonHTTPthroughrpcHandleHTTPAfterthatweareabletotransferdatathroughHTTP

Clientsidecode

RPC

203

packagemain

import(

fmt

log

netrpc

os

)

typeArgsstruct

ABint

typeQuotientstruct

QuoRemint

funcmain()

iflen(osArgs)=2

fmtPrintln(UsageosArgs[0]server)

osExit(1)

serverAddress=osArgs[1]

clienterr=rpcDialHTTP(tcpserverAddress+1234)

iferr=nil

logFatal(dialingerr)

Synchronouscall

args=Args178

varreplyint

err=clientCall(ArithMultiplyargsampreply)

iferr=nil

logFatal(aritherrorerr)

fmtPrintf(Arithdd=dnargsAargsBreply)

varquotQuotient

err=clientCall(ArithDivideargsampquot)

iferr=nil

logFatal(aritherrorerr)

fmtPrintf(Arithdd=dremainderdnargsAargsBquotQuoquotRem)

WecompiletheclientandtheserversidecodeseparatelythenstarttheserverandclientYoullthenhavesomethingsimilarasfollowsafteryouinputsomedata

$http_clocalhost

Arith178=136

Arith178=2remainder1

AsyoucanseewedefinedastructforthereturntypeWeuseitastypeoffunctionargumentontheserversideandasthetypeofthesecondandthirdargumentsontheclientclientCallThiscallisveryimportantIthasthreeargumentswherethefirstoneisthenameofthefunctionthatisgoingtobecalledthesecondistheargumentyouwanttopassandthelastoneisthereturnvalue(ofpointertype)SofarweseethatitseasytoimplementRPCinGo

TCPRPCLetstrytheRPCthatisbasedonTCPhereistheserversidecode

RPC

204

packagemain

import(

errors

fmt

net

netrpc

os

)

typeArgsstruct

ABint

typeQuotientstruct

QuoRemint

typeArithint

func(tArith)Multiply(argsArgsreplyint)error

reply=argsAargsB

returnnil

func(tArith)Divide(argsArgsquoQuotient)error

ifargsB==0

returnerrorsNew(dividebyzero)

quoQuo=argsAargsB

quoRem=argsAargsB

returnnil

funcmain()

arith=new(Arith)

rpcRegister(arith)

tcpAddrerr=netResolveTCPAddr(tcp1234)

checkError(err)

listenererr=netListenTCP(tcptcpAddr)

checkError(err)

for

connerr=listenerAccept()

iferr=nil

continue

rpcServeConn(conn)

funccheckError(errerror)

iferr=nil

fmtPrintln(FatalerrorerrError())

osExit(1)

ThedifferencebetweenHTTPRPCandTCPRPCisthatwehavetocontrolconnectionsbyourselvesifweuseTCPRPCthenpassconnectionstoRPCforprocessing

AsyoumayhaveguessedthisisablockingpatternYouarefreetousegoroutinestoextendthisapplicationasamoreadvancedexperiment

Theclientsidecode

RPC

205

packagemain

import(

fmt

log

netrpc

os

)

typeArgsstruct

ABint

typeQuotientstruct

QuoRemint

funcmain()

iflen(osArgs)=2

fmtPrintln(UsageosArgs[0]serverport)

osExit(1)

service=osArgs[1]

clienterr=rpcDial(tcpservice)

iferr=nil

logFatal(dialingerr)

Synchronouscall

args=Args178

varreplyint

err=clientCall(ArithMultiplyargsampreply)

iferr=nil

logFatal(aritherrorerr)

fmtPrintf(Arithdd=dnargsAargsBreply)

varquotQuotient

err=clientCall(ArithDivideargsampquot)

iferr=nil

logFatal(aritherrorerr)

fmtPrintf(Arithdd=dremainderdnargsAargsBquotQuoquotRem)

TheonlydifferenceintheclientsidecodeisthatHTTPclientsuseDialHTTPwhereasTCPclientsuseDial(TCP)

JSONRPC

JSONRPCencodesdatatoJSONinsteadofgobLetsseeanexampleofaGoJSONRPContheserver

RPC

206

packagemain

import(

errors

fmt

net

netrpc

netrpcjsonrpc

os

)

typeArgsstruct

ABint

typeQuotientstruct

QuoRemint

typeArithint

func(tArith)Multiply(argsArgsreplyint)error

reply=argsAargsB

returnnil

func(tArith)Divide(argsArgsquoQuotient)error

ifargsB==0

returnerrorsNew(dividebyzero)

quoQuo=argsAargsB

quoRem=argsAargsB

returnnil

funcmain()

arith=new(Arith)

rpcRegister(arith)

tcpAddrerr=netResolveTCPAddr(tcp1234)

checkError(err)

listenererr=netListenTCP(tcptcpAddr)

checkError(err)

for

connerr=listenerAccept()

iferr=nil

continue

jsonrpcServeConn(conn)

funccheckError(errerror)

iferr=nil

fmtPrintln(FatalerrorerrError())

osExit(1)

JSONRPCisbasedonTCPanddoesntsupportHTTPyet

Theclientsidecode

RPC

207

packagemain

import(

fmt

log

netrpcjsonrpc

os

)

typeArgsstruct

ABint

typeQuotientstruct

QuoRemint

funcmain()

iflen(osArgs)=2

fmtPrintln(UsageosArgs[0]serverport)

logFatal(1)

service=osArgs[1]

clienterr=jsonrpcDial(tcpservice)

iferr=nil

logFatal(dialingerr)

Synchronouscall

args=Args178

varreplyint

err=clientCall(ArithMultiplyargsampreply)

iferr=nil

logFatal(aritherrorerr)

fmtPrintf(Arithdd=dnargsAargsBreply)

varquotQuotient

err=clientCall(ArithDivideargsampquot)

iferr=nil

logFatal(aritherrorerr)

fmtPrintf(Arithdd=dremainderdnargsAargsBquotQuoquotRem)

SummaryGohasgoodsupportforHTTPTPCandJSONRPCimplementationwhichallowustoeasilydevelopdistributedwebapplicationshoweveritisregrettablethatGodoesnthavebuilt-insupportforSOAPRPCalthoughsomeopensourcethird-partypackagesdoofferthis

LinksDirectoryPrevioussectionRESTNextsectionSummary

RPC

208

85SummaryInthischapterIintroducedyoutoseveralmainstreamwebapplicationdevelopmentmodelsInsection81IdescribedthebasicsofnetworkprogrammingsocketsBecauseoftherapidevolutionofnetworktechnologyandinfrastructureandgiventhattheSocketisthecornerstoneofthesechangesyoumustmastertheconceptsbehindsocketprogramminginordertobeacompetentwebdeveloperInsection82IdescribedHTML5WebSocketswhichsupportfull-duplexcommunicationsbetweenclientandserverandeliminatetheneedforpollingwithAJAXInsection83weimplementedasimpleapplicationusingtheRESTarchitecturewhichisparticularlysuitableforthedevelopmentofnetworkAPIsduetotherapidriseofmobileapplicationsIbelievethatRESTfulAPIswillbeanongoingtrendInsection84welearnedaboutGoRPCs

GoprovidesexcellentsupportforthefourkindsofdevelopmentmethodsmentionedaboveNotethatthenetpackageanditssub-packagesistheplacewhereGosnetworkprogrammingtoolsGoresideIfyouwantamorein-depthunderstandingoftherelevantimplementationdetailsyoushouldtryreadingthesourcecodeofthosepackages

LinksDirectoryPrevioussectionRPCNextchapterSecurityandencryption

Summary

209

9SecurityandencryptionSecurityisanextremelyimportantaspectofmostwebapplicationsThistopichasbeengettingmoreandmoreattentionlatelyespeciallyinlightoftherecentCSDNLinkedinandYahoopasswordleaksAsGodeveloperswemustbeawareofvulnerabilitiesinourapplicationsandtakeprecautionsinordertopreventattackersfromtakingoveroursystems

Manyofthesecurityproblemsthatariseinmodernwebapplicationsoriginatefromdataprovidedbythird-partiesForexampleuserinputshouldalwaysbevalidatedandsanitizedbeforebeingstoredassecuredataIfthisisntdonewhenthedataisoutputtedtoaclientitmaycauseacross-sitescriptingattack(XSS)SimilarlyifunsafedataisuseddirectlyasyourapplicationsdatabasequeriesthenyoumaybevulnerabletoSQLinjectionattacksInsections93and94welllookathowtoavoidtheseproblems

Whenusingthird-partydata(whichincludesuser-supplieddata)firstverifytheintegrityofthedatabyfilteringtheinputSection92willdescribehowtofilterinput

UnfortunatelyfilteringinputandescapingoutputdoesnotsolveallsecurityproblemsInsection91wewillexplaincross-siterequestforgery(CSRF)attacksThisisamaliciousexploitwhereunauthorizedcommandsaretransmittedfromauserthatthewebsitetrusts

KeepingconfidentialdataencryptedcanalsohelpyoutosecureyourwebapplicationsInsection95wewilldescribehowtostorepasswordssafelyusingGosencryptionpackage

AgoodhashfunctionmakesithardtofindtwostringsthatwouldproducethesamehashvalueandthisisonewaywithwhichwecanencryptourdataThereisalsotwo-wayencryptionwhereyouuseasecretkeytodecryptencrypteddataInsection96wewilldescribehowtoperformbothone-wayandtwo-wayencryption

LinksDirectoryPreviousChapterChapter8SummaryNextsectionCSRFattacks

Securityandencryption

210

91CSRFattacks

WhatisCSRFCSRFandXSRFbothstandforCross-siterequestforgeryItsalsoknownasaoneclickattackorsessionriding

SohowdoesaCSRFattackworkACSRFattackhappenswhenanattackertricksatrusteduserintoaccessingawebsiteorclickingaURLthattransmitsmaliciousrequests(withouttheuserrsquosconsent)toatargetedwebsiteHeresasimpleexampleusingafewsocialengineeringtricksanattackercouldusetheQQchatsoftwaretofindandsendmaliciouslinkstovictimstargetedattheirusersonlinebankingwebsiteIfthevictimlogsintotheironlinebankaccountanddoesnotexitthenclickingonamaliciouslinksentfromtheattackercouldallowtheattackertostealalloftheusersbankaccountfunds

WhenunderaCSRFattackasingleend-userwithanadministratoraccountcanthreatentheintegrityoftheentirewebapplication

CSRFprincipleThefollowingdiagramprovidesasimpleoverviewofaCSRFattack

Figure91CSRFattackprocess

AscanbeseenfromthefiguretocompleteaCSRFattackthevictimmustcompletethefollowingtwosteps

-1LogintotrustedsiteAandstorealocalCookie-2WithoutgoingthroughexistingsiteAaccessthedangerouslinktositeB

AsareaderyoumaybeaskingIfIdonotmeettheabovetwoconditionsIwillnotbesubjectedtoCSRFattacksYesthisistruehoweveryoucannotguaranteethatthefollowingdoesnotoccur

YoucannotguaranteethatwhenyouareloggedintoasitethesitedidntlaunchanyhiddentabsYoucannotguaranteethatwhenyoucloseyourbrowseryourcookieswillimmediatelyexpireandyourlastsessionwillhaveendedTrustedhightrafficwebsiteswilllikelynothavehiddenvulnerabilitieseasilyexploitablebyCSRFbasedattacks

ThusitcanbedifficultforuserstovisitawebsitethroughalinkandknowthatitwillnotcarryoutunknownoperationsintheformofaCSRFattack

CSRFattacksworkmostlybecauseoftheprocessthroughwhichusersareauthenticatedAlthoughyoucanreasonablyguaranteethatarequestoriginatesfromausersbrowserthereisnoguaranteethattheusergrantedapprovalfortherequest

HowtopreventCSRFattacksYoumightbealittlescaredafterreadingthesectionaboveButfearisagoodthingItwillforceyoutoeducateyourselfonhowtopreventvulnerabilitieslikethisfromhappeningtoyou

PreventativemeasuresagainstCSRFattackscanbetakenonboththeserverandclientsidesofawebapplicationHoweverCSRFattacksaremosteffectivelythwartedontheserverside

TherearemanywaysofpreventingCSRFattacksontheserversideMostapproachesstemfromthefollowingtwoaspects

1 MaintainingproperuseofGETPOSTandcookies

CSRFattacks

211

2 Includingapseudo-randomnumberwithnon-GETrequests

InthepreviouschapteronRESTwesawhowmostwebapplicationsarebasedonGETandPOSTHTTPrequestsandthatcookieswereincludedalongwiththeserequestsWegenerallydesignapplicationsaccordingtothefollowingprinciples

1 GETiscommonlyusedtoviewinformationwithoutalteringanydata

2 POSTisusedinplacingorderschangingthepropertiesofaresourceorperformingothertasks

ImnowgoingtousetheGolanguagetoillustratehowtorestrictaccesstoresourcesmethods

muxGet(useruidgetuser)

muxPost(useruidmodifyuser)

SincewevestipulatedthatmodificationscanonlyusePOSTwhenaGETmethodisissuedinsteadofaPOSTwecanrefusetorespondtotherequestAccordingtothefigureaboveattacksutilizingGETasaCSRFexploitcanbepreventedIsthisenoughtopreventallpossibleCSRFattacksOfcoursenotbecausePOSTscanalsobeforged

Weneedtoimplementasecondstepwhichis(inthecaseofnon-GETrequests)toincreasethelengthofthepseudo-randomnumberincludedwiththerequestThisusuallyinvolvessteps

Foreachusergenerateauniquecookietokenwithapseudo-randomvalueAllformsmustcontainthesamepseudo-randomvalueThisproposalisthesimplestonebecauseintheoryanattackercannotreadthirdpartycookiesAnyformthatanattackermaysubmitwillfailthevalidationprocesswithoutknowingwhattherandomvalueisDifferentformscontaindifferentpseudo-randomvaluesasweveintroducedinsection44HowtopreventmultipleformsubmissionWecanreusetherelevantcodefromthatsectiontomeetourneeds

Generatingarandomnumbertoken

h=md5New()

ioWriteString(hstrconvFormatInt(crutime10))

ioWriteString(hganraomaxxxxxxxxx)

token=fmtSprintf(xhSum(nil))

t_=templateParseFiles(logingtpl)

tExecute(wtoken)

Outputtoken

ltinputtype=hiddenname=tokenvalue=gt

Authenticationtoken

rParseForm()

token=rFormGet(token)

iftoken=

Verificationtokenoflegitimacy

Else

Errortokendoesnotexist

WecanusetheprecedingcodetosecureourPOSTsYoumightbewonderinginaccordancewithourtheorywhethertherecouldbesomewayforamaliciousthirdpartytosomehowfigureoutoursecrettokenvalueInfactcrackingitisbasicallyimpossible-successfullycalculatingthecorrectstringvalueusingbruteforcemethodsneedsabout2tothe11thtime

Summary

CSRFattacks

212

Cross-siterequestforgeryalsoknownasCSRFisaverydangerouswebsecuritythreatItisknowninwebsecuritycirclesasasleepinggiantsecurityissueasyoucantellCSRFattackshavequitethereputationThissectionnotonlyintroducedcross-siterequestforgeryitselfbutfactorsunderlyingthisvulnerabilityItconcludeswithsomesuggestionsandmethodsforpreventingsuchattacksIhopethissectionwillhaveinspiredyouasareadertowritebetterandmoresecurewebapplications

LinksDirectoryPrevioussectionSecurityandencryptionNextsectionFilterinputs

CSRFattacks

213

92FilteringinputsFilteringuserdataisonewaywecanimprovethesecurityofourwebappsusingittoverifythelegitimacyofincomingdataAlloftheinputdataisfilteredinordertoavoidmaliciouscodeordatafrombeingmistakenlyexecutedorstoredMostwebapplicationvulnerabilitiesariseformneglectingtofilterinputdataandnaivelytrustingit

Ourintroductiontofilteringdataisdividedintothreesteps

1 identifyingthedataweneedtofilterthedatatofigureoutwhereitoriginatedfrom2 filteringofthedataitselfweneedtofigureoutwhatkindofdatawehavereceived3 distinguishbetweenfiltered(sanitized)andtainteddataafterthedatahasbeenfilteredwecanbeassuredthatitis

secure

IdentifyingdataIdentifyingthedataisourfirststepbecausemostofthetimeasmentionedwedontknowwhereitoriginatesfromWithoutthisknowledgewewouldbeunabletoproperlyfilteritThedatahereisprovidedinternallyallfromnon-codedataForexamplealldatacomesfromclientshoweverclientsthatareusersarenottheonlyexternalsourcesofdataAdatabaseinterfaceprovidingthirdpartydatacouldalsobeanexternaldatasource

DatathathasbeenenteredbyauserisveryeasytorecognizeinGoWeuserParseFormaftertheuserPOSTsaformtogetallofthedatainsidetherFormOthertypesofinputaremuchhardertoidentifyForexampleinrHeadersmanyoftheelementsareoftenmanipulatedbytheclientItcanoftenbedifficulttoidentifywhichoftheseelementshavebeenmanipulatedbyclientssoitsbesttoconsiderallofthemashavingbeentaintedTherHeaderGet(Accept-Charset)headerfieldforinstanceisalsoconsideredasuserinputalthoughthesearetypicallyonlymanipulatedbybrowsers

FilteringdataIfweknowthesourceofthedatawecanfilteritFilteringisabitofaformaluseofthetermTheprocessisknownbymanyothertermssuchasinputcleaningvalidationandsanitizationDespitethefactthatthesetermsdiffersomewhatintheirmeaningtheyallrefertothesamethingtheprocessofpreventingillegaldatafrommakingitswayintoyourapplications

TherearemanywaystofilterdatasomeofwhicharelesssecurethanothersThebestmethodistocheckwhetherornotthedataitselfmeetsthelegalrequirementsdictatedbyyourapplicationWhenattemptingtodosoitsveryimportantnottomakeanyattemptsatcorrectingtheillegaldatathiscouldallowmalicioususerstomanipulateyourvalidationrulesfortheirownneedsaltogetherdefeatingthepurposeoffilteringthedatainthefirstplaceHistoryhasproventhatattemptingtocorrectinvaliddataoftenleadstosecurityvulnerabilitiesLetstakealookatanoverlysimpleexampleforillustrationpurposesSupposethatabankingsystemasksuserstosupplyasecure6digitpasswordThesystemvalidatesthelengthofallpasswordsOnemightnaivelywriteavalidationrulethatcorrectspasswordsofillegallengthsIfapasswordisshorterthanthelegallengthfillintheremainingdigitswith0sThissimplerulewouldallowattackerstoguessjustthefirstfewdigitsofapasswordtosuccessfullygainaccesstouseraccounts

Wecanuseseverallibrariestohelpustofilterdata

ThestrconvpackagecanhelpustoconvertstringsinputbyusersintospecifictypessincerFormsaremapsofstringvaluesSomecommonstringconversionsprovidedbystrconvareAtoiParseBoolParseFloatandParseIntGosstringspackagecontainssomefilterfunctionslikeTrimToLowerandToTitlewhichcanhelpustoobtaindatainaspecificformatsaccordingtoourneedsGosregexppackagecanbeusedtohandlecaseswhicharemorecomplexinnaturesuchasdeterminingwhetheraninputisanemailaddressabirthdayetc

Filterinputs

214

FilteringincomingdatainadditiontoauthenticationcanbequiteeffectiveLetsaddanothertechniquetoourrepertoirecalledwhitelistingWhitelistingisagoodwayofconfirmingthelegitimacyofincomingdataUsingthismethodifanerroroccursitcanonlymeanthattheincomingdataisillegalandnottheoppositeOfcoursewedontwanttomakeanymistakesinourwhitelistbyfalselylabellinglegitimatedataasillegalbutthisscenarioismuchbetterthanillegaldatabeinglabeledaslegitimateandthusmuchmoresecure

DistinguishingbetweenfilteredandtainteddataIfyouhavecompletedtheabovestepsthejoboffilteringdatahasbasicallybeencompletedHoweverwhenwritingwebapplicationswealsoneedtodistinguishbetweenfilteredandtainteddatabecausedoingsocanguaranteetheintegrityofourdatafilteringprocesswithoutaffectingtheinputdataLetsputallofourfiltereddataintoaglobalmapvariablecalledCleanMapThentwoimportantstepsarerequiredtopreventcontaminationviadatainjection

EachrequestmustinitializeCleanMapasanemptymapPreventvariablesfromexternaldatasourcesnamedCleanMapfrombeingintroducedintotheapp

Nextletsuseanexampleformtoreinforcetheseconcepts

ltformaction=whoamimethod=POSTgt

WhoamI

ltselectname=namegt

ltoptionvalue=astaxiegtastaxieltoptiongt

ltoptionvalue=herrygtherryltoptiongt

ltoptionvalue=marrygtmarryltoptiongt

ltselectgt

ltinputtype=submitgt

ltformgt

IndealingwiththistypeofformitcanbeveryeasytomakethemistakeofthinkingthatuserswillonlybeabletosubmitoneofthethreeselectoptionsInfactPOSToperationscaneasilybesimulatedbyattackersForexamplebysubmittingthesameformwithname=attackamalicioususercouldintroduceillegaldataintooursystemWecanuseasimplewhitelisttocounterthesetypesofattacks

rParseForm()

name=rFormGet(name)

CleanMap=make(map[string]interface0)

ifname==astaxie||name==herry||name==marry

CleanMap[name]=name

TheabovecodeinitializesaCleanMapvariableandanameisonlyassignedaftercheckingitagainstaninternalwhitelistoflegitimatevalues(astaxieherryandmarryinthiscase)WestorethedataintheCleanMapinstancesoyoucanbesurethatCleanMap[name]holdsavalidatedvalueAnycodewishingtoaccessthisvaluecanthenfreelydosoWecanalsoaddanadditionalelsestatementtotheaboveifwhitelistfordealingwithillegaldataapossibilitybeingthattheformwasdisplayedwithanerrorDonottrytobetooaccommodatingthoughoryouruntheriskofaccidentallycontaminatingyourCleanMap

TheabovemethodforfilteringdataagainstasetofknownlegitimatevaluesisveryeffectiveThereisanothermethodforcheckingwhetherornotincomingdataconsistsoflegalcharactersusingregexphoweverthiswouldbeineffectualintheabovecasewherewerequirethatthenamebeanoptionfromtheselectForexampleyoumayrequirethatusernamesonlyconsistoflettersandnumbers

rParseForm()

username=rFormGet(username)

CleanMap=make(map[string]interface0)

ifok_=regexpMatchString(^[a-zA-Z0-9]$username)ok

CleanMap[username]=username

Filterinputs

215

SummaryDatafilteringplaysavitalroleinthesecurityofmodernwebapplicationsMostsecurityvulnerabilitiesaretheresultofimproperlyfilteringdataorneglectingtoproperlyvalidateitBecausetheprevioussectiondealtwithCSRFattacksandthenexttwowillbeintroducingXSSattacksandSQLinjectiontherewasnonaturalsegueintodealingwithatopicasimportantasdatasanitizationsointhissectionwepaidspecialattentiontoit

LinksDirectoryPrevioussectionCSRFattacksNextsectionXSSattacks

Filterinputs

216

93XSSattacksWiththedevelopmentofInternettechnologywebapplicationsareoftenpackedwithdynamiccontenttoimproveuserexperienceDynamiccontentiscontentthatreactsandchangesaccordingtouserrequestsandactionsDynamicsitesareoftensusceptibletocross-sitescriptingattacks(oftenreferredtobysecurityexpertsinitsabbreviatedformXSS)somethingwhichstaticwebsitesarecompletelyunaffectedby

WhatisXSSAsmentionedthetermXSSisanacronymforCross-SiteScriptingwhichisatypeofattackcommononthewebInordernottoconfuseitwithanothercommonwebacronymCSS(CascadingStyleSheets)weuseanXinsteadofaCforthecrossincross-sitescriptingXSSisacommonwebsecurityvulnerabilitywhichallowsattackerstoinjectmaliciouscodeintowebpagesUnlikemosttypesofattackswhichgenerallyinvolveonlyanattackerandavictimXSSinvolvesthreepartiesanattackeraclientandawebapplicationThegoalofanXSSattackistostealcookiesstoredonclientsbywebapplicationsforthepurposeofreadingsensitiveclientinformationOnceanattackergetsaholdofthisinformationtheycanimpersonateusersandinteractwithwebsiteswithouttheirknowledgeorapproval

XSSattackscanusuallybedividedintotwocategoriesoneisastoredXSSattackThisformofattackariseswhenusersareallowedtoinputdataontoapublicpagewhichafterbeingsavedbytheserverwillbereturned(unescaped)tootherusersthathappentobebrowsingitSomeexamplesofthetypesofpagesthatareoftenaffectedincludecommentsreviewsblogpostsandmessageboardsTheprocessoftengoeslikethisanattackerenterssomehtmlfollowedbyahiddenltscriptgttagcontainingsomemaliciouscodethenhitssaveThewebapplicationsavesthistothedatabaseWhenanotheruserrequeststhispagetheapplicationqueriesthistainteddatafromthedatabaseandservesthepagetotheuserTheattackersscriptthenexecutesarbitrarycodeontheclientscomputer

TheothertypeisareflectedXSSattackThemainideaistoembedamaliciousscriptdirectlyintothequeryparametersofaURLaddressAserverthatimmediatelyparsesthisdataintoapageofresultsandreturnsit(totheclientwhomadetherequest)unsanitizedcanunwittinglycausetheclientscomputertoexecutethiscodeAnattackercansendauseralegitimatelookinglinktoatrustedwebsitewiththeencodedpayloadclickingonthislinkcancausetheusersbrowsertoexecutethemaliciousscript

XSSpresentthemainmeansandendsasfollows

TheftofcookiesaccesstosensitiveinformationTheuseofembeddedFlashthroughcrossdomainpermissionscanalsobeusedbyanattackertoobtainhigheruserprivilegesThisalsoappliesforothersimilarattackvectorssuchasJavaandVBScriptTheuseofiframesframesXMLHttpRequestsetccanallowanattackertoassumetheidentityofausertoperformadministrativeactionssuchasmicro-bloggingaddingfriendssendingprivatemessagesandotherroutineoperationsAwhileagotheSinamicrobloggingplatformsufferedfromthistypeofXSSvulnerabilityWhenmanyusersvisitapageaffectedbyanXSSattacktheeffectonsomesmallersitescanbecomparabletothatofaDDoSattack

XSSprinciplesWebapplicationsthatreturnrequesteddatatouserswithoutfirstinspectingandfilteringitcanallowmalicioususerstoinjectscripts(typicallyembeddedinsideHTMLwithinltscriptgttags)ontootherusersbrowsersWhenthismaliciouscodeisrenderedonausersbrowserwithoutfirsthavingbeenescapedfromtheusersbrowserwillinterpretthiscodethisisthedefinitionofanXSSattackandthistypeofmistakeistheleadingcauseofXSSvulnerabilities

LetsgothroughtheprocessofareflectiveXSSattackLetssaytheresawebsitethatoutputsausersnameaccordingtotheURLqueryparametersaccessthefollowingURLhttp127001name=astaxiewillcausetheservertooutputthefollowing

XSSattacks

217

helloastaxie

Letssaywepassthefollowingparameterinsteadaccessingthesameurlhttp127001name=ltscriptgtalert(astaxiexss)ltscriptgtIfthiscausesthebrowsertoproduceanalertpop-upboxwecanconfirmthatthesiteisvulnerabletoXSSattacksSohowdomalicioususersstealcookiesusingthesametypeofattack

JustlikebeforewehaveaURL

http127001

name=amp60scriptamp62documentlocationhref=httpwwwxxxcomcookie+documentcookieamp60scriptamp62

ByclickingonthisURLyoudbesendingthecurrentcookietothespecifiedsitewwwxxxcomYoumightbewonderingwhywouldanybodyclickonsuchastrangelookingURLinthefirstplaceWhileitstruethatthiskindofURLwillmakemostpeopleskepticalifanattackerweretouseoneofthemanypopularURLshorteningservicestoobscureitwouldyoustillbeabletoseeitMostattackerswouldobfuscatetheURLinonewayoranotherandyoudonlyknowthelegitimacyofthelinkafterclickingonitHoweverbythispointcookiedatawillhavealreadybeensenttothe3rdpartywebsitecompromisingyoursensitiveinformationYoucanusetoolslikeWebsleuthtoauditthesecurityofyourwebapplicationsforthesetypesofvulnerabilities

ForamoredetailedanalysisonanXSSattackhavealookatthearticle[SinamicrobloggingXSSeventanalysis](httpwwwrisingcomcnnewsletternews2011-08-189621html)

HowtopreventXSSTheanswerissimplenevertrustuserinputandalwaysfilteroutallspecialcharactersinanyinputdatayoumayreceiveThiswilleliminatethemajorityofXSSattacks

UsethefollowingtechniquestodefendagainstXSSattacks

Filterspecialcharacters

OnewaytoavoidXSSistofilteruser-suppliedcontentTheGolanguageprovidessomeHTMLfilteringfunctionsinitstexttemplatepackgesuchasHTMLEscapeStringandJSEscapeStringtonameafew

SpecifythecontenttypeinyourHTTPheaders

wHeader()Set(Content-Typetextjavascript)

Thisallowsclientbrowserstoparsetheresponseasjavascriptcode(applyingtheneccessaryfilters)insteadofrenderingthecontentinanunspecifiedandpotentiallydangerousmanner

SummaryIntroducingXSSvulnerabilitiesisaveryrealhazardwhendevelopingwebapplicationsItisimportanttoremembertofilteralldataespeciallybeforeoutputtingittoclientsthisisnowawell-establishedmeansofpreventingXSS

LinksDirectoryPrevioussectionFilterinputsNextsectionSQLinjection

XSSattacks

218

94SQLinjection

WhatisSQLinjectionSQLinjectionattacksare(asthenamewouldsuggest)oneofthemanytypesofscriptinjectionattacksInwebdevelopmentthesearethemostcommonformofsecurityvulnerabilitiesAttackerscanuseittoobtainsensitiveinformationfromdatabasesandaspectsofanattackcaninvolveaddinguserstothedatabaseexportingprivatefilesandevenobtainingthehighestsystemprivilegesfortheirownnefariouspurposes

SQLinjectionoccurswhenwebapplicationsdonoteffectivelyfilteroutuserinputleavingthedoorwideopenforattackerstosubmitmaliciousSQLquerycodetotheserverApplicationsoftenreceiveinjectedcodeaspartofanattackersinputwhichaltersthelogicoftheoriginalqueryinsomewayWhentheapplicationattemptstoexecutethequerytheattackersmaliciouscodeisexecutedinstead

SQLinjectionexamplesManywebdevelopersdonotrealizehowSQLqueriescanbetamperedwithandmayholdthemisconceptionthattheyaretrustedcommandsAseveryoneknowsSQLqueriesareabletocircumventaccesscontrolstherebybypassingthestandardauthenticationandauthorizationchecksWhatsmoreitspossibletorunSQLqueriesthroughcommandsatthelevelofthehostsystem

LetshavealookatsomerealexamplestoexplaintheprocessofSQLinjectionindetail

Considerthefollowingsimpleloginform

ltformaction=loginmethod=POSTgt

ltpgtUsernameltinputtype=textname=usernamegtltpgt

ltpgtPasswordltinputtype=passwordname=passwordgtltpgt

ltpgtltinputtype=submitvalue=Logingtltpgt

ltformgt

Ourformprocessingmightlooklikethis

username=rFormGet(username)

password=rFormGet(password)

sql=SELECTFROMuserWHEREusername=+username+ANDpassword=+password+

Iftheuserinputsausernameorpasswordas

myuserorfoo=foo--

ThenourSQLbecomesthefollowing

SELECTFROMuserWHEREusername=myuserorfoo=foo--ANDpassword=xxx

InSQLanythingafter--isacommentThusinsertingthe--astheattackerdidabovealtersthequeryinafatalwayallowinganattackertosuccessfullyloginasauserwithoutavalidpassword

FarmoredangerousexploitsexistforMSSQLSQLinjectionsandsomecanevenperformsystemcommandsThefollowingexampleswilldemonstratehowterribleSQLinjectionscanbeinsomeversionsofMSSQLdatabases

sql=SELECTFROMproductsWHEREnameLIKE+prod+

DbExec(sql)

SQLinjection

219

Ifanattackersubmitsaexecmasterxp_cmdshellnetusertesttestpassADD--astheprodvariablethenthesqlwillbecome

sql=SELECTFROMproductsWHEREnameLIKEaexecmasterxp_cmdshellnetusertesttestpassADD--

TheMSSQLServerexecutestheSQLstatementincludingthecommandsintheusersuppliedprodvariablewhichaddsnewuserstothesystemIfthisprogramisrunasisandtheMSSQLSERVERservicehassufficientprivilegesanattackercanregisterasystemaccounttoaccessthismachine

AlthoughtheexamplesabovearetiedtoaspecificdatabasesystemthisdoesnotmeanthatotherdatabasesystemscannotbesubjectedtosimilartypesofattacksTheprinciplesbehindSQLinjectionattacksremainthesamethoughthemethodwithwhichtheyareperpetratedmayvary

HowtopreventSQLinjectionYoumightbethinkingthatanattackerwouldhavetoknowinformationaboutthetargetdatabasesstructureinordertocarryoutanSQLinjectionattackWhilethisistrueitsdifficulttoguaranteethatanattackerwontbeabletofindthisinformationandoncetheygetitthedatabasecanbecompromisedIfyouareusingopensourcesoftwaretoaccessthedatabasesuchasaforumapplicationintruderscaneasilygettherelatedcodeObviouslywithpoorlydesignedcodethesecurityrisksareevengreaterDiscuzphpwindandphpcmsaresomeexamplesofpopularopensourceprogramsthathavebeenvulnerabletoSQLinjectionattacks

TheseattackshappentosystemswheresafetyprecautionsarenotprioritizedWevesaiditbeforewellsayitagainnevertrustanykindofinputespeciallyuserdataThisincludesdatacomingfromselectionboxeshiddeninputfieldsorcookiesAsourfirstexampleabovehasshownevensupposedlynormalqueriescancausedisasters

SQLinjectionattackscanbedevastating-howcandoweevenbegintodefendagainstthemThefollowingsuggestionsareagoodstartingpointforpreventingSQLinjection

1 Strictlylimitpermissionsfordatabaseoperationssothatusersonlyhavetheminimumsetofpermissionsrequiredtoaccomplishtheirworkthusminimizingtheriskofdatabaseinjectionattacks

2 CheckthatinputdatahastheexpecteddataformatandstrictlylimitthetypesofvariablesthatcanbesubmittedThiscaninvolveregexpmatchingorusingthestrconvpackagetoconvertstringsintootherbasictypesforsanitizationandevaluation

3 Transcodeorescapefrompairsofspecialcharacters(ampetc)beforepersistingthemintothedatabaseGostexttemplatepackagehasaHTMLEscapeStringfunctionthatcanbeusedtoreturnescapedHTML

4 UseyourdatabasesparameterizedqueryinterfaceParameterizedstatementsuseparametersinsteadofconcatenatinguserinputvariablesinembeddedSQLstatementsinotherwordstheydonotdirectlyspliceSQLstatementsForexampleusingthePreparefunctioninGosdatabasesqlpackagewecancreatepreparedstatementsforlaterexecutionwithQueryorExec(querystringargsinterface)

5 BeforereleasingyourapplicationthoroughlytestitusingprofessionaltoolsfordetectingSQLinjectionvulnerabilitiesandtorepairthemiftheyexistTherearemanyonlineopensourcetoolsthatdojustthissuchassqlmapSQLninjatonameafew

6 AvoidprintingoutSQLerrorinformationonpublicwebpagesAttackerscanusetheseerrormessagestocarryoutSQLinjectionattacksExamplesofsucherrorsaretypeerrorsfieldsnotmatchingerrorsoranyerrorscontainingSQLstatements

SummaryThroughtheaboveexampleswevelearnedthatSQLinjectionisaveryrealandverydangerouswebsecurityvulnerabilityWhenwewritewebapplicationweshouldpayattentiontoeverylittledetailandtreatsecurityissueswiththeutmostcareDoingsowillleadtobetterandmoresecurewebapplicationsandcanultimatelybethedetermingfactorinwhetherornotyourapplicationsucceeds

SQLinjection

220

LinksDirectoryPrevioussectionXSSattacksNextsectionPasswordstorage

SQLinjection

221

95PasswordstorageOvertheyearsmanywebsiteshavesufferedfrombreachesinuserpassworddataEventopinternetcompaniessuchasLinkedinandCSDNnethavebeenaffectedTheimpactoftheseeventshasbeenfeltacrosstheentireinternetandcannotbeunderestimatedThisisespeciallythecasefortodaysinternetuserswhooftenadoptthehabitofusingthesamepasswordformanydifferentwebsites

AswebdeveloperswehavemanychoiceswhenitcomestoimplementingapasswordstorageschemeHoweverthisfreedomisoftenadoubleedgedswordSowhatarethecommonpitfallsandhowcanweavoidfallingintothem

BadsolutionCurrentlythemostfrequentlyusedpasswordstorageschemeistoone-wayhashplaintextpasswordsbeforestoringthemThemostimportantcharacteristicofone-wayhashingisthatitisnotfeasibletorecovertheoriginaldatagiventhehasheddata-hencetheone-wayinone-wayhashingCommonlyusedcryptographicone-wayhashalgorithmsincludeSHA-256SHA-1MD5andsoon

YoucaneasilyusethethreeaforementionedhashingalgorithmsinGoasfollows

importcryptosha256

h=sha256New()

ioWriteString(hHismoneyistwicetaintedtaintyoursandtaintmine)

fmtPrintf(xhSum(nil))

importcryptosha1

h=sha1New()

ioWriteString(hHismoneyistwicetaintedtaintyoursandtaintmine)

fmtPrintf(xhSum(nil))

importcryptomd5

h=md5New()

ioWriteString(h需要加密的密码)

fmtPrintf(xhSum(nil))

Therearetwokeyfeaturesofone-wayhashing

1)givenaone-wayhashofapasswordtheresultingsummaryisalwaysuniquelydetermined2)calculationspeedAstechnologyadvancesitonlytakesasecondtocompletebillionsofone-wayhashcalculations

GiventhecombinationoftheabovetwocharacteristicsandtakingintoaccountthefactthatthemajorityofpeopleusesomecombinationofcommonpasswordsanattackercancomputeacombinationofallthecommonpasswordsEventhoughthepasswordsyoustoreinyourdatabasemaybehashvaluesonlyifattackersgainaccesstothisdatabasetheycancomparethestoredhashestotheirprecomputedhashestoobtainthecorrespondingpasswordsThistypeofattackreliesonwhatistypicallycalledarainbowtable

Wecanseethathashinguserdatausingone-wayhashesmaynotbeenoughOnceawebsitesdatabasegetsleakedtheusersoriginalpasswordcouldpotentiallyberevealedtotheworld

GoodsolutionThemethodmentionedabovemayhavebeensecureenoughtothwartmosthackingattemptsafewyearsagosincemostattackerswouldnothavehadthecomputingresourcestocomputelargerainbowtablesHoweverwiththeriseofparallelcomputingcapabilitiesthesetypesofattacksarebecomingmoreandmorefeasible

Passwordstorage

222

HowdowesecurelystoreapasswordsothatitcannotbedecipheredbyathirdpartygivenreallifelimitationsintimeandmemoryresourcesThesolutionistocalculateahashedpasswordtodeliberatelyincreasetheamountofresourcesandtimeitwouldtaketocrackitWewanttodesignahashsuchthatnobodycouldpossiblyhavetheresourcesrequiredtocomputetherequiredrainbowtable

VerysecuresystemsutilizehashalgorithmsthattakeintoaccountthetimeandresourcesitwouldrequiretocomputeagivenpassworddigestThisallowsustocreatepassworddigeststhatarecomputationallyexpensivetoperformonalargescaleThegreatertheintensityofthecalculationthemoredifficultitwillbeforanattackertopre-computerainbowtables-somuchsothatitmayevenbeinfeasibletotry

InGoitsrecommendedthatyouusethebcryptpackage

Thepackagessourcecodecanbefoundatthefollowinglinkhttpsgithubcomgolangcryptoblobmasterbcryptbcryptgo

Hereisanexamplecodesnippetwhichcanbeusedtohashstoreandvalidateuserpasswords

packagemain

import(

fmt

log

golangorgxcryptobcrypt

)

funcmain()

userPassword1=someuser-providedpassword

Generatehashtostorefromuserpassword

hasherr=bcryptGenerateFromPassword([]byte(userPassword1)bcryptDefaultCost)

iferr=nil

TODOProperlyhandleerror

logFatal(err)

fmtPrintln(Hashtostorestring(hash))

Storethishashsomewhereeginyourdatabase

Afterawhiletheuserwantstologinandyouneedtocheckthepasswordheentered

userPassword2=someuser-providedpassword

hashFromDatabase=hash

Comparingthepasswordwiththehash

iferr=bcryptCompareHashAndPassword(hashFromDatabase[]byte(userPassword2))err=nil

TODOProperlyhandleerror

logFatal(err)

fmtPrintln(Passwordwascorrect)

SummaryIfyoureworriedaboutthesecurityofyouronlinelifeyoucantakethefollowingsteps

1)AsaregularinternetuserwerecommendusingLastPassforpasswordstorageandgenerationondifferentsitesusedifferentpasswords

2)AsaGowebdeveloperwestronglysuggestthatyouuseoneoftheprofessionalwelltestedmethodsaboveforstoringuserpasswords

LinksDirectory

Passwordstorage

223

PrevioussectionSQLinjectionNextsectionEncryptanddecryptdata

Passwordstorage

224

96EncryptinganddecryptingdataTheprevioussectiondescribeshowtosecurelystorepasswordsbutsometimesitmightbeneccessarytomodifysomesensitiveencrypteddatathathasalreadybeenstoredintoourdatabaseWhendatadecryptionisrequiredweshoulduseasymmetricencryptionalgorithminsteadoftheone-wayhashingtechniqueswevepreviouslycovered

AdvancedencryptionanddecryptionTheGolanguagesupportssymmetricencryptionalgorithmsinitscryptopackageDonotuseanythingexceptAESinGCMmodeifyoudontknowwhatyouredoing

cryptoaespackageAES(AdvancedEncryptionStandard)alsoknownasRijndaelencryptionmethodisusedbytheUSfederalgovernmentasablockencryptionstandard

InthefollowingexamplewedemonstratehowtoencryptdatausingAESinGCMmode

Encryptanddecryptdata

225

packagemain

import(

cryptoaes

cryptocipher

cryptorand

errors

fmt

io

log

)

funcmain()

text=[]byte(MynameisAstaxie)

key=[]byte(the-key-has-to-be-32-bytes-long)

ciphertexterr=encrypt(textkey)

iferr=nil

TODOProperlyhandleerror

logFatal(err)

fmtPrintf(s=gtxntextciphertext)

plaintexterr=decrypt(ciphertextkey)

iferr=nil

TODOProperlyhandleerror

logFatal(err)

fmtPrintf(x=gtsnciphertextplaintext)

funcencrypt(plaintext[]bytekey[]byte)([]byteerror)

cerr=aesNewCipher(key)

iferr=nil

returnnilerr

gcmerr=cipherNewGCM(c)

iferr=nil

returnnilerr

nonce=make([]bytegcmNonceSize())

if_err=ioReadFull(randReadernonce)err=nil

returnnilerr

returngcmSeal(noncenonceplaintextnil)nil

funcdecrypt(ciphertext[]bytekey[]byte)([]byteerror)

cerr=aesNewCipher(key)

iferr=nil

returnnilerr

gcmerr=cipherNewGCM(c)

iferr=nil

returnnilerr

nonceSize=gcmNonceSize()

iflen(ciphertext)ltnonceSize

returnnilerrorsNew(ciphertexttooshort)

nonceciphertext=ciphertext[nonceSize]ciphertext[nonceSize]

returngcmOpen(nilnonceciphertextnil)

Encryptanddecryptdata

226

CallingtheabovefunctionaesNewCipher(whose[]bytekeyparametermustbe1624or32correspondingtotheAES-128AES-192orAES-256algorithmsrespectively)returnsacipherBlockInterfacethatimplementsthreefunctions

typeBlockinterface

BlockSizereturnstheciphersblocksize

BlockSize()int

Encryptencryptsthefirstblockinsrcintodst

Dstandsrcmaypointatthesamememory

Encrypt(dstsrc[]byte)

Decryptdecryptsthefirstblockinsrcintodst

Dstandsrcmaypointatthesamememory

Decrypt(dstsrc[]byte)

ThesethreefunctionsimplementencryptionanddecryptionoperationsseetheGodocumentationforamoredetailedexplanation

SummaryThissectiondescribesencryptionalgorithmswhichcanbeusedindifferentwaysaccordingtoyourwebapplicationsencryptionanddecryptionneedsForapplicationswithevenbasicsecurityrequirementsitisrecommendedtouseAESinGCMmode

LinksDirectoryPreviousstorepasswordsNextSummary

Encryptanddecryptdata

227

97SummaryInthischapterwevedescribedCSRFXSSandSQLinjectionbasedattacksMostwebapplicationsarevulnerabletothesetypesofattacksduetoalackofadequateinputfilteringonthepartoftheapplicationSoinadditiontointroducingtheprinciplesbehindtheseattackswevealsointroducedafewtechniquesforeffectivelyfilteringuserdataandpreventingtheseattacksfromevertakingplaceWethendiscussedafewmethodsforsecurelystoringuserpasswordsfirstintroducingbasicone-wayhashingforwebapplicationswithloosesecurityrequirementsthenpasswordsaltingandencryptionalgorithmsformoreseriousapplicationsFinallywebrieflydiscussedtwo-wayhashingandtheencryptionanddecryptionofsensitivedataWelearnedthattheGolanguageprovidespackagesforthreesymmetricencryptionalgorithmsbase64AESandDESThepurposeofthischapteristohelpreadersbecomemoreconsciousofthesecurityissuesthatexistinmoderndaywebapplicationsHopefullyitcanhelpdeveloperstoplananddesigntheirwebapplicationsalittlemorecarefullysotheycanwritesystemsthatareabletopreventhackersfromexploitinguserdataTheGolanguagehasalargeandwelldesignedanti-attacktoolkitandeveryGodevelopershouldtakefulladvantageofthesepackagestobettersecuretheirwebapplications

LinksDirectoryPrevioussectionEncryptanddecryptdataNextchapterInternationalizationandlocalization

Summary

228

10InternationalizationandlocalizationInordertoadapttotheincreasingglobalizationoftheinternetasdeveloperswemaysometimesneedtobuildmultilingualinternationalwebapplicationsThismeansthatsomepageswillappearindifferentlanguagesaccordingtouserregionsandperhapstheUIandUXwillalsobeadaptedtoshowdifferenteffectsbasedonlocalholidaysorcultureForexampleatruntimetheapplicationwillbeabletorecognizeandprocessrequestscomingfromdifferentgeographicalregionsandrenderpagesinthelocaldialectordisplaydifferentuserinterfaceAscompetentdeveloperswedontwanttohavetomanuallymodifyourapplicationssourcecodetocatertoeverypossibleregionoutthereWhenanapplicationneedstoaddsupportforanewlanguageweshouldbeabletosimplydropintheappropriatelanguagepackandbedonewithit

Inthissectionwellbetalkingaboutinternationalizationandlocalization(usuallyexpressedasi18nandL10Nrespectively)InternationalizationistheprocessofdesigningapplicationsthatareflexibleenoughtobeservedtomultipleregionsaroundtheworldInsomewayswecanthinkofinternationalizationassomethingthathelpstofacilitatelocalizationwhichistheadaptationofawebapplicationscontentanddesigntosuitthelanguageorculturalneedsofspecificlocales

CurrentlyGosstandardpackagedoesnotprovidei18nsupportbuttherearesomeusefulandrelativelysimplethird-partyimplementationsavailableInthischapterwellbeusingtheopen-sourcego-i18nlibrarytosupportinternationalizationinourexamples

WhenwetalkaboutmakingourwebapplicationsinternationalwemeanthateachwebpageshouldbeconstructedwithlocalespecificinformationandassembledwiththecorrespondinglocalstringstimeandcurrencyformatsetcThisinvolvesthreethings

1 howtodeterminetheuserslocale

2 howtosavestringsorotherinformationassociatedwiththelocale

3 howtoembedstringsandotherinformationaccordingtotheuserslocale

InthefirstsectionwelldescribehowtodetectandsetthecorrectlocaleinordertoallowwebsiteusersaccesstotheirlanguagespecificpagesThesecondsectiondescribeshowtohandleorstorestringscurrenciestimesdatesandotherlocalerelatedinformationFinallythethirdsectionwilldescribehowtointernationalizeyourwebapplicationmorespecificallywelldiscusshowtoreturndifferentpageswithlocaleappropriatecontentThroughthesethreesectionswellbeabletosupportfulli18ninourwebapplications

LinksDirectoryPreviousChapterChapter9SummaryNextsectionSettingthedefaultregion

Internationalizationandlocalization

229

101Settingthedefaultregion

FindingoutthelocaleAlocaleisasetofdescriptorsforaparticulargeographicalregionandcanincludespecificlanguagehabitstextformattingculturalidiomsandamultitudeofothersettingsAlocalesnameisusuallycomposedofthreepartsFirst(andmandatory)isthelocaleslanguageabbreviationsuchasenforEnglishorzhforChineseThesecondpartisanoptionalcountryspecifierandfollowsthefirstwithanminussignThisspecifierallowswebapplicationstodistinguishbetweendifferentcountrieswhichspeakthesamelanguagesuchasen-USforUSEnglishanden-GBforBritishEnglishThelastpartisanotheroptionalspecifierandisaddedtothelocalewithaperiodItspecifieswhichcharactersettouseforinstancezh-CNgb2312specifiesthegb2312charactersetforChinese

GodefaultstotheUTF-8encodingsetsoi18ninGoapplicationsdonotneedtoconsiderthelastparameterThusinourexampleswellonlyusethefirsttwopartsoflocaledescriptionsasourstandardi18nlocalenames

OnLinuxandSolarissystemsyoucanusethelocale-acommandtogetalistofallsupportedregionalnamesYoucanusethislistasexamplesofsomecommonlocalesForBSDandothersystemsthereisnolocalecommandbuttheregionalinformationisstoredinusrsharelocale

SettingthelocaleNowthatwevedefinedwhatalocaleisweneedtobeabletosetitaccordingtovisitingusersinformation(eitherfromtheirpersonalsettingsthevisiteddomainnameetc)Herearesomemethodswecanusetosettheuserslocale

Fromthedomainname

WecansetauserslocaleviathedomainnameitselfwhentheapplicationusesdifferentdomainsfordifferentregionsForexamplewecanusewwwastacomasourdefaultEnglishwebsiteandthedomainnamewwwastacnasitsChinesecounterpartBysettingupseparatedomainsforseparateregionsyoucandetectandservetherequestedlocaleThistypeofsetuphasseveraladvantages

IdentifyingthelocaleviaURLisdistinctiveandunambiguousUsersintuitivelyknowwhichdomainnamestovisitfortheirspecificregionorlanguageImplementingthisschemeinaGoapplicationisverysimpleandconvenientandcanbeachievedthroughamapConducivetosearchenginecrawlerswhichcanimprovethesitesSEO

Wecanusethefollowingcodetoimplementacorrespondingdomainnamelocale

ifrHost==wwwastacom

i18nSetLocale(en)

elseifrHost==wwwastacn

i18nSetLocale(zh-CN)

elseifrHost==wwwastatw

i18nSetLocale(zh-TW)

Alternativelywecouldhavealsosetlocalesthroughtheuseofsub-domainsuchasenastacomforEnglishsitesandcnastacomforChinesesiteThisschemecanberealizedincodeasfollows

Timezone

230

prefix=stringsSplit(rHost)

ifprefix[0]==en

i18nSetLocale(en)

elseifprefix[0]==cn

i18nSetLocale(zh-CN)

elseifprefix[0]==tw

i18nSetLocale(zh-TW)

Settinglocalesfromthedomainnameaswevedoneabovehasitsadvantageshoweverl10nisgenerallynotimplementedinthiswayFirstofallthecostofdomainnames(althoughusuallyquiteaffordableindividually)canquicklyaddupgiventhateachlocalewillneeditsowndomainnameandoftenthenameofthedomainwillnotnecessarilyfitinwiththelocalcontextSecondlywedontwanttohavetoindividuallyconfigureeachwebsiteforeachlocaleRatherweshouldbeabletodothisprogrammaticallyforinstancebyusingURLparametersLetshavealookatthefollowingdescription

FromURLparameters

Themostcommonwayofimplementingl10nistosetthedesiredlocaledirectlyintheURLparameterssuchwwwastacomhellolocale=zhorwwwastacomzhhelloThiswaywecansettheregionlikesoi18nSetLocale(params[locale])

ThissetuphasalmostalltheadvantagesofprependingthelocaleinfrontofthedomainanditsRESTfulsowedontneedtoaddadditionalmethodstoimplementitThedownsidetothisapproachisthatitrequiresacorrespondinglocaleparameterinsideeachlinkwhichcanbequitecumbersomeandmayincreasecomplexityHoweverwecanwriteagenericfunctionthatproducestheselocale-specificURLssothatalllinksaregeneratedthroughitThisfunctionshouldautomaticallyaddalocaleparametertoeachlinksowhenusersclickthemweareabletoparsetheirrequestswitheaselocale=params[locale]

PerhapswewantourURLstolookevenmoreRESTfulForexamplewecouldmapeachofourresourcesunderaspecificlocalelikewwwastacomenbooksforourEnglishsiteandwwwastacomzhbooksfortheChineseoneThisapproachisnotonlymoreconducivetoURLSEObutisalsomorefriendlyforusersAnybodyvisitingthesiteshouldbeabletoaccesslocale-specificwebsiteresourcesdirectlyfromtheURLSuchURLaddressescanthenbepassedthroughtheapplicationrouterinordertoobtaintheproperlocale(refertotheRESTsectionwhichdescribestherouterplug-inimplementation)

muxGet(localebookslistbook)

Fromtheclientsettingsarea

InsomespecialcaseswerequireexplicitclientinformationinordertosetthelocaleratherthanobtainingitfromtheURLorURLparametersThisinformationmaycomedirectlyfromtheclientsbrowsersettingstheusersIPaddressorthelocationsettingsfilledoutbytheuseratthetimeofregistrationThisapproachismoresuitableforweb-basedapplications

Accept-Language

WhenaclientrequestsinformationusinganHTTPheadersetwiththeAccept-LanguagefieldwecanusethefollowingGocodetoparsetheheaderandsettheappropriateregioncode

AL=rHeaderGet(Accept-Language)

ifAL==en

i18nSetLocale(en)

elseifAL==zh-CN

i18nSetLocale(zh-CN)

elseifAL==zh-TW

i18nSetLocale(zh-TW)

Ofcourseinrealworldapplicationswemayrequiremorerigorousprocessesandrulesforsettinguserregions

Timezone

231

IPAddress

AnotherwayofsettingaclientsregionistolookattheusersIPaddressWecanusethepopularGeoIPGeoLiteCountryorCitylibrariestohelpusrelateuserIPaddressestotheircorrespondingregionalareasImplementingthismechanismisverysimpleweonlyneedtolookuptheusersIPaddressinsideourdatabaseandthenreturnlocale-specificcontentaccordingtowhichregionwasreturned

Userprofile

Youcanalsoletusersprovideyouwiththeirlocaleinformationthroughaninputelementsuchasadrop-downmenu(orsomethingsimilar)WhenwereceivethisinformationwecansaveittotheaccountassociatedwiththeusersprofileWhentheuserlogsinagainwewillbeabletocheckandsettheirlocalesettings-thisguaranteesthateverytimetheuseraccessesthewebsitethereturnedcontentwillbebasedontheirpreviouslysetlocale

SummaryInthissectionwevedemonstratedavarietyofwayswithwhichuserspecificlocalescanbedetectedandsetThesemethodsincludedsettingtheuserlocaleviadomainnamesubdomainnameURLparametersanddirectlyfromclientsettingsBycateringtothespecificneedsofspecificregionswecanprovideacomfortablefamiliarandintuitiveenvironmentforuserstoaccesstheservicesthatweprovide

LinksDirectoryPreviousoneInternationalizationandlocalizationNextsectionLocalizedresources

Timezone

232

102LocalizedResourcesTheprevioussectiondescribedhowtosetlocalesAfterthelocalehasbeensetwethenneedtoaddresstheproblemofstoringtheinformationcorrespondingtospecificlocalesThisinformationcanincludetextualcontenttimeanddatecurrencyvaluespicturesspecificfilesandotherviewresourcesInGoallofthiscontextualinformationisstoredinJSONformatonourbackendtobecalleduponandinjectedintoourviewswhenusersfromspecificregionsvisitourwebsiteForexampleEnglishandChinesecontentwouldbestoredinenjsonandzh-CNjsonfilesrespectively

LocalizedtextualcontentPlaintextisthemostcommonwayofrepresentinginformationinwebapplicationsandthebulkofyourlocalizedcontentwilllikelytakethisformThegoalistoprovidetextualcontentthatisbothidiomatictoregionalexpressionsandfeelsnaturalforforeignusersofyoursiteOnesolutionistocreateanestedmapoflocalesnativelanguagestringsandtheirlocalcounterpartsWhenclientsrequestpageswithsometextualcontentwefirstchecktheirdesiredlocalethenretrievethecorrespondingstringsfromtheappropriatemapThefollowingsnippetisasimpleexampleofthisprocess

packagemain

importfmt

varlocalesmap[string]map[string]string

funcmain()

locales=make(map[string]map[string]string2)

en=make(map[string]string10)

en[pea]=pea

en[bean]=bean

locales[en]=en

cn=make(map[string]string10)

cn[pea]=豌豆

cn[bean]=毛豆

locales[zh-CN]=cn

lang=zh-CN

fmtPrintln(msg(langpea))

fmtPrintln(msg(langbean))

funcmsg(localekeystring)string

ifvok=locales[locale]ok

ifv2ok=v[key]ok

returnv2

return

Theaboveexamplesetsupmapsoftranslatedstringsfordifferentlocales(inthiscasetheChineseandEnglishlocales)WemapourcntranslationstothesameEnglishlanguagekeyssothatwecanreconstructourEnglishtextmessageinChineseIfwewantedtoswitchourtexttoanyotherlocalewemayhaveimplementeditdbeasimplematterofsettingonelangvariable

Simplekey-valuesubstitutionscansometimesbeinadequateforourneedsForexampleifwehadaphrasesuchasIam30yearsoldwhere30isavariablehowwouldwelocalizeitIncaseslikethesewecancombineusethefmtPrintffunctiontoachievethedesiredresult

en[howold]=Iamdyearsold

cn[howold]=我今年d岁了

fmtPrintf(msg(langhowold)30)

Localizedresources

233

TheexamplecodeaboveisonlyforthepurposeofdemonstrationactuallocaledataistypicallystoredinJSONformatinourdatabaseallowingustoexecuteasimplejsonUnmarshaltopopulatemaplocaleswithourstringtranslations

LocalizeddateandtimeBecauseofourtimezoneconventionsthetimeinoneregionoftheworldcanbedifferentthanthetimeinanotherregionSimilarlythewayinwhichtimeisrepresentedcanalsovaryfromlocaletolocaleForexampleaChineseenvironmentmayread2012年10月24日星期三23时11分13秒CSTwhileinEnglishitmightbeWedOct24231113CST2012NotonlyaretherevariationsinlanguagebuttherearedifferencesinformattingalsoSowhenitcomestolocalizingdatesandtimesweneedtoaddressthefollowingtwopoints

1 timezones2 formattingissues

The$GOROOTlibtimepackagetimeinfozipdirectorycontainslocalescorrespondingtotimezonedefinitionsInordertoobtainthetimecorrespondingtoauserscurrentlocaleweshouldfirstusetimeLoadLocation(namestring)togetaLocationobjectcorrespondingtoourlocalepassinginastringrepresentingthelocalesuchasAsiaShanghaiorAmericaChicagoWecanthenusethisLocationobjectinconjunctionwithaTimeobject(obtainedbycallingtimeNow)togetthefinaltimeusingtheTimeobjectsInmethodAdetailedlookatthisprocesscanbeseenbelow(thisexampleusessomeofthevariablesfromtheexampleabove)

en[time_zone]=AmericaChicago

cn[time_zone]=AsiaShanghai

loc_=timeLoadLocation(msg(langtime_zone))

t=timeNow()

t=tIn(loc)

fmtPrintln(tFormat(timeRFC3339))

Wecanhandletextformattinginasimilarwaytosolveourtimeformattingproblem

en[date_format]=Y-m-dHMS

cn[date_format]=Y年m月d日H时M分S秒

fmtPrintln(date(msg(langdate_format)t))

funcdate(fomatstringttimeTime)string

yearmonthday=tDate()

hourminsec=tClock()

ParsingthecorrespondingYmdHMSandthenreturningtheinformation

Yreplacedby2012

mreplacedby10

dreplacedby24

LocalizedcurrencyvalueObviouslycurrencydiffersfromregiontoregionalsoWecantreatitthesamewaywetreatedourdates

en[money]=USDd

cn[money]=¥d元

fmtPrintln(date(msg(langdate_format)100))

funcmoney_format(fomatstringmoneyint64)string

returnfmtSprintf(fomatmoney)

Localizedresources

234

LocalizationofviewsandresourcesWecanservecustomizedviewswithdifferentimagescssjsandotherstaticresourcesdependingonthecurrentlocaleOnewaytoaccomplishthisisbyorganizingthesefilesintotheirrespectivelocalesHeresanexample

views

|--enEnglishTemplates

|--imagesstorepictureinformation

|--jsJSfiles

|--cssCSSfiles

indextplUserHome

logintplLogHome

|--zh-CNChineseTemplates

|--images

|--js

|--css

indextpl

logintpl

Withthisdirectorystructurewecanrenderlocale-specificviewslikeso

s1_=templateParseFiles(views+lang+indextpl)

VVLang=lang

s1Execute(osStdoutVV)

Theresourcesreferencedintheindextplfilecanbedealtwithasfollows

jsfile

ltscripttype=textjavascriptsrc=viewsVVLangjsjqueryjquery-180minjsgtltscriptgt

cssfile

ltlinkhref=viewsVVLangcssbootstrap-responsivemincssrel=stylesheetgt

Picturefiles

ltimgsrc=viewsVVLangimagesbtnpnggt

Withdynamicviewsandthewaywevelocalizedourresourceswewillbeabletoaddmorelocaleswithoutmucheffort

SummaryThissectiondescribedhowtouseandstorelocalresourcesWelearnedthatwecanuseconversionfunctionsandstringinterpolationforthisandsawthatmapscanbeaneffectivewayofstoringlocale-specificdataForthelatterwecouldsimplyextractthecorrespondinglocaleinformationwhenneeded-ifitwastextualcontentwedesiredourmappedtranslationsandidiomscouldbepipeddirectlytotheoutputIfitwassomethingmoresophisticatedliketimeorcurrencywesimplyusedthefmtPrintffunctiontoformatitbefore-handLocalizingourviewsandresourceswastheeasiestcaseandsimplyinvolvedorganizingourfilesintotheirrespectivelocalesthenreferencingthemfromtheirlocalerelativepaths

LinksDirectoryPrevioussectionSettingthedefaultregionNextsectionInternationalsites

Localizedresources

235

103InternationalsitesTheprevioussectionexplainedhowtodealwithlocalizedresourcesnamelybyusinglocaleconfigurationfilesSowhatcanwedoifweneedtodealwithmultiplelocalizedresourcesliketexttranslationstimesanddatesnumbersetcThissectionwilladdresstheseissuesonebyone

ManagingmultiplelocalepackagesInthedevelopmentofanapplicationoftenthefirstthingyouneedtodoistodecidewhetherornotyouwanttosupportmorethanonelanguageIfyoudodecidetosupportmultiplelanguagesyoullneedtodevelopanorganizationalstructuretofacilitatetheprocessofaddingmorelanguagesinthefutureOnewaywecandothisistoputallourrelatedlocalefilestogetherinaconfiglocalesdirectoryorsomethingofthelikeLetssupposeyouwanttosupportbothChineseandEnglishInthiscaseyoudbeplacingboththeenjsonandzhjsonlocalefilesintotheaforementionedfolderTheircontentswouldprobablylooksomethinglikethefollowing

zhjson

zh

submit提交

create创建

enjson

en

submitSubmit

createCreate

Wedecidedtousesome3rdpartyGopackagestohelpusinternationalizeourwebapplicationsInthecaseofgo-i18n(Amoreadvancedi18npackagecanbefoundhere)wefirsthavetoregisterourconfiglocalesdirectorytoloadallofourlocalefiles

Tr=i18nNewLocale()

TrLoadPath(configlocales)

ThispackageissimpletouseWecantestthatitworkslikeso

fmtPrintln(TrTranslate(submit))

Outputsubmit

TrSetLocale(zn)

fmtPrintln(TrTranslate(submit))

Outputs递交

AutomaticallyloadlocalpackageWevejustdescribedhowtoautomaticallyloadcustomlanguagepacksInfactthego-i18nlibrarycomespre-loadedwithabunchofdefaultformattinginformationsuchastimeandcurrencyformatsThesedefaultconfigurationscanbeoverriddenandcustomizedbyuserstosuittheirneedsConsiderthefollowingprocess

Internationalsites

236

Loadthedefaultconfigurationfileswhichareplacedbelowin`go-i18nlocales`

Fileshouldbenamedzhjsonen-jsonen-USjsonetcsowecancontinuouslysupportmorelanguages

func(ilIL)loadDefaultTranslations(dirPathstring)error

direrr=osOpen(dirPath)

iferr=nil

returnerr

deferdirClose()

nameserr=dirReaddirnames(-1)

iferr=nil

returnerr

for_name=rangenames

fullPath=pathJoin(dirPathname)

fierr=osStat(fullPath)

iferr=nil

returnerr

iffiIsDir()

iferr=illoadTranslations(fullPath)err=nil

returnerr

elseiflocale=ilmatchingLocaleFromFileName(name)locale=

fileerr=osOpen(fullPath)

iferr=nil

returnerr

deferfileClose()

iferr=illoadTranslation(filelocale)err=nil

returnerr

returnnil

Usingtheabovecodetoloadallofourdefaulttranslationswecanthenusethefollowingcodetoselectandusealocale

fmtPrintln(TrTime(timeNow()))

Output2009年1月08日星期四203758CST

fmtPrintln(TrTime(timeNow()long))

Output2009年1月08日

fmtPrintln(TrMoney(1111))

Outputyen1111

TemplatemapfuncAbovewevepresentedonewayofmanagingandintegratinganumberoflanguagepacksSomeofthefunctionsweveimplementedarebasedonthelogicallayerforexampleTrTranslateTrTimeTrMoneyandsoonInthelogicallayerwecanusethesefunctions(aftersupplyingtherequiredparameters)forapplyingyourtranslationsoutputtingtheresultsdirectlytothetemplatelayeratrendertimeWhatcanwedoifwewanttousethesefunctionsdirectlyinthetemplatelayerIncaseyouveforgottenearlierinthebookwementionedthatGotemplatessupportcustomtemplatefunctionsThefollowingcodeshowshoweasymapfuncistoimplement

1textinformation

Internationalsites

237

AsimpletextconversionfunctionimplementingamapfunccanbeseenbelowItusesTrTranslatetoperformtheappropriatetranslations

funcI18nT(argsinterface)string

ok=false

varsstring

iflen(args)==1

sok=args[0](string)

ifok

s=fmtSprint(args)

returnTrTranslate(s)

Weregisterthefunctionlikeso

tFuncs(templateFuncMapTI18nT)

Thenuseitfromyourtemplate

VSubmit|T

1 Thedateandtime

DatesandtimescalltheTrTimefunctiontoperformtheirtranslationsThemapfuncisimplementedasfollows

funcI18nTimeDate(argsinterface)string

ok=false

varsstring

iflen(args)==1

sok=args[0](string)

ifok

s=fmtSprint(args)

returnTrTime(s)

Registerthefunctionlikeso

tFuncs(templateFuncMapTDI18nTimeDate)

Thenuseitfromyourtemplate

VNow|TD

3CurrencyInformation

CurrenciesusetheTrMoneyfunctiontoconvertmoneyThemapFuncisimplementedasfollows

Internationalsites

238

funcI18nMoney(argsinterface)string

ok=false

varsstring

iflen(args)==1

sok=args[0](string)

ifok

s=fmtSprint(args)

returnTrMoney(s)

Registerthefunctionlikeso

tFuncs(templateFuncMapMI18nMoney)

Thenuseitfromyourtemplate

VMoney|M

SummaryInthissectionwelearnedhowtoimplementmultiplelanguagepacksinourwebapplicationsWesawthatthroughcustomlanguagepackswecannotonlyeasilyinternationalizeourapplicationsbutfacilitatetheadditionofotherlanguagesalso(throughtheuseofaconfigurationfile)Bydefaultthego-i18npackagewillprovidesomecommonconfigurationsfortimecurrencyetcwhichcanbeveryconvenienttouseWelearnedthatthesefunctionscanalsobeuseddirectlyfromourtemplatesusingmappingfunctionseachtranslatedstringcanbepipeddirectlytoourtemplatesThisenablesourwebapplicationstoaccommodatemultiplelanguageswithminimaleffort

LinksDirectoryPrevioussectionLocalizedresourcesNextsectionSummary

Internationalsites

239

104SummaryThroughthisintroductorychapteroni18nyoushouldnowbefamiliarwithsomeofthestepsandprocessesthatarenecessaryforinternationalizingandlocalizingyourwebsitesIvealsointroducedanopensourcesolutionfori18ninGogo-i18nUsingthisopensourcelibrarywecaneasilyimplementmulti-languageversionsofourwebapplicationsThisallowsourapplicationstobeflexibleandresponsivetolocalaudiencesallaroundtheworldIfyoufindanerrorinthisopensourcelibraryoranymissingfeaturespleaseopenanissueorapullrequestLetsstrivetomakeitoneofGosstandardlibraries

LinksDirectoryPrevioussectionInternationalsitesNextchapterErrorhandlingdebuggingandtesting

Summary

240

11ErrorHandlingDebuggingandTestingWeoftenseethemajorityofaprogrammersprogrammingtimespentoncheckingforbugsandworkingonbugfixesWhetheryouarerefactoringcodeorre-configuringsystemsmuchofyourtimewillundoubtedlybespenttroubleshootingandtestingFromtheoutsidepeoplemaythinkthatallwedoasprogrammersisdesignoursystemsandthenwriteourcodeTheymightthinkthatwehavetheidealjobWedoworkthatisveryengagingandimplementsystemsthathaveneverbeendonebeforeWhilethislastpartmaybetruewhattheydontknowisthatwespendthemajorityofourtimecyclingbetweentroubleshootingdebuggingandtestingourcodeOfcourseifyouhavegoodprogramminghabitsandthetechnologicalsolutionstohelpyoutakeonthesetasksthenyoucanminimizethetimespentdoingthesethingsenablingyoutofocusinsteadonmorevaluablethingsliketheapplicationlogic

UnfortunatelymanyprogrammersarenotthoroughinfulfillingtheirerrorhandlingdebuggingandtestingresponsibilitiesbeforehandInexperiencedprogrammerswilloftenonlymakeanefforttofinderrorsandflawsaftertheyhaveoccurredspendinghourslocatingandfixingproblemsaftertheapplicationisalreadyonlineItsgoodpractice(andprobablycommonsense)thatweshoulddesignourapplicationswithpropererrorhandlingtestcasesetcfromthegetgoThiswillmakeyourjobandthejobsofalltheotherdeveloperswhomaybeworkingonyourapplicationsomedaymucheasierwhentheyinevitablyneedtomodifythecodeorupgradethesystem

IntheprocessofdevelopingwebapplicationsyouwillinevitablyencounterunforeseenerrorsWhatsthemostefficientwayoffindingthecausesoftheseerrorsandsolvingthemSection111describeshowtohandleerrorsintheGolanguageaswellashowtodesignyourownerrorhandlingpackageandfunctionsSection112describeshowtouseGDBtodebugprogramsunderdynamicoperatingconditionsdependingonavarietyofvariableinformationWethendiscussapplicationmonitoringanddebuggingoperations

Section113willexplainunittestinginGoandfeaturesomein-depthdiscussionsandexamplesonhowtowriteunittestsaswellasdefiningGosunittestingrulesWellseehowfollowingtheseruleswillensurethatwhenupgradingormodifyingyourapplicationthetestcodewillbeabletorunsmoothly

ManyprogrammersavoidspendingtimetolearnandcultivategooddebuggingandtestinghabitsThischaptertakesontheseissueshead-onsoyouwonthavetorunawayfromthesetasksanylongerSinceyourejustlearninghowtobuildwebapplicationsinGoletsusethisopportunitytoestablishthesegoodhabitsfromtheverybeginning

LinksDirectoryPreviouschapterChapter10summaryNextsectionErrorhandling

Errorhandlingdebuggingandtesting

241

111ErrorhandlingGosmajordesignconsiderationsarerootedinthefollowingideasasimpleclearandconcisesyntax(similartoC)andstatementswhichareexplicitanddontcontainanyhiddenorunexpectedthingsGoserrorhandlingschemereflectsalloftheseprinciplesinthewaythatitsimplementedIfyourefamiliarwiththeClanguageyoullknowthatitscommontoreturn-1orNULLvaluestoindicatethatanerrorhasoccurredHoweveruserswhoarenotfamiliarwithCsAPIwillnotknowexactlywhatthesereturnvaluesmeanInCitsnotexplicitwhetheravalueof0indicatessuccessoffailureOntheotherhandGoexplicitlydefinesatypecallederrorforthesolepurposeofexpressingerrorsWheneverafunctionreturnswechecktoseewhethertheerrorvariableisnilornottodetermineiftheoperationwassuccessfulForexampletheosOpenfunctionfailsitwillreturnanon-nilerrorvariable

funcOpen(namestring)(fileFileerrerror)

HeresanexampleofhowwedhandleanerrorinosOpenFirstweattempttoopenafileWhenthefunctionreturnswechecktoseewhetheritsucceededornotbycomparingtheerrorreturnvaluewithnilcallinglogFataltooutputanerrormessageifitsanon-nilvalue

ferr=osOpen(filenameext)

iferr=nil

logFatal(err)

SimilartotheosOpenfunctionthefunctionsinGosstandardpackagesallreturnerrorvariablestofacilitateerrorhandlingThissectionwillgointodetailaboutthedesignoferrortypesanddiscusshowtoproperlyhandleerrorsinwebapplications

Errortypeerrorisaninterfacetypewiththefollowingdefinition

typeerrorinterface

Error()string

errorisabuilt-ininterfacetypeWecanfinditsdefinitioninthebuiltinpackagebelowWealsohavealotofinternalpackageswhichuseerrorinaprivatestructurecallederrorStringwhichimplementstheerrorinterface

errorStringisatrivialimplementationoferror

typeerrorStringstruct

sstring

func(eerrorString)Error()string

returnes

YoucanconvertaregularstringtoanerrorStringthrougherrorsNewinordertogetanobjectthatsatisfiestheerrorinterfaceItsinternalimplementationisasfollows

Newreturnsanerrorthatformatsasthegiventext

funcNew(textstring)error

returnamperrorStringtext

Errorhandling

242

ThefollowingexampledemonstrateshowtouseerrorsNew

funcSqrt(ffloat64)(float64error)

ifflt0

return0errorsNew(mathsquarerootofnegativenumber)

implementation

InthefollowingexamplewepassanegativenumbertoourSqrtfunctionCheckingtheerrvariablewecheckwhethertheerrorobjectisnon-nilusingasimplenilcomparisonTheresultofthecomparisonistruesofmtPrintln(thefmtpackagecallstheerrormethodwhendealingwitherrorcalls)iscalledtooutputanerror

ferr=Sqrt(-1)

iferr=nil

fmtPrintln(err)

CustomErrorsThroughtheabovedescriptionweknowthatagoErrorisaninterfaceBydefiningastructthatimplementsthisinterfacewecanimplementtheirerrordefinitionsHeresanexamplefromtheJSONpackage

typeSyntaxErrorstruct

msgstringerrordescription

Offsetint64wheretheerroroccurred

func(eSyntaxError)Error()stringreturnemsg

TheerrorsOffsetfieldwillnotbeprintedatruntimewhensyntaxerrorsoccurbutusingatypeassertionerrortypeyoucanprintthedesirederrormessage

iferr=decDecode(ampval)err=nil

ifserrok=err(jsonSyntaxError)ok

linecol=findLine(fserrOffset)

returnfmtErrorf(sddvfName()linecolerr)

returnerr

ItshouldbenotedthatwhenthefunctionreturnsacustomerrorthereturnvalueissettotherecommendedtypeoferrorratherthanacustomerrortypeBecarefulnottopre-declarevariablesofcustomerrortypesForexample

funcDecode()SyntaxError

errorwhichmayleadtothecallerserr=nilcomparisontoalwaysbetrue

varerrSyntaxErrorpre-declareerrorvariable

ifanerrorcondition

err=ampSyntaxError

returnerrerrorerralwaysequalnon-nilcausescallerserr=nilcomparisontoalwaysbetrue

Seehttpgolangorgdocfaqnil_errorforanindepthexplanation

TheaboveexampleshowshowtoimplementasimplecustomErrortypeButwhatifweneedmoresophisticatederrorhandlingInthiscasewehavetorefertothenetpackageapproach

Errorhandling

243

packagenet

typeErrorinterface

error

Timeout()boolIstheerroratimeout

Temporary()boolIstheerrortemporary

UsingtypeassertionwecancheckwhetherornotourerrorisoftypenetErrorasshowninthefollowingexampleThisallowsustorefineourerrorhandling-ifatemporaryerroroccursonthenetworkitwillsleepfor1secondthenretrytheoperation

ifnerrok=err(netError)okampampnerrTemporary()

timeSleep(1e9)

continue

iferr=nil

logFatal(err)

ErrorhandlingGohandleserrorsandchecksthereturnvaluesoffunctionsinaC-likefashionwhichisdifferenttohowmostoftheothermajorlanguagesdoThismakesthecodemoreexplicitandpredictablebutalsomoreverboseToreducetheredundancyofourerror-handlingcodewecanuseabstracterrorhandlingfunctionsthatallowustoimplementsimilarerrorhandlingbehaviour

funcinit()

httpHandleFunc(viewviewRecord)

funcviewRecord(whttpResponseWriterrhttpRequest)

c=appengineNewContext(r)

key=datastoreNewKey(cRecordrFormValue(id)0nil)

record=new(Record)

iferr=datastoreGet(ckeyrecord)err=nil

httpError(werrError()500)

return

iferr=viewTemplateExecute(wrecord)err=nil

httpError(werrError()500)

TheaboveexampledemonstratehowthedataaccessandtemplatecallhasdetectedanerrorWhenanerroroccursacalltounifiedhandlerhttpErrorreturnsa500errorcodetotheclientanddisplaysthecorrespondingerrordataButwhenmoreandmoreHandleFunccallsaremadesoerror-handlinglogiccodewillincreaseWecancustomizetheroutertoreducecode(refertothethirdchapterofHTTPformoredetail)

typeappHandlerfunc(httpResponseWriterhttpRequest)error

func(fnappHandler)ServeHTTP(whttpResponseWriterrhttpRequest)

iferr=fn(wr)err=nil

httpError(werrError()500)

AbovewevedefinedacustomrouterWecanthenregisterourhandlerasusual

Errorhandling

244

funcinit()

httpHandle(viewappHandler(viewRecord))

Theviewhandlercanthenbehandledbythefollowingcodeitisalotsimplerthanouroriginalimplementationisntit

funcviewRecord(whttpResponseWriterrhttpRequest)error

c=appengineNewContext(r)

key=datastoreNewKey(cRecordrFormValue(id)0nil)

record=new(Record)

iferr=datastoreGet(ckeyrecord)err=nil

returnerr

returnviewTemplateExecute(wrecord)

Theerrorhandlerexampleabovewillreturnthe500InternalErrorcodetouserswhenanyerrorsoccurinadditiontoprintingoutthecorrespondingerrorcodeInfactwecancustomizethetypeoferrorreturnedtooutputamoredeveloperfriendlyerrormessagewithinformationthatisusefulfordebugginglikeso

typeappErrorstruct

Errorerror

Messagestring

Codeint

Ourcustomroutercanbechangedaccordingly

typeappHandlerfunc(httpResponseWriterhttpRequest)appError

func(fnappHandler)ServeHTTP(whttpResponseWriterrhttpRequest)

ife=fn(wr)e=nileisappErrornotosError

c=appengineNewContext(r)

cErrorf(veError)

httpError(weMessageeCode)

Afterwevefinishedmodifyingourcustomerrorourlogiccanbechangedasfollows

funcviewRecord(whttpResponseWriterrhttpRequest)appError

c=appengineNewContext(r)

key=datastoreNewKey(cRecordrFormValue(id)0nil)

record=new(Record)

iferr=datastoreGet(ckeyrecord)err=nil

returnampappErrorerrRecordnotfound404

iferr=viewTemplateExecute(wrecord)err=nil

returnampappErrorerrCantdisplayrecord500

returnnil

AsshownabovewecanreturndifferenterrorcodesanderrormessagesinourviewsdependingonthesituationAlthoughthisversionofourcodefunctionssimilarlytothepreviousversionitsmoreexplicitanditserrormessagepromptsaremorecomprehensibleAllofthesefactorscanhelptomakeyourapplicationmorescalableascomplexityincreases

Summary

Errorhandling

245

FaulttoleranceisaveryimportantaspectofanyprogramminglanguageInGoitisachievedthrougherrorhandlingAlthoughErrorisonlyoneinterfaceitcanhavemanyvariationsinthewaythatitsimplementedandwecancustomizeitaccordingtoourneedsonacasebycasebasisByintroducingthesevariouserrorhandlingconceptswehopethatyouwillhavegainedsomeinsightonhowtoimplementbettererrorhandlingschemesinyourownwebapplications

LinksDirectoryPrevioussectionErrorhandlingdebuggingandtestingNextsectionDebuggingbyusingGDB

Errorhandling

246

112DebuggingwithGDBDuringthedevelopmentprocessofanyapplicationdeveloperswillalwaysneedtoperformsomekindofcodedebuggingPHPPythonandmostoftheotherdynamiclanguagesareabletobemodifiedatruntimeaslongasthemodificationsdonotexplicitlyneedtobecompiledWecaneasilyprintdataindynamicoperatingenvironmentsoutputtingourchangesandprintingvariableinformationdirectlyInGoyoucanofcoursespeckleyourcodewithPrintlnsbefore-handtodisplayvariableinformationfordebuggingpurposesbutanychangestoyourcodeneedtoberecompiledeverytimeThiscanquicklybecomecumbersomeIfyouveprogrammedinPythonorJavascriptyoullknowthattheformerprovidestoolssuchaspdbandipdbfordebuggingandthelatterhassimilartoolsthatareabletodynamicallydisplayvariableinformationandfacilitatesingle-stepdebuggingFortunatelyGohasnativesupportforasimilartoolwhichprovidessuchdebuggingfeaturesGDBThissectionservesasabriefintroductionintodebuggingGoapplicationsusingGDB

GDBdebuggingprofileGDBisapowerfuldebuggingtooltargetingUNIX-likesystemsreleasedbytheFSF(FreeSoftwareFoundation)GDBallowsustodothefollowingthings

1 Initialsettingscanbecustomizeaccordingtothespecificrequirementsofyourapplication2 Canbesetsothattheprogrambeingdebuggedinthedevelopersconsolestopsattheprescribedbreakpoints

(breakpointscanbeconditionalexpressions)3 Whentheprogramhasbeenstoppedyoucancheckitscurrentstatetoseewhathappened4 Dynamicallychangethecurrentprogramsexecutionenvironment

TodebugyourGoapplicationsusingGDBtheversionofGDByouusemustbegreaterthan71

WhencompilingGoprogramsthefollowingpointsrequireparticularattention

1 Using-ldflags-swillpreventthestandarddebugginginformationfrombeingprinted2 Using-gcflags-N-lwillpreventGofromperformingsomeofitsautomatedoptimizations-optimizationsof

aggregatevariablesfunctionsetcTheseoptimizationscanmakeitverydifficultforGDBtodoitsjobsoitsbesttodisablethematcompiletimeusingtheseflags

SomeofGDBsmostcommonlyusedcommandsareasfollows

list

AlsousedinitsabbreviatedformllistisusedtodisplaythesourcecodeBydefaultitdisplaystenlinesofcodeandyoucanspecifythelineyouwishtodisplayForexamplethecommandlist15displaystenlinesofcodecenteredaroundline15asshownbelow

10timeSleep(2timeSecond)

11clt-i

12

13close(c)

14

15

16funcmain()

17msg=Startingmain

18fmtPrintln(msg)

19bus=make(chanint)

break

AlsousedinitsabbreviatedformbbreakisusedtosetbreakpointsandtakesasanargumentthatdefineswhichpointtosetthebreakpointatForexampleb10setsabreakpointatthetenthrow

delete

DebuggingbyusingGDB

247

AlsousedinitsabbreviatedformddeleteisusedtodeletebreakpointsThebreakpointissetfollowedbytheserialnumberTheserialnumbercanbeobtainedthroughtheinfobreakpointscommandBreakpointssetwiththeircorrespondingserialnumbersaredisplayedasfollowstosetabreakpointnumber

NumTypeDispEnbAddressWhat

2breakpointkeepy0x0000000000400dc3inmainmainathomexiemengjungdbgo23

breakpointalreadyhit1time

backtrace

Abbreviatedasbtthiscommandisusedtoprinttheexecutionofthecodeforinstance

0mainmain()athomexiemengjungdbgo23

10x000000000040d61einruntimemain()athomexiemengjungosrcpkgruntimeprocc244

20x000000000040d6c1inschedunlock()athomexiemengjungosrcpkgruntimeprocc267

30x0000000000000000in()

info

TheinfocommandcanbeusedinconjunctionwithseveralparameterstodisplayinformationThefollowingparametersarecommonlyused

infolocals

Displaysthecurrentlyexecutingprogramsvariablevalues

infobreakpoints

Displaysalistofcurrentlysetbreakpoints

infogoroutines

Displaysthecurrentlistofrunninggoroutinesasshowninthefollowingcodewiththeindicatingthecurrentexecution

1runningruntimegosched

2syscallruntimeentersyscall

3waitingruntimegosched

4runnableruntimegosched

print

AbbreviatedaspthiscommandisusedtoprintvariablesorotherinformationIttakesasargumentsthevariablenamestobeprintedandofcoursetherearesomeveryusefulfunctionssuchas$len()and$cap()thatcanbeusedtoreturnthelengthorcapacityofthecurrentstringsslicesormaps

whatis

whatisisusedtodisplaythecurrentvariabletypefollowedbythevariablenameForinstancewhatismsgwilloutputthefollowing

type=structstring

next

Abbreviatedasnnextisusedinsingle-stepdebuggingtoskiptothenextstepWhenthereisabreakpointyoucanenterntojumptothenextsteptocontinue

continue

AbbreviatedasccontinueisusedtojumpoutofthecurrentbreakpointandcanbefollowedbyaparameterNwhichspecifiesthenumberoftimestoskipthebreakpoint

setvariable

DebuggingbyusingGDB

248

ThiscommandisusedtochangethevalueofavariableintheprocessItcanbeusedlikesosetvariableltvargt=ltvaluegt

ThedebuggingprocessNowletstakealookatthefollowingcodetoseehowGDBistypicallyusedtodebugGoprograms

packagemain

import(

fmt

time

)

funccounting(cchanlt-int)

fori=0ilt10i++

timeSleep(2timeSecond)

clt-i

close(c)

funcmain()

msg=Startingmain

fmtPrintln(msg)

bus=make(chanint)

msg=startingagofunc

gocounting(bus)

forcount=rangebus

fmtPrintln(countcount)

Nowwecompilethefilecreatinganexecutablefilecalledgdbfile

gobuild-gcflags-N-lgdbfilego

UsetheGDBcommandtostartdebugging

gdbgdbfile

AfterfirststartingGDByoullhavetoentertheruncommandtoseeyourprogramrunningYouwillthenseetheprogramoutputthefollowingexecutingtheprogramdirectlyfromthecommandlinewilloutputexactlythesamething

(gdb)run

Startingprogramhomexiemengjungdbfile

Startingmain

count0

count1

count2

count3

count4

count5

count6

count7

count8

count9

[LWP2771exited]

[Inferior1(process2771)exitednormally]

Oknowthatweknowhowtogettheprogramupandrunningletstakealookatsettingbreakpoints

DebuggingbyusingGDB

249

(gdb)b23

Breakpoint1at0x400d8dfilehomexiemengjungdbfilegoline23

(gdb)run

Startingprogramhomexiemengjungdbfile

Startingmain

[NewLWP3284]

[SwitchingtoLWP3284]

Breakpoint1mainmain()athomexiemengjungdbfilego23

23fmtPrintln(countcount)

Intheaboveexampleweusetheb23commandtosetabreakpointonline23ofourcodethenenterruntostarttheprogramWhenourprogramstopsatourbreakpointwetypicallyneedtolookatthecorrespondingsourcecodecontextEnteringthelistcommandintoourGDBsessionwecanseethefivelinesofcodeprecedingourbreakpoint

(gdb)list

18fmtPrintln(msg)

19bus=make(chanint)

20msg=startingagofunc

21gocounting(bus)

22forcount=rangebus

23fmtPrintln(countcount)

24

25

NowthatGDBisrunningthecurrentprogramenvironmentwehaveaccesstosomeusefuldebugginginformationthatwecanprintoutToseethecorrespondingvariabletypesandvaluestypeinfolocals

(gdb)infolocals

count=0

bus=0xf840001a50

(gdb)pcount

$1=0

(gdb)pbus

$2=(chanint)0xf840001a50

(gdb)whatisbus

type=chanint

Tolettheprogramcontinueitsexecutionuntilthenextbreakpointentertheccommand

(gdb)c

Continuing

count0

[NewLWP3303]

[SwitchingtoLWP3303]

Breakpoint1mainmain()athomexiemengjungdbfilego23

23fmtPrintln(countcount)

(gdb)c

Continuing

count1

[SwitchingtoLWP3302]

Breakpoint1mainmain()athomexiemengjungdbfilego23

23fmtPrintln(countcount)

AftereachcthecodewillexecuteoncethenjumptothenextiterationoftheforloopItwillofcoursecontinuetoprintouttheappropriateinformation

LetssaythatyouneedtochangethecontextvariablesinthecurrentexecutionenvironmentskiptheprocessthencontinuetothenextstepYoucandosobyfirstusinginfolocalstogetthevariablestatesthenthesetvariablecommandtomodifythem

DebuggingbyusingGDB

250

(gdb)infolocals

count=2

bus=0xf840001a50

(gdb)setvariablecount=9

(gdb)infolocals

count=9

bus=0xf840001a50

(gdb)c

Continuing

count9

[SwitchingtoLWP3302]

Breakpoint1mainmain()athomexiemengjungdbfilego23

23fmtPrintln(countcount)

FinallywhilerunningtheprogramcreatesanumberofgoroutinesWecanseewhateachgoroutineisdoingusinginfogoroutines

(gdb)infogoroutines

1runningruntimegosched

2syscallruntimeentersyscall

3waitingruntimegosched

4runnableruntimegosched

(gdb)goroutine1bt

00x000000000040e33binruntimegosched()athomexiemengjungosrcpkgruntimeprocc927

10x0000000000403091inruntimechanrecv(c=voidep=voidselected=voidreceived=void)

athomexiemengjungosrcpkgruntimechanc327

20x000000000040316finruntimechanrecv2(t=voidc=void)

athomexiemengjungosrcpkgruntimechanc420

30x0000000000400d6finmainmain()athomexiemengjungdbfilego22

40x000000000040d0c7inruntimemain()athomexiemengjungosrcpkgruntimeprocc244

50x000000000040d16ainschedunlock()athomexiemengjungosrcpkgruntimeprocc267

60x0000000000000000in()

FromthegoroutinescommandwecanhaveabetterpictureofwhatGosruntimesystemisdoinginternallythecallingsequenceforeachfunctionisplainlydisplayed

SummaryInthissectionweintroducedsomebasiccommandsfromtheGDBdebuggerthatyoucanusetodebugyourGoapplicationsTheseincludedtherunprintinfosetvariablecontinuelistandbreakcommandsamongothersFromthebriefexamplesaboveIhopethatyouwillhaveabetterunderstandingofhowthedebuggingprocessworksinGousingtheGDBdebuggerIfyouwanttogetmoredebuggingtipspleaserefertotheGDBmanualonitsofficialwebsite

LinksDirectoryPrevioussectionErrorhandlingNextsectionWritetestcases

DebuggingbyusingGDB

251

113WritingtestcasesInthecourseofdevelopmentaveryimportantstepistotestourcodetoensureitsqualityandintegrityWeneedtomakesurethateveryfunctionreturnstheexpectedresultandthatourcodeperformsoptimallyWealreadyknowthatthefocusofunittestsistofindlogicalerrorsinthedesignorimplementationofprogramsTheyareusedtodetectandexposeproblemsincodeearlyonsothatwecanmoreeasilyfixthembeforetheygetoutofhandWealsoknowthatperformancetestsareconductedforthepurposeofoptimizingourcodesothatitisstableunderloadandcanmaintainahighlevelofconcurrencyInthissectionwelltakealookatsomecommonlyaskedquestionsabouthowunitandperformancetestsareimplementedinGo

TheGolanguagecomeswithalightweighttestingframeworkcalledtestingandwecanusethegotestcommandtoexecuteunitandperformancetestsGostestingframeworkworkssimilarlytotestingframeworksinotherlanguagesYoucandevelopallsortsoftestsuiteswiththemwhichmayincludetestsforunittestesbenchmarkingstresstestsetcLetslearnabouttestinginGostepbystep

HowtowritetestcasesSincethegotestcommandcanonlybeexecutedinadirectorycontainingallcorrespondingfileswearegoingtocreateanewprojectdirectorygotestsothatallofourcodeandtestcodeareinthesamedirectory

Letsgoaheadandcreatetwofilesinthedirectorycalledgotestgoandgotest_testgo

1 GotestgoThisfiledeclaresourpackagenameandhasafunctionthatperformsadivisionoperation

packagegotest

import(

errors

)

funcDivision(abfloat64)(float64error)

ifb==0

return0errorsNew(Divisorcannotbe0)

returnabnil

2 Gotest_testgoThisisourunittestfileKeepinmindthefollowingprinciplesfortestfiles

3 Filenamesmustendin_testgosothatgotestcanfindandexecutetheappropriatecode

4 Youhavetoimportthetestingpackage5 AlltestcasefunctionsbeginwithTest6 Testcasesfollowthesourcecodeorder7 TestfunctionsoftheformTestXxx()takeatestingTargumentwecanusethistypetorecorderrorsortogetthe

testingstatus8 InfunctionsoftheformfuncTestXxx(ttestingT)theXxxsectioncanbeanyalphanumericcombinationbutthe

firstlettercannotbealowercaseletter[az]ForexampleTestintdivwouldbeaninvalidfunctionname9 BycallingoneoftheErrorErrorfFailNowFatalorFatalIfmethodsoftestingTonourtestingfunctions

wecanfailthetestInadditionwecancalltheLogmethodoftestingTtorecordtheinformationintheerrorlog

Hereisourtestcode

Writetestcases

252

packagegotest

import(

testing

)

funcTest_Division_1(ttestingT)

tryaunittestonfunction

ifie=Division(62)i=3||e=nil

Ifitisnotasexpectedthenthetesthasfailed

tError(divisionfunctiontestsdonotpass)

else

recordtheexpectedinformation

tLog(firsttestpassed)

funcTest_Division_2(ttestingT)

tError(justdoesnotpass)

Whenexecutinggotestintheprojectdirectoryitwilldisplaythefollowinginformation

---FAILTest_Division_2(000seconds)

gotest_testgo16isnotpassed

FAIL

exitstatus1

FAILgotest0013s

Wecanseefromthisresultthatthesecondtestfunctiondoesnotpasssincewewroteinadead-endusingtErrorButwhatabouttheperformanceofourfirsttestfunctionBydefaultexecutinggotestdoesnotdisplaytestresultsWeneedtosupplytheverboseargument-vlikegotest-vtodisplaythefollowingoutput

===RUNTest_Division_1

---PASSTest_Division_1(000seconds)

gotest_testgo11firsttestpassed

===RUNTest_Division_2

---FAILTest_Division_2(000seconds)

gotest_testgo16isnotpassed

FAIL

exitstatus1

FAILgotest0012s

TheaboveoutputshowsindetailtheresultsofourtestWeseethatthetestfunction1Test_Division_1passesandthetestfunction2Test_Division_2failsfinallyconcludingthatourtestsuitedoesnotpassNextwemodifythetestfunction2withthefollowingcode

funcTest_Division_2(ttestingT)

tryaunittestonfunction

if_e=Division(60)e==nil

Ifitisnotasexpectedthentheerror

tError(Divisiondidnotworkasexpected)

else

recordsomeoftheinformationyouexpecttorecord

tLog(onetestpassede)

Weexecutegotest-vonceagainThefollowinginformationshouldnowbedisplayed-thetestsuitehaspassed~

Writetestcases

253

===RUNTest_Division_1

---PASSTest_Division_1(000seconds)

gotest_testgo11firsttestpassed

===RUNTest_Division_2

---PASSTest_Division_2(000seconds)

gotest_testgo20onetestpasseddivisorcannotbe0

PASS

okgotest0013s

HowtowritestresstestsStresstestingisusedtodetectfunctionperformanceandbearssomeresemblancetounittesting(whichwewillnotgetintohere)howeverweneedtopayattentiontothefollowingpoints

StresstestsmustfollowthefollowingformatwhereXXXcanbeanyalphanumericcombinationanditsfirstlettercannotbealowercaseletter

funcBenchmarkXXX(btestingB)

BydefaultGotestdoesnotperformfunctionstresstestsIfyouwanttoperformstresstestsyouneedtosettheflag-testbenchwiththeformat-testbench=test_name_regexForinstancetorunallstresstestsinyoursuiteyouwouldrungotest-testbench=

InyourstresstestspleaseremembertousetestingBNanyloopbodiessothatthetestscanberunproperlyAsbeforetestfilenamesmustendin_testgo

Herewecreateastresstestfilecalledwebbench_testgo

packagegotest

import(

testing

)

funcBenchmark_Division(btestingB)

fori=0iltbNi++usebNforlooping

Division(45)

funcBenchmark_TimeConsumingFunction(btestingB)

bStopTimer()callthefunctiontostopthestresstesttimecount

Dosomeinitializationworksuchasreadingfiledatadatabaseconnectionsandthelike

Sothatourbenchmarksreflecttheperformanceofthefunctionitself

bStartTimer()re-starttime

fori=0iltbNi++

Division(45)

Wethenexecutethegotest-filewebbench_testgo-testbench=commandwhichoutputsthefollowingresults

PASS

Benchmark_Division500000000776nsop

Benchmark_TimeConsumingFunction500000000780nsop

okgotest9364s

TheaboveresultsshowthatwedidnotperformanyofourTestXXXunittestfunctionsandinsteadonlyperformedourBenchmarkXXXtests(whichisexactlyasexpected)ThefirstBenchmark_DivisiontestshowsthatourDivision()functionexecuted500milliontimeswithanaverageexecutiontimeof776nsThesecondBenchmark_TimeConsumingFunctionshows

Writetestcases

254

thatourTmeConsumingFunctionexecuted500milliontimeswithanaverageexecutiontimeof780nsFinallyitoutputsthetotalexecutiontimeofourtestsuite

SummaryFromourbriefencounterwithunitandstresstestinginGowecanseethatthetestingpackageisverylightweightyetpackedwithusefulutilitiesWesawthatwritingunitandstresstestscanbeverysimpleandrunningthemcanbeeveneasierwithGosbuilt-ingotestcommandEverytimewemodifyourcodewecansimplyrungotesttobeginregressiontesting

LinksDirectoryPrevioussectionDebuggingusingGDBNextsectionSummary

Writetestcases

255

114SummaryOverthecourseofthelastthreesectionsweveintroducedhowtohandleerrorsinGofirstlookingatgooderrorhandlingpracticesanddesignthenlearninghowtousetheGDBdebuggereffectivelyWesawthatwithGDBwecanperformsingle-stepdebuggingviewandmodifyourprogramvariablesduringexecutionandprintouttherelevantprocessinformationFinallywedescribedhowtouseGosbuilt-intestingframeworktowriteunitandstresstestsProperlyusingthisframeworkallowsustoeasilymakeanyfuturechangestoourcodeandperformthenecessaryregressiontestingGoodwebapplicationsmusthavegooderrorhandlingandpartofthatishavingreadableerrorsanderrorhandlingmechanismswhichcanscaleinapredictablemannerUsingthetoolsmentionedaboveaswellaswritinghighqualityandthoroughunitandstresstestswecanhavepeaceofmindknowingthatonceourapplicationsarelivetheycanmaintainoptimalperformanceandrunasexpected

LinksDirectoryPrevioussectionWritetestcasesNextchapterDeploymentandmaintenance

Summary

256

12DeploymentandmaintenanceSofarwevecoveredthebasicsofdevelopingdebuggingandtestingwebapplicationsinGoAsisoftensaidhoweverthelast10ofdevelopmenttakes90ofthetimeInthischapterwewillbeemphasizingthislast10ofapplicationdevelopmentinordertotrulycraftreliableandhighqualitywebapplicationsInthefirstsectionwewillexaminehowproductionservicesgeneratelogsandtheprocessofloggingitselfThesecondsectionwilldescribedealingwithruntimeerrorsandhowtomanagethemwhentheyoccursothattheimpactonendusersisminimizedInthethirdsectionwetacklethesubjectofdeployingstandaloneGoprogramswhichcanbetrickyatfirstAsyoumightknowGoprogramscannotbewrittenwithdaemonslikeyouwouldwithalanguagesuchasCWelldiscusshowbackgroundprocessesaretypicallymanagedinGoFinallyourfourthandlastsectionwilladdresstheprocessofbackingupandrecoveringapplicationdatainGoWelltakealookatsometechniquesforensuringthatintheeventofacrashwewillbeabletomaintaintheintegrityofourdata

LinksDirectoryPreviouschapterChapter11summaryNextsectionLogs

Deploymentandmaintenance

257

121LogsWewanttobuildwebapplicationsthatcankeeptrackofeventswhichhaveoccurredthroughoutexecutioncombiningthemallintooneplaceforeasyaccesslateronwhenweinevitablyneedtoperformdebuggingoroptimizationtasksGoprovidesasimplelogpackagewhichwecanusetohelpusimplementsimpleloggingfunctionalityLogscanbeprintedusingGosfmtpackagecalledinsideerrorhandlingfunctionsforgeneralerrorloggingGosstandardpackageonlycontainsbasicfunctionalityforlogginghoweverTherearemanythirdpartyloggingtoolsthatwecanusetosupplementitifyourneedsaremoresophisticated(toolssimilartolog4jandlog4cppifyouveeverhadtodealwithlogginginJavaorC++)Apopularandfullyfeaturedopen-sourceloggingtoolinGoistheseelogloggingframeworkLetstakealookathowwecanuseseelogtoperformlogginginourGoapplications

IntroductiontoseelogSeelogisaloggingframeworkforGothatprovidessomesimplefunctionalityforimplementingloggingtaskssuchasfilteringandformattingItsmainfeaturesareasfollows

DynamicconfigurationviaXMLyoucanloadconfigurationparametersdynamicallywithoutrecompilingyourprogramSupportshotupdatestheabilitytodynamicallychangetheconfigurationwithouttheneedtorestarttheapplicationSupportsmulti-outputstreamsthatcansimultaneouslypipelogoutputtomultiplestreamssuchasafilestreamnetworkflowetcSupportfordifferentlogoutputs

CommandlineoutputFileOutputCachedoutputSupportlogrotateSMTPMail

TheaboveisonlyapartiallistofseelogsfeaturesTofullytakeadvantageofallofseelogsfunctionalityhavealookatitsofficialwikiwhichthoroughlydocumentswhatyoucandowithitLetsseehowweduseseeloginourprojects

Firstinstallseelog

goget-ugithubcomcihubseelog

Thenletswriteasimpleexample

packagemain

importloggithubcomcihubseelog

funcmain()

deferlogFlush()

logInfo(HellofromSeelog)

CompileandruntheprogramIfyouseeaHellofromseeloginyourapplicationlogseeloghasbeensuccessfullyinstalledandisrunningoperatingnormally

CustomlogprocessingwithseelogSeelogsupportscustomlogprocessingThefollowingcodesnippetisbasedontheitscustomlogprocessingpartofitspackage

Logs

258

packagelogs

import(

errors

fmt

seeloggithubcomcihubseelog

io

)

varLoggerseelogLoggerInterface

funcloadAppConfig()

appConfig=`

ltseelogminlevel=warngt

ltoutputsformatid=commongt

ltrollingfiletype=sizefilename=datalogsrolllogmaxsize=100000maxrolls=5gt

ltfilterlevels=criticalgt

ltfilepath=datalogscriticallogformatid=criticalgt

ltsmtpformatid=criticalemailsenderaddress=astaxiegmailcomsendername=ShortUrlAPIhostname=smtp

gmailcomhostport=587username=mailusernamepassword=mailpasswordgt

ltrecipientaddress=xiemengjungmailcomgt

ltsmtpgt

ltfiltergt

ltoutputsgt

ltformatsgt

ltformatid=commonformat=DateTime[LEV]Msgngt

ltformatid=criticalformat=FileFullPathFuncMsgngt

ltformatid=criticalemailformat=CriticalerroronourservernTimeDateRelFileFuncMsgnSent

bySeeloggt

ltformatsgt

ltseeloggt

`

loggererr=seelogLoggerFromConfigAsBytes([]byte(appConfig))

iferr=nil

fmtPrintln(err)

return

UseLogger(logger)

funcinit()

DisableLog()

loadAppConfig()

DisableLogdisablesalllibrarylogoutput

funcDisableLog()

Logger=seelogDisabled

UseLoggerusesaspecifiedseelogLoggerInterfacetooutputlibrarylog

UsethisfuncifyouareusingSeelogloggingsysteminyourapp

funcUseLogger(newLoggerseelogLoggerInterface)

Logger=newLogger

Theaboveimplementsthethreemainfunctions

DisableLog

InitializesaglobalvariableLoggerwithseelogdisabledmainlyinordertopreventtheloggerfrombeingrepeatedlyinitialized

LoadAppConfig

InitializestheconfigurationsettingsofseelogaccordingtoaconfigurationfileInourexamplewearereadingtheconfigurationfromanin-memorystringbutofcourseyoucanreaditfromanXMLfilealsoInsidetheconfigurationwesetupthefollowingparameters

Logs

259

Seelog

TheminlevelparameterisoptionalIfconfiguredlogginglevelswhicharegreaterthanorequaltothespecifiedlevelwillberecordedTheoptionalmaxlevelparameterissimilarlyusedtoconfigurethemaximumloggingleveldesired

Outputs

ConfigurestheoutputdestinationInourparticularcasewechannelourloggingdataintotwooutputdestinationsThefirstisarollinglogfilewherewecontinuouslysavethemostrecentwindowofloggingdataTheseconddestinationisafilteredlogwhichrecordsonlycriticallevelerrorsWeadditionallyconfigureittoalertusviaemailwhenthesetypesoferrorsoccur

Formats

DefinesthevariousloggingformatsYoucanusecustomformattingorpredefinedformatting-afulllistofpredefinedformatscanbefoundonseelogswiki

UseLogger

Setthecurrentloggerasourlogprocessor

AbovewevedefinedandconfiguredacustomlogprocessingpackageThefollowingcodedemonstrateshowweduseit

packagemain

import(

nethttp

projectlogs

projectconfigs

projectroutes

)

funcmain()

addr_=configsMainConfigString(serveraddr)

logsLoggerInfo(Startserveratvaddr)

err=httpListenAndServe(addrroutesNewMux())

logsLoggerCritical(Servererrverr)

EmailnotificationsTheaboveexampleexplainshowtosetupemailnotificationswithseelogAsyoucanseeweusedthefollowingsmtpconfiguration

ltsmtpformatid=criticalemailsenderaddress=astaxiegmailcomsendername=ShortUrlAPIhostname=smtpgmailcom

hostport=587username=mailusernamepassword=mailpasswordgt

ltrecipientaddress=xiemengjungmailcomgt

ltsmtpgt

WesettheformatofouralertmessagesthroughthecriticalemailconfigurationprovidingourmailserverparameterstobeabletoreceivethemWecanalsoconfigureournotifiertosendoutalertstoadditionalusersusingtherecipientconfigurationItsasimplematterofaddingonelineforeachadditionalrecipient

Totestwhetherornotthiscodeisworkingproperlyyoucanaddafakecriticalmessagetoyourapplicationlikeso

logsLoggerCritical(testCriticalmessage)

Dontforgettodeleteitonceyouredonetestingorwhenyourapplicationgoesliveyourinboxmaybefloodedwithemailnotifications

NowwheneverourapplicationlogsacriticalmessagewhileonlineyouandyourspecifiedrecipientswillreceiveanotificationemailYouandyourteamcanthenprocessandremedythesituationinatimelymanner

Logs

260

UsingapplicationlogsWhenitcomestologseachapplicationsuse-casemayvaryForexamplesomepeopleuselogsfordataanalysispurposesothersforperformanceoptimizationSomelogsareusedtoanalyzeuserbehaviorandhowpeopleinteractwithyourwebsiteOfcoursetherearelogswhicharesimplyusedtorecordapplicationeventsasauxiliarydataforfindingproblems

AsanexampleletssayweneedtotrackuserattemptsatloggingintooursystemThisinvolvesrecordingbothsuccessfulandunsuccessfulloginattemptsintoourlogWedtypicallyusetheInfologleveltorecordthesetypesofeventsratherthansomethingmoreseriouslikewarnIfyoureusingalinux-typesystemyoucanconvenientlyviewallunsuccessfulloginattemptsfromthelogusingthegrepcommandlikeso

catdatalogsrolllog|grepfailedlogin

2012-12-11111200WARNfailedloginattemptfrom11223344usernamepassword

ThiswaywecaneasilyfindtheappropriateinformationinourapplicationlogwhichcanhelpustoperformstatisticalanalysisifneededInadditionwealsoneedtoconsiderthesizeoflogsgeneratedbyhigh-trafficwebapplicationsTheselogscansometimesgrowunpredictablyToresolvethisissuewecansetseelogupwiththelogrotateconfigurationtoensurethatsinglelogfilesdonotconsumeexcessivediskspace

SummaryInthissectionwevelearnedthebasicsofseelogandhowtobuildacustomloggingsystemwithitWesawthatwecaneasilyconfigureseelogintoaspowerfulalogprocessingsystemasweneedusingittosupplyuswithreliablesourcesofdataforanalysisThroughloganalysiswecanoptimizeoursystemandeasilylocatethesourcesofproblemswhentheyariseInadditionseelogshipswithvariousdefaultloglevelsWecanusetheminlevelconfigurationinconjunctionwithalogleveltoeasilysetuptestsorsendautomatednotificationmessages

LinksDirectoryPrevioussectionDeploymentandmaintenanceNextsectionErrorsandcrashes

Logs

261

122ErrorsandcrashesOnceourwebapplicationsgoliveitslikelythattherewillbesomeunforeseenerrorsAfewexampleofcommonerrorsthatmayoccurinthecourseofyourapplicationsdailyoperationsarelistedbelow

DatabaseErrorserrorsrelatedtoaccessingthedatabaseserverorstoreddataThefollowingaresomedatabaseerrorswhichyoumayencounter

ConnectionErrorsindicatesthataconnectiontothenetworkdatabaseservercouldnotbeestablishedasuppliedusernameorpasswordisincorrectorthatthedatabasedoesnotexist

QueryErrorstheillegalorincorrectuseofanSQLquerycanraiseanerrorsuchasthisThesetypesoferrorscanbeavoidedthroughrigoroustestingDataErrorsdatabaseconstraintviolationsuchasattemptingtoinsertafieldwithaduplicateprimarykeyThesetypesoferrorscanalsobeavoidedthroughrigoroustestingbeforedeployingyourapplicationintoaproductionenvironmentApplicationRuntimeErrorsThesetypesoferrorsvarygreatlycoveringalmostallerrorcodeswhichmayappearduringruntimePossibleapplicationerrorsareasfollows

FilesystemandpermissionerrorswhentheapplicationattemptstoreadafilewhichdoesnotexistordoesnothavepermissiontoreadorwhenitattemptstowritetoafilewhichitisnotallowedtowritetoerrorsofthiscategorywilloccurAfilesystemerrorwillalsooccurifanapplicationreadsafilewithanunexpectedformatforinstanceaconfigurationfilethatshouldbeintheINIformatbutisinsteadstructuredasJSON

Third-partyapplicationerrorsTheseerrorsoccurinapplicationswhichinterfacewithotherthird-partyapplicationsorservicesForinstanceifanapplicationpublishestweetsaftermakingcallstoTwittersAPIitsobviousthatTwittersservicesmustbeupandrunninginorderforourapplicationtocompleteitstaskWemustalsoensurethatwesupplythesethird-partyinterfaceswiththeappropriateparametersinourcallsorelsetheywillalsoreturnerrors

HTTPerrorsTheseerrorsvarygreatlyandarebasedonuserrequestsThemostcommonisthe404NotFounderrorwhichariseswhenusersattempttoaccessnon-existentresourcesinyourapplicationAnothercommonHTTPerroristhe401Unauthorizederror(authenticationisrequiredtoaccesstherequestedresource)403Forbiddenerror(usersarealtogetherrefusedaccesstothisresource)and503ServiceUnavailableerrors(indicativeofaninternalprogramerror)

OperatingsystemerrorsThesesortsoferrorsoccurattheoperatingsystemlayerandcanhappenwhenoperatingsystemresourcesareover-allocatedleadingtocrashesandsysteminstabilityAnothercommonoccurrenceatthisleveliswhentheoperatingsystemdiskgetsfilledtocapacitymakingitimpossibletowritetoThisnaturallyproducesinmanyerrorsNetworkerrorsnetworkerrorstypicallycomeintwoflavorsoneiswhenusersissuerequeststotheapplicationandthenetworkdisconnectsthusdisruptingitsprocessingandresponsephaseTheseerrorsdonotcausetheapplicationtocrashbutcanaffectuseraccesstothewebsitetheotheriswhenapplicationsattemptstoreaddatafromdisconnectednetworkscausingreadfailuresJudicioustestingisparticularlyimportantwhenmakingnetworkcallstoavoidsuchproblemswhichcancauseyourapplicationtocrash

ErrorhandlinggoalsBeforeimplementingerrorhandlingwemustbeclearaboutwhatgoalswearetryingtoachieveIngeneralerrorhandlingsystemsshouldaccomplishthefollowing

UsererrornotificationswhensystemorusererrorsoccurcausingcurrentuserrequeststofailtocompleteaffectedusersshouldbenotifiedoftheproblemForexampleforerrorscausebyuserrequestsweshowaunifiederrorpage(404html)Whenasystemerroroccursweuseacustomerrorpagetoprovidefeedbackforusersastowhathappened-forinstancethatthesystemistemporarilyunavailable(errorhtml)Logerrorswhensystemerrorsoccur(ingeneralwhenfunctionsreturnnon-nilerrorvariables)aloggingsystemsuch

Errorsandcrashes

262

astheonedescribedearliershouldbeusedtorecordtheeventintoalogfilefileIfitisafatalerrorthesystemadministratorshouldalsobenotifiedviae-mailIngeneralhowevermost404errorsdonotwarrantthesendingofemailnotificationsrecordingtheeventintoalogforlaterscrutinyisoftenadequateRollbackthecurrentrequestoperationIfauserrequestcausesaservererrorthenweneedtobeabletorollbackthecurrentoperationLetslookatanexampleasystemsavesauser-submittedformtoitsdatabasethensubmitsthisdatatoathird-partyserverHoweverthethird-partyserverdisconnectsandweareunabletoestablishaconnectionwithitwhichresultsinanerrorInthiscasethepreviouslystoredformdatashouldbedeletedfromthedatabase(voidshouldbeinformed)andtheapplicationshouldinformtheuserofthesystemerrorEnsurethattheapplicationcanrecoverfromerrorsweknowthatitsdifficultforanyprogramtoguarantee100uptimesoweneedtomakeprovisionforscenarioswhereourprogramsfailForinstanceifourprogramcrasheswefirstneedtologtheerrornotifytherelevantpartiesinvolvedthenimmediatelygettheprogramupandrunningagainThiswayourapplicationcancontinuetoprovideserviceswhileasystemadministratorinvestigatesandfixesthecauseoftheproblem

HowtohandleerrorsInchapter11weaddressedtheprocessoferrorhandlinganddesignusingsomeexamplesLetsgointotheseexamplesinabitmoredetailandseesomeothererrorhandlingscenarios

Notifytheuseroferrors

Whenanerroroccurswecanpresenttheuseraccessingthepagewithtwokindsoferrorspages404htmlanderrorhtmlHereisanexampleofwhatthesourcecodeofanerrorpagemightlooklike

lthtmllang=engt

ltheadgt

ltmetahttp-equiv=Content-Typecontent=texthtmlcharset=utf-8gt

lttitlegtPageNotFound

lttitlegt

ltmetaname=viewportcontent=width=device-widthinitial-scale=10gt

ltheadgt

ltbodygt

ltdivclass=containergt

ltdivclass=rowgt

ltdivclass=span10gt

ltdivclass=hero-unitgt

lth1gt404lth1gt

ltpgtErrorInfoltpgt

ltdivgt

ltdivgt

lt--span--gt

ltdivgt

ltdivgt

ltbodygt

lthtmlgt

Anotherexample

Errorsandcrashes

263

lthtmllang=engt

ltheadgt

ltmetahttp-equiv=Content-Typecontent=texthtmlcharset=utf-8gt

lttitlegtsystemerrorpage

lttitlegt

ltmetaname=viewportcontent=width=device-widthinitial-scale=10gt

ltheadgt

ltbodygt

ltdivclass=containergt

ltdivclass=rowgt

ltdivclass=span10gt

ltdivclass=hero-unitgt

lth1gtsystemistemporarilyunavailablelth1gt

ltpgtErrorInfoltpgt

ltdivgt

ltdivgt

lt--span--gt

ltdivgt

ltdivgt

ltbodygt

lthtmlgt

404error-handlinglogicintheoccurrenceofasystemerror

func(pMyMux)ServeHTTP(whttpResponseWriterrhttpRequest)

ifrURLPath==

sayhelloName(wr)

return

NotFound404(wr)

return

funcNotFound404(whttpResponseWriterrhttpRequest)

logError(pagenotfound)errorlogging

t_=tParseFiles(tmpl404htmlnil)parsethetemplatefile

ErrorInfo=FilenotfoundGetthecurrentuserinformation

tExecute(wErrorInfo)executethetemplatemergeroperation

funcSystemError(whttpResponseWriterrhttpRequest)

logCritical(SystemError)systemerrortriggeredCriticalthenloggingwillnotonly

sendamessage

t_=tParseFiles(tmplerrorhtmlnil)parsethetemplatefile

ErrorInfo=systemistemporarilyunavailableGetthecurrentuserinformation

tExecute(wErrorInfo)executethetemplatemergeroperation

HowtohandleexceptionsWeknowthatmanyotherlanguageshavetrycatchkeywordsusedtocapturetheunusualcircumstancesbutinfactmanyerrorscanbeexpectedtooccurwithouttheneedforexceptionhandlingandcanbeinsteadtreatedasanerrorsItsforthisreasonthatGofunctionsreturnerrorsbydesignForexampleifafileisnotfoundorifosOpenreturnsanerrorthesefunctionswillnotpanicasanotherexampleifanetworkconnectiongetsdisconnectedduringadatawriteoperationthenetConnfamilyofWritefunctionswillreturnerrorsinsteadofpanickingTheseerrorstatesaretobeexpectedinmostapplicationsandGoparticularlymakesitexplicitwhenoperationsmightfailbyreturningerrorvariablesLookingattheexampleabovewecanclearlyseetheerrorsthatcanbeexpectedtooccur

Errorsandcrashes

264

TherearehowevercaseswherepanicshouldbeusedForinstanceinoperationswherefailureisalmostimpossibleorincertainsituationswherethereisnowaytoreturnanerrorandtheoperationcannotcontinuepanicshouldbeusedTakeforexampleaprogramthattriestoobtainthevalueofanarrayatx[j]buttheindexjisoutofboundsThispartofthecodewillcausetheprogramtopanicaswillothercriticalunexpectederrorsofthisnatureBydefaultpanickingwillkillofftheoffendingprocess(goroutine)allowingthecodewhichdispatchedthegoroutineanopportunitytorecoverfromtheerrorThiswaythefunctioninwhichtheerroroccurredaswellasallsubsequentcodeafteritwillnotcontinuetoexecuteGospanicwasdeliberatelydesignedwiththisbehaviorinmindwhichisdifferentthantypicalerrorhandlingpanicisreallyjustexceptionhandlingIntheexamplebelowweexpectthatUser[UID]willreturnausernamefromtheUserarraybuttheUIDthatweuseisoutofboundsandthrowsanexceptionIfwedonothavearecoverymechanismtodealwiththisimmediatelytheprocesswillbekilledandthepanicwillpropagateupthestackuntilourprogramfinallycrashesInorderforourapplicationtoberobustandresilienttothesekindsofruntimeerrorsweneedtoimplementrecoverymechanismsincertainplaces

funcGetUser(uidint)(usernamestring)

deferfunc()

ifx=recover()x=nil

username=

()

username=User[uid]

return

TheabovedescribesthedifferencesbetweenerrorsandexceptionsSowhenitcomesdowntodevelopingourGoapplicationswhendoweuseoneortheotherTherulesaresimpleifyoudefineafunctionthatyouanticipatemightfailthenreturnanerrorvariableWhencallinganotherpackagesfunctionifitisimplementedwellthereshouldbenoneedtoworrythatitwillpanicunlessatrueexceptionhasoccurred(whetherrecoverylogichasbeenimplementedornot)PanicandrecovershouldonlybeusedinternallyinsidepackagestodealwithspecialcaseswherethestateoftheprogramcannotbeguaranteedorwhenaprogrammerserrorhasoccurredExternallyfacingAPIsshouldexplicitlyreturnerrorvalues

SummaryThisissectionsummarizeshowwebapplicationsshouldhandlevariouserrorssuchasnetworkdatabaseandoperatingsystemerrorsamongothersWeveoutlineseveraltechniquestoeffectivelydealwithruntimeerrorssuchasdisplayinguser-friendlyerrornotificationsrollingbackactionsloggingandalertingsystemadministratorsFinallyweexplainedhowtocorrectlyhandleerrorsandexceptionsTheconceptofanerrorisoftenconfusedwiththatofanexceptionhoweverinGothereisacleardistinctionbetweenthetwoForthisreasonwevediscussedtheprinciplesofprocessingbotherrorsandexceptionsinwebapplications

LinksDirectoryPrevioussectionLogsNextsectionDeployment

Errorsandcrashes

265

123DeploymentWhenourwebapplicationisfinallyproductionreadywhatarethestepsnecessarytogetitdeployedInGoanexecutablefileencapsulatingourapplicationiscreatedafterwecompileourprogramsProgramswritteninCcanrunperfectlyasbackgrounddaemonprocesseshoweverGodoesnotyethavenativesupportfordaemonsThegoodnewsisthatwecanusethirdpartytoolstohelpusmanagethedeploymentofourGoapplicationsexamplesofwhichareSupervisordupstartanddaemontoolsamongothersThissectionwillintroduceyoutosomebasicsoftheSupervisordprocesscontrolsystem

DaemonsCurrentlyGoprogramscannotberunasdaemonprocesses(foradditionalinformationseetheopenissueongithubhere)ItsdifficulttoforkexistingthreadsinGobecausethereisnowayofensuringaconsistentstateinallthreadsthathavebeenused

Wecanhoweverseemanyattemptsatimplementingdaemonsonlinesuchasinthetwofollowingways

MarGooneimplementationoftheconceptofusingCommandtodeployapplicationsIfyoureallywanttodaemonizeyourapplicationsitisrecommendedtousecodesimilartothefollowing

d=flagBool(dfalseWhetherornottolaunchinthebackground(likea

daemon))

ifd

cmd=execCommand(osArgs[0]

-close-fds

-addraddr

-callcall

)

serrerr=cmdStderrPipe()

iferr=nil

logFatalln(err)

err=cmdStart()

iferr=nil

logFatalln(err)

serr=ioutilReadAll(serr)

s=bytesTrimSpace(s)

ifbytesHasPrefix(s[]byte(addr))

fmtPrintln(string(s))

cmdProcessRelease()

else

logPrintf(unexpectedresponsefromMarGo`s`error`v`nserr)

cmdProcessKill()

Anothersolutionistousesyscallbutthissolutionisnotperfect

Deployment

266

packagemain

import(

log

os

syscall

)

funcdaemon(nochdirnocloseint)int

varretret2uintptr

varerruintptr

darwin=syscallOS==darwin

alreadyadaemon

ifsyscallGetppid()==1

return0

forkofftheparentprocess

retret2err=syscallRawSyscall(syscallSYS_FORK000)

iferr=0

return-1

failure

ifret2lt0

osExit(-1)

handleexceptionfordarwin

ifdarwinampampret2==1

ret=0

ifwegotagoodPIDthenwecallexittheparentprocess

ifretgt0

osExit(0)

Changethefilemodemask

_=syscallUmask(0)

createanewSIDforthechildprocess

s_rets_errno=syscallSetsid()

ifs_errno=0

logPrintf(ErrorsyscallSetsiderrnods_errno)

ifs_retlt0

return-1

ifnochdir==0

osChdir()

ifnoclose==0

fe=osOpenFile(devnullosO_RDWR0)

ife==nil

fd=fFd()

syscallDup2(fdosStdinFd())

syscallDup2(fdosStdoutFd())

syscallDup2(fdosStderrFd())

return0

Deployment

267

WhilethetwosolutionsaboveimplementdaemonizationinGoIstillcannotrecommendthatyouuseeithermethodssincethereisnoofficialsupportfordaemonsinGoNotwithstandingthisfactthefirstoptionisthemorefeasibleoneandiscurrentlybeingusedbysomewell-knownopensourceprojectslikeskynetforimplementingdaemons

SupervisordAbovewevelookedattwoschemesthatarecommonlyusedtoimplementdaemonsinGohoweverbothmethodslackofficialsupportSoitsrecommendedthatyouuseathird-partytooltomanageapplicationdeploymentHerewetakealookattheSupervisordprojectimplementedinPythonwhichprovidesextensivetoolsforprocessmanagementSupervisordwillhelpyoutodaemonizeyourGoapplicationsalsoallowingyoutodothingslikestartshutdownandrestartyourapplicationswithsomesimplecommandsamongmanyotheractionsInadditionSupervisordmanagedprocessescanautomaticallyrestartprocesseswhichhavecrashedensuringthatprogramscanrecoverfromanyinterruptions

AsanasideIrecentlyfellintoacommonpitfallwhiletryingtodeployanapplicationusingSupervisordAllapplicationsdeployedusingSupervisordarebornoutoftheSupervisordparentprocessWhenyouchangeanoperatingsystemfiledescriptordontforgettocompletelyrestartSupervisord-simplyrestartingtheapplicationitismanagingwillnotsufficeWhenIfirstdeployedanapplicationwithSupervisordImodifiedthedefaultfiledescriptorfieldchangingthedefaultnumberfrom1024to100000andthenrestartingmyapplicationInrealitySupervisordcontinuedusingonly1024filedescriptorstomanageallofmyapplicationsprocessesUpondeployingmyapplicationtheloggerbeganreportingalackoffiledescriptorsItwasalongprocessfindingandfixingthismistakesobeware

InstallingSupervisord

Supervisordcaneasilybeinstalledusingsudoeasy_installsupervisorOfcoursethereisalsotheoptionofdirectlydownloadingitfromitsofficialwebsiteuncompressingitgoingintothefolderthenrunningsetuppyinstalltoinstallitmanually

Ifyouregoingtheeasy_installroutethenyouneedtofirstinstallsetuptools

GotohttppypipythonorgpypisetuptoolsfilesanddownloadtheappropriatefiledependingonyoursystemspythonversionEnterthedirectoryandexecuteshsetuptoolsxxxxeggWhenthenscriptisdoneyoullbeabletousetheeasy_installcommandtoinstallSupervisord

ConfiguringSupervisord

SupervisordsdefaultconfigurationfilepathisetcsupervisordconfandcanbemodifiedusingatexteditorThefollowingiswhatatypicalconfigurationfilemaylooklike

Deployment

268

etcsupervisordconf

[unix_http_server]

file=varrunsupervisordsock

chmod=0777

chown=rootroot

[inet_http_server]

Webmanagementinterfacesettings

port=9001

username=admin

password=yourpassword

[supervisorctl]

Mustunix_http_servermatchthesettingsinside

serverurl=unixvarrunsupervisordsock

[supervisord]

logfile=varlogsupervisordsupervisordlog(mainlogfiledefault$CWDsupervisordlog)

logfile_maxbytes=50MB(maxmainlogfilebytesb4rotationdefault50MB)

logfile_backups=10(numofmainlogfilerotationbackupsdefault10)

loglevel=info(logleveldefaultinfoothersdebugwarntrace)

pidfile=varrunsupervisordpid(supervisordpidfiledefaultsupervisordpid)

nodaemon=true(startinforegroundiftruedefaultfalse)

minfds=1024(minavailstartupfiledescriptorsdefault1024)

minprocs=200(minavailprocessdescriptorsdefault200)

user=root(defaultiscurrentuserrequiredifroot)

childlogdir=varlogsupervisord(AUTOchildlogdirdefault$TEMP)

[rpcinterfacesupervisor]

supervisorrpcinterface_factory=supervisorrpcinterfacemake_main_rpcinterface

Managetheconfigurationofasingleprocessyoucanaddmultipleprogram

[programblogdemon]

command=datablogblogdemon

autostart=true

startsecs=5

user=root

redirect_stderr=true

stdout_logfile=varlogsupervisordblogdemonlog

SupervisordmanagementAfterinstallationiscompletetwoSupervisordcommandsbecomeavailabletoyouonthecommandlinesupervisorandsupervisorctlThecommandsareasfollows

supervisordinitialstartuplaunchandprocessconfigurationmanagementsupervisorctlstopprogramxxxstoptheprogramxxxprocesswhereprogramxxxisavalueconfiguredinyoursupervisordconffileForinstanceifyouhavesomethinglike[programblogdemon]configuredyouwouldusethesupervisorctlstopblogdemoncommandtokilltheprocesssupervisorctlstartprogramxxxstarttheprogramxxxprocesssupervisorctlrestartprogramxxxrestarttheprogramxxxprocesssupervisorctlstopallstopallprocessesnotestartrestartstopwillnotloadthelatestconfigurationfilessupervisorctlreloadloadthelatestconfigurationfilelaunchthemandmanageallprocesseswiththenewconfiguration

SummaryInthissectionwedescribedhowtoimplementdaemonsinGoWelearnedthatGodoesnotnativelysupportdaemonsandthatweneedtousethird-partytoolstohelpusmanagethemOnesuchtoolistheSupervisordprocesscontrolsystemwhichwecanusetoeasilydeployandmanageourGoprograms

Links

Deployment

269

DirectoryPrevioussectionErrorsandcrashesNextsectionBackupandrecovery

Deployment

270

124BackupandrecoveryInthissectionwelldiscussanotheraspectofapplicationmanagementdatabackupandrecoveryonproductionserversWeoftenencountersituationswhereproductionserversdontbehaveasweexpectthemtoServernetworkoutagesharddrivemalfunctionsoperatingsystemcrashesandothersimilareventscancausedatabasestobecomeunavailableTheneedtorecoverfromthesetypesofeventshasledtotheemergenceofmanycoldstandbyhotstandbytoolsthatcanhelptofacilitatedisasterrecoveryremotelyInthissectionwellexplainhowtobackupdeployedapplicationsinadditiontobackingupandrestoringanyMySQLandRedisdatabasesyoumightbeusing

ApplicationBackupInmostclusterenvironmentswebapplicationsdonotneedtobebackedupsincetheyareactuallycopiesofcodefromourlocaldevelopmentenvironmentorfromaversioncontrolsystemInmanycaseshoweverweneedtobackupdatawhichhasbeensuppliedbytheusersofoursiteForinstancewhensitesrequireuserstouploadfilesweneedtobeabletobackupanyfilesthathavebeenuploadedbyuserstoourwebsiteThecurrentapproachforprovidingthiskindofredundancyistoutilizeso-calledcloudstoragewhereuserfilesandotherrelatedresourcesarepersistedintoahighlyavailablenetworkofserversIfoursystemcrashesaslongasuserdatahasbeenpersistedontothecloudwecanatleastbesurethatnodatawillbelost

ButwhataboutthecaseswherewedidnotbackupourdatatoacloudserviceorwherecloudstoragewasnotanoptionHowdowebackupdatafromourwebapplicationsthenHerewedescribeatoolcalledrsyncwhichcanbecommonlyfoundonunix-likesystemsRsyncisatoolwhichcanbeusedtosynchronizefilesresidingondifferentsystemsandaperfectuse-caseforthisfunctionalityistokeepourwebsitebackedup

NoteCwrsyncisanimplementationofrsyncfortheWindowsenvironment

RsyncinstallationYoucanfindthelatestversionofrsyncfromitsofficialwebsiteOfcoursebecausersyncisveryusefulsoftwaremanyLinuxdistributionswillalreadyhaveitinstalledbydefault

PackageInstallation

sudoapt-getinstallrsyncNotedebianubuntuandotheronlineinstallationmethods

yuminstallrsyncNoteFedoraRedhatCentOSandotheronlineinstallationmethods

rpm-ivhrsyncNoteFedoraRedhatCentOSandotherrpmpackageinstallationmethods

FortheotherLinuxdistributionspleaseusetheappropriatepackagemanagementmethodstoinstallitAlternativelyyoucanbuildityourselffromthesource

tarxvfrsync-xxxtargz

cdrsync-xxx

configure-prefix=usrmakemakeinstall

NoteIfwanttocompileandinstallthersyncfromitssourceyouhavetoinstallgcccompilertoolssuchasjob

NoteBeforeusingsourcepackagescompiledandinstalledyouhavetoinstallgcccompilertoolssuchasjob

RsyncConfiguration

Rsynccanbeconfiguredfromthreemainconfigurationfilesrsyncdconfwhichisthemainconfigurationfilersyncdsecretswhichholdspasswordsandrsyncdmotdwhichcontainsserverinformation

Backupandrecovery

271

Youcanrefertotheofficialdocumentationonrsyncswebsiteformoredetailedexplanationsbutherewewillsimplyintroducethebasicsofsettinguprsync

Startinganrsyncdaemonserver-side

usrbinrsync--daemon--config=etcrsyncdconf

the--daemonparameterisforrunningrsyncinservermodeMakethisthedefaultboot-timesettingbyjoiningittotherclocalfile

echorsync--daemongtgtetcrcdrclocal

SetupanrsyncusernameandpasswordmakingsurethatitsownedonlybyrootsothatlocalunauthorizedusersorexploitsdonothaveaccesstoitIfthesepermissionsarenotsetcorrectlyrsyncmaynotboot

echoYourUsernameYourPasswordgtetcrsyncdsecrets

chmod600etcrsyncdsecrets

Clientsynchronization

Clientscansynchronizeserverfileswiththefollowingcommand

rsync-avzP--delete--password-file=rsyncdsecretsusername1921681455wwwvarrsyncbackup

Letsbreakthisdownintoafewkeypoints

1 -avzParesomecommonoptionsUsersync--helptoreviewwhatthesedo2 --deletedeletesextraneousfilesonthereceivingsideForexampleiffilesaredeletedonthesendingsidethenext

timethetwomachinesaresynchronizedthereceivingsideswillautomaticallydeletethecorrespondingfiles3 --password-filespecifiesapasswordfileforaccessinganrsyncdaemonOntheclientsidethisistypicallythe

clientetcrsyncdsecretsfileandontheserversideitsetcrsyncdsecretsWhenusingsomethinglikeCrontoautomatersyncyouwontneedtomanuallyenterapassword

4 usernamespecifiestheusernametobeusedinconjunctionwiththeserver-sideetcrsyncdsecretspassword5 1921681455istheIPaddressoftheserver6 www(notethedoublecolons)specifiescontactinganrsyncdaemondirectlyviaTCPforsynchronizingthewww

moduleaccordingtotheserver-sideconfigurationslocatedinetcrsyncdconfWhenonlyasinglecolonisusedthersyncdaemonisnotcontacteddirectlyinsteadaremote-shellprogramsuchassshisusedasthetransport

InordertoperiodicallysynchronizefilesyoucansetupacrontabfilethatwillrunrsynccommandsasoftenasneededOfcourseuserscanvarythefrequencyofsynchronizationaccordingtohowcriticalitistokeepcertaindirectoriesorfilesuptodate

MySQLbackupMySQLdatabasesarestillthemainstreamgo-tosolutionformostwebapplicationsThetwomostcommonmethodsofbackingupMySQLdatabasesarehotbackupsandcoldbackupsHotbackupsareusuallyusedwithsystemssetupinamasterslaveconfigurationtobackuplivedata(themasterslavesynchronizationmodeistypicallyusedforseparatingdatabasereadwriteoperationsbutcanalsobeusedforbackinguplivedata)ThereisalotofinformationavailableonlinedetailingthevariouswaysonecanimplementthistypeofschemeForcoldbackupsincomingdataisnotbackedupinreal-timeasisthecasewithhotbackupsInsteaddatabackupsareperformedperiodicallyThiswayifthesystemfailstheintegrityofdatabeforeacertainperiodoftimecanstillbeguaranteedForinstanceincaseswhereasystemmalfunctioncausesdatatobelostandthemasterslavemodelisunabletoretrieveitcoldbackupscanbeusedforapartialrestoration

Ashellscriptisgenerallyusedtoimplementregularcoldbackupsofdatabasesexecutingsynchronizationtasksusingrsyncinanon-localmode

Backupandrecovery

272

ThefollowingisanexampleofabackupscriptthatperformsscheduledbackupsforaMySQLdatabaseWeusethemysqldumpprogramwhichallowsustoexportthedatabasetoafile

binbash

Configurationinformationmodifyitasneeded

mysql_user=USERMySQLbackupuser

mysql_password=PASSWORDMySQLbackupuserspassword

mysql_host=localhost

mysql_port=3306

mysql_charset=utf8MySQLencoding

backup_db_arr=(db1db2)Nameofthedatabasetobebackedupseparatingmultipledatabaseswihspaces(DB1

DB2db3)

backup_location=varwwwmysqlBackupdatastoragelocationpleasedonotendwithaandleaveitatitsdefau

ltfortheprogramtoautomaticallycreateafolder

expire_backup_delete=ONWhethertodeleteoutdatedbackupsornot

expire_days=3Settheexpirationtimeofbackupsindays(defaultstothreedays)thisisonlyvalidwhenthe`ex

pire_backup_delete`optionisON

Wedonotneedtomodifythefollowinginitialsettingsbelow

backup_time=`date+YmdHM`Definethebackuptimeformat

backup_Ymd=`date+Y-m-d`Definethebackupdirectorydatetime

backup_3ago=`date-d3daysago+Y-m-d`3daysbeforethedate

backup_dir=$backup_location$backup_YmdFullpathtothebackupfolder

welcome_msg=WelcometouseMySQLbackuptoolsGreeting

DeterminewhethertoMySQLisrunningifnotthenabortthebackup

mysql_ps=`ps-ef|grepmysql|wc-l`

mysql_listen=`netstat-an|grepLISTEN|grep$mysql_port|wc-l`

if[[$mysql_ps==0]-o[$mysql_listen==0]]then

echoERRORMySQLisnotrunningbackupaborted

exit

else

echo$welcome_msg

fi

Connecttothemysqldatabaseifaconnectioncannotbemadeabortthebackup

mysql-h$mysql_host-P$mysql_port-u$mysql_user-p$mysql_passwordltltend

usemysql

selecthostuserfromuserwhereuser=rootandhost=localhost

exit

end

flag=`echo$`

if[$flag=0]then

echoERRORCantconnectmysqlserverbackupaborted

exit

else

echoMySQLconnectokPleasewait

DeterminewhetherabackupdatabaseisdefinedornotIfsobeginthebackupifnotthenabort

if[$backup_db_arr=]then

dbnames=$(cut-d-f1-5$backup_database)

echoarris($backup_db_arr[])

fordbnamein$backup_db_arr[]

do

echodatabase$dbnamebackupstart

`mkdir-p$backup_dir`

`mysqldump-h$mysql_host-P$mysql_port-u$mysql_user-p$mysql_password$dbname-default-character-set=

$mysql_charset|gzipgt$backup_dir$dbname-$backup_timesqlgz`

flag=`echo$`

if[$flag==0]then

echodatabase$dbnamesuccessfullybackedupto$backup_dir$dbname-$backup_timesqlgz

else

echodatabase$dbnamebackuphasfailed

fi

done

else

echoERRORNodatabasetobackupbackupaborted

exit

fi

Ifdeletingexpiredbackupsisenableddeleteallexpiredbackups

Backupandrecovery

273

if[$expire_backup_delete==ON-a$backup_location=]then

`find$backup_location-typed-o-typef-ctime+$expire_days-execrm-rf`

`find$backup_location-typed-mtime+$expire_days|xargsrm-rf`

echoExpiredbackupdatadeletecomplete

fi

echoAlldatabaseshavebeensuccessfullybackedupThankyou

exit

fi

Modifythepropertiesoftheshellscriptlikeso

chmod600rootmysql_backupsh

chmod+xrootmysql_backupsh

Thenaddthecrontabcommand

0000rootmysql_backupsh

Thissetsupregularbackupsofyourdatabasestothevarwwwmysqldirectoryeverydayat0000whichcanthenbesynchronizedusingrsync

MySQLRecoveryWevejustdescribedsomecommonlyusedbackuptechniquesforMySQLnamelyhotbackupsandcoldbackupsTorecapthemaingoalofahotbackupistobeabletorecoverdatainreal-timeafteranapplicationhasfailedinsomewaysuchasinthecaseofaserverhard-diskmalfunctionWelearnedthatthistypeofschemecanbeimplementedbymodifyingdatabaseconfigurationfilessothatdatabasesarereplicatedontoaslaveminimizinginterruptiontoservices

ButsometimesweneedtoperformacoldbackupoftheSQLdatarecoveryaswithdatabasebackupyoucanimportthroughthecommandHotbackupsarehoweversometimesinadequateTherearecertainsituationswherecoldbackupsarerequiredtoperformdatarecoveryevenifitsonlyapartialoneWhenyouhaveacoldbackupofyourdatabaseyoucanusethefollowingMySQLcommandtoimportit

mysql-uusername-pdatabseltbackupsql

AsyoucanseeimportingandexportingdatabaseisafairlysimplematterIfyouneedtomanageadministrativeprivilegesordealwithdifferentcharactersetsthisprocessmaybecomealittlemorecomplicatedthoughthereareanumberofcommandswhichwillhelpyoutodothis

RedisbackupRedisisoneofthemostpopularNoSQLdatabasesandbothhotandcoldbackuptechniquescanalsobeusedinsystemswhichuseitLikeMySQLRedisalsosupportsmasterslavemodewhichisidealforimplementinghotbackups(refertoRedisofficialdocumentationtolearnhowtoconfigurethistheprocessisverystraightforward)AsforcoldbackupsRedisroutinelysavescacheddatainmemorytothedatabasefileon-diskWecansimplyusethersyncbackupmethoddescribedabovetosynchronizeitwithanon-localmachine

RedisrecoverySimilarlyRedisrecoverycanbedividedintohotandcoldbackuprecoveryThemethodsandobjectivesofrecoveringdatafromahotbackupofaRedisdatabasearethesameasthosementionedaboveforMySQLaslongastheRedisapplicationisusingtheappropriatedatabaseconnection

Backupandrecovery

274

ARediscoldbackuprecoverysimplyinvolvescopyingbacked-updatabasefilesintotheworkingdirectorythenstartingRedisonitThedatabasefilesareautomaticallyloadedintomemoryatboottimethespeedwithwhichRedisbootswilldependonthesizeofthedatabasefiles

SummaryInthissectionwelookedatsometechniquesforbackingupdataaswellasrecoveringfromdisasterswhichmayoccurafterdeployingourapplicationsWealsointroducedrsyncatoolwhichcanbeusedtosynchronizefilesondifferentsystemsUsingrsyncwecaneasilyperformbackupandrestorationproceduresforbothMySQLandRedisdatabasesamongothersWehopethatbybeingintroducedtosomeoftheseconceptsyouwillbeabletodevelopdisasterrecoveryprocedurestobetterprotectthedatainyourwebapplications

LinksDirectoryPrevioussectionDeploymentNextsectionSummary

Backupandrecovery

275

125SummaryInthischapterwediscussedhowtodeployandmaintainourGowebapplicationsWealsolookedatsomecloselyrelatedtopicswhichcanhelpustokeepthemrunningsmoothlywithminimalmaintenance

Specificallywelookedat

CreatingarobustloggingsystemcapableofrecordingerrorsandnotifyingsystemadministratorsHandlingruntimeerrorsthatmayoccurincludingloggingthemandhowtorelaythisinformationinauser-friendlymannerthatthereisaproblemHandling404errorsandnotifyingusersthattherequestedpagecannotbefoundDeployingapplicationstoaproductionenvironment(includinghowtodeployupdates)HowtodeployhighlyavailableapplicationsBackingupandrestoringfilesanddatabases

Afterreadingthecontentsofthischapterthosethinkingaboutdevelopingawebapplicationfromscratchshouldalreadyhavethefullpictureonhowtodosothischapterprovidedanintroductiononhowtomanagedeploymentenvironmentswhilepreviouschaptershavefocusedonthedevelopmentofcode

LinksDirectoryPrevioussectionBackupandrecoveryNextchapterBuildingawebframework

Summary

276

13BuildingawebframeworkThePrecedingtwelvechaptersdescribehowtodevelopwebapplicationsinGointroducingalotofbasicknowledgedevelopmenttoolsandtechniquesInthischapterwewillbeusingthisknowledgetoimplementasimplewebframeworkThefirstsectionofthischapterwilltakeyouthroughtheplanninganddesignstageofbuildingawebframeworkWelllookatleveragingtheMVCpatternaswellasdesigningprogramexecutionflowamongotherthingsThesecondsectionwilldescribethefirstfeatureofourframeworkRoutingnamelyhowtomapURLstoprocessinglogicTheninthethirdsectionwedescribetheprocessinglogicitselfwhichinvolvesdesigninggenericcontrollersandhowtohandlerequestsandreturnresponsesafterinheritingfromanobjecthandlerNextwedescribesomeoftheauxiliaryfunctionalitycommontomostwebframeworkssuchaslogprocessinginformationconfigurationetcFinallywellimplementasimplebloggingsystemontopofourframeworkwhichwilldemonstratetheapplicationlogicnecessaryforpublishingmodifyingdeletinganddisplayinglistsofblogposts

Byseeingfirst-handhowtoimplementsuchacompleteprojectfromscratchyouwillhopefullyhaveabetterunderstandingoftheinnerworkingsofGowebapplicationsYoullbecomfortablebuildingyourownprojectdirectorystructuresimplementingURLroutersandutilizingMVCamongotheraspectsofwebdevelopmentAmongtheframeworksprevalenttodayMVCisnolongeramythItsnotuncommontohearprogrammersarguingaboutwhichframeworksaregoodandwhicharebadwhichisoftentooshallowofanapproachFrameworksareonlytoolsandsometoolsaremoresuitableforcertainapplicationsthanothersTherearenouniversallygoodorbadtoolsThusbyteachingyourselfhowtowriteaframeworkfromscratchyouwillbeabletotailor-maketheperfecttooltobestrealizeyourideas

LinksDirectoryPreviouschapterChapter12summaryNextsectionProjectprogram

Buildawebframework

277

131ProjectplanningAnythingyouintendtodowellmustfirstbeplannedwellInourcaseourintentionistodevelopabloggingsystemsothefirststepweshouldtakeistodesigntheflowoftheapplicationinitsentiretyWhenwehaveaclearunderstandingoftheourapplicationsprocessofexecutionthesubsequentdesignandcodingstepsbecomemucheasier

GOPATHandprojectsettingsLetsproceedbyassumingthatourGOPATHpointstoafolderwithanordinarydirectoryname(ifnotwecaneasilysetupasuitabledirectoryandsetitspathastheGOPATH)AswevedescribeearlieraGOPATHcancontainmorethanonedirectoryinWindowswecansetthisasanenvironmentvariableinlinuxOSXsystemsGOPATHcanbesetusingexportieexportgopath=pathtoyourdirectoryaslongasthedirectorywhichGOPATHpointstocontainsthethreesub-directoriespkgbinandsrcBelowweveplacedthesourcecodeofournewprojectinthesrcdirectorywiththetentativenamebeelogHerearesomescreenshotsoftheWindowsenvironmentvariablesaswellasofthedirectorystructure

Figure131SettingtheGOPATHenvironmentvariable

Figure132Theworkingdirectoryunder$gopathsrc

ApplicationflowchartOurbloggingsystemwillbebasedonthemodel-view-controllerdesignpatternMVCistheseparationoftheapplicationlogicfromthepresentationlayerInpracticewhenwekeepthepresentationlayerseparatedwecandrasticallyreducetheamountofcodeneededonourwebpages

ModelsrepresentdataaswellastherulesandlogicgoverningitInGeneralamodelclasswillcontainfunctionsforremovinginsertingandupdatingdatabaseinformationViewsarearepresentationofthestateofamodelAviewisusuallyapagebutinGoaviewcanalsobeafragmentofapagesuchasaheaderorfooterItcanalsobeanRSSfeedoranyothertypeofpageGostemplatepackageprovidesverygoodsupportforviewlayerfunctionalityControllersarethegluelogicbetweenthemodelandviewlayersandencompassesalltheintermediarylogicnecessaryforhandlingHTTPrequestsandgeneratingWebpages

Thefollowingfigureisanoverviewoftheprojectframeworkanddemonstrateshowdatawillflowthroughthesystem

Figure133frameworkdataflow

1 Maingoistheapplicationsentrypointandinitializessomebasicresourcesrequiredtoruntheblogsuchasconfigurationinformationlisteningportsetc

2 RoutingchecksallincomingHTTPrequestsandaccordingtothemethodURLandparametersmatchesitwiththecorrespondingcontrolleraction

3 Iftherequestedresourcehasalreadybeencachedtheapplicationwillbypasstheusualexecutionprocessandreturnaresponsedirectlytotheusersbrowser

4 SecuritydetectionTheapplicationwillfilterincomingHTTPrequestsandanyotherusersubmitteddatabeforehandingitofftothecontroller

5 ControllerloadsmodelscorelibrariesandanyotherresourcesrequiredtoprocessspecificrequestsThecontrollerisprimarilyresponsibleforhandlingbusinesslogic

Projectprogram

278

6 OutputtherenderedviewtobesenttotheclientswebbrowserIfcachinghasbeenenabledthefirstviewiscachedforfuturerequeststothesameresource

DirectorystructureAccordingtotheframeworkflowwevedesignedaboveourblogprojectsdirectorystructureshouldlooksomethinglikethefollowing

|mdashmdashmaingoimportdocuments

|mdashmdashconfconfigurationfilesandprocessingmodule

|mdashmdashcontrollerscontrollerentry

|mdashmdashmodelsdatabaseprocessingmodule

|mdashmdashutilsusefulfunctionlibrary

|mdashmdashstaticstaticfiledirectory

|mdashmdashviewsviewgallery

FrameworkdesignInordertoquicklybuildourblogweneedtodevelopaminimalframeworkbasedontheapplicationwevedesignedaboveTheframeworkshouldincluderoutingcapabilitiessupportforRESTfulcontrollersautomatedtemplaterenderingaloggingsystemconfigurationmanagementandmore

SummaryThissectiondescribestheinitialdesignofourbloggingsystemfromsettingupourGOPATHtobrieflyintroducingtheMVCpatternWealsolookedattheflowofdataandtheexecutionsequenceofourbloggingsystemFinallywedesignedthestructureofourprojectdirectoryAtthispointwevebasicallycompletedthegroundworkrequiredforassemblingourframeworkInthenextfewsectionswewillimplementeachofthecomponentswevediscussedonebyone

LinksDirectoryPrevioussectionBuildingawebframeworkNextsectionCustomizingrouters

Projectprogram

279

132Customizingrouters

HTTProutingTheHTTProutingcomponentisresponsibleformappingHTTPrequeststoacorrespondingfunctionorstructmethodTheroutertakestwokeypiecesofinformationfromincomingrequests

-Theuserrequestedpath(forexampleuser123article123)andanyquerystringsorparametersthatcomewithit(forexampleid=11)-TheHTTPrequestmethod(GETPOSTPUTandDELETEPATCHetc)

Therouterthenforwardstherequesttothehandlerfunction(controllerlayer)thathasbeenregisteredwiththatparticularHTTPmethodandpath

DefaultroutingimplementationInsection34weintroducedGoshttppackageindetailwhichincludedhowtodesignandimplementroutingHerewetakeanotherlookatanexamplethatillustratestheroutingprocess

funcfooHandler(whttpResponseWriterrhttpRequest)

fmtFprintf(wHelloqhtmlEscapeString(rURLPath))

httpHandle(foofooHandler)

httpHandleFunc(barfunc(whttpResponseWriterrhttpRequest)

fmtFprintf(wHelloqhtmlEscapeString(rURLPath))

)

logFatal(httpListenAndServe(8080nil))

TheexampleabovecallshttpsdefaultmuxcalledDefaultServeMuximplicitlyspecifiedbythenilparameterinthecalltohttpListenAndServeThehttpHandlefunctiontakestwoparametersthefirstparameteristheresourceyouwantuserstoaccessspecifiedbyitsURLpath(whichisstoredinrURLPath)andthesecondargumentbindsahandlerfunctionwiththispathTheRouterhastwomainjobs

ToaddandstoreroutinginformationToforwardrequeststoahandlerfunctionforprocessing

BydefaultGoroutesarehandledwithhttpHandleandhttpHandleFunctypesregisteredbydefaultthroughtheunderlyingDefaultServeMuxHandle(patternstringhandlerHandler)functionThisfunctionmapsresourcepathstohandlersandstorestheminamap[string]muxEntrymapThisisthefirstjobthatwementionedabove

WhentheapplicationisrunningtheGoserverlistenstoaportWhenitreceivesatcpconnectionitusesaHandlertoprocessitAsaforementionedsincetheHandlerintheexampleaboveisnilthedefaultrouterhttpDefaultServeMuxisusedUsingthemapofpreviouslystoredroutesDefaultServeMuxServeHTTPwilldispatchtherequesttothefirsthandlerwithamatchingpathThisistherouterssecondjob

forkv=rangemuxm

ifpathMatch(kpath)

continue

ifh==nil||len(k)gtn

n=len(k)

h=vh

Customizedrouters

280

RoutingwithBeegoAtpresentmostGowebapplicationsbasetheirroutingonhttpsdefaultrouterhoweverthishasseverallimitations

DoesnotsupportdynamicrouteswithparameterssuchastheuserUIDDoesnothavegoodsupportforRESTTheaccessmethodscannotberestrictedforinstanceintheaboveexamplewhenusersaccessfootheycanusetheGETPOSTDELETEandHEADHTTPmethodsamongothersInlargeappsroutingrulescanbecomerepetitiveandcumbersomePersonallyIvedevelopedsimplewebAPIscomposedofnearlythirtyroutingruleswheninfacttheserulescouldhavebeenfurthersimplifiedusingmethodstructs

TheBeegoframeworksrouterisdesignedtoovercometheselimitationstakingtheRESTparadigmintoconsiderationandsimplifyingthestoringandforwardingofroutesandrequests

Storingroutes

ToaddressthefirstlimitationofthedefaultrouterweneedtobeabletosupportdynamicURLparametersForthesecondandthirdpointsweadoptanalternativeapproachmappingRESTmethodstostructmethodsandroutingrequeststothisstructinsteadoftohandlerfunctionsThiswayaforwardedrequestcanbehandledaccordingtoitsHTTPmethod

BasedontheaboveideaswevedesignedtwodatatypescontrollerInfowhichsavesthepathandthecorrespondingcontrollerTypestructasareflectTypetypeandControllerRegistorwhichsavesroutinginformationforthespecifiedBeegoapplication

typecontrollerInfostruct

regexregexpRegexp

paramsmap[int]string

controllerTypereflectType

typeControllerRegistorstruct

routers[]controllerInfo

ApplicationApp

ControllerRegistorsexternalinterfacecontainsthefollowingmethod

func(pControllerRegistor)Add(patternstringcControllerInterface)

Itsdetailedimplementationisasfollows

Customizedrouters

281

func(pControllerRegistor)Add(patternstringcControllerInterface)

parts=stringsSplit(pattern)

j=0

params=make(map[int]string)

foripart=rangeparts

ifstringsHasPrefix(part)

expr=([^]+)

ausermaychoosetooverridethedefaultexpression

similartoexpressjslsquouserid([0-9]+)rsquo

ifindex=stringsIndex(part()index=-1

expr=part[index]

part=part[index]

params[j]=part

parts[i]=expr

j++

recreatetheurlpatternwithparametersreplaced

byregularexpressionsThencompiletheregex

pattern=stringsJoin(parts)

regexregexErr=regexpCompile(pattern)

ifregexErr=nil

TODOadderrorhandlingheretoavoidpanic

panic(regexErr)

return

nowcreatetheRoute

t=reflectIndirect(reflectValueOf(c))Type()

route=ampcontrollerInfo

routeregex=regex

routeparams=params

routecontrollerType=t

prouters=append(proutersroute)

StaticroutingWeveimplementeddynamicroutinginourexampleaboveBydefaultGoshttppackagesupportsservingstaticfileswithhttpFileServerwhichreturnsaHandlerSincewehaveimplementedacustomrouterwewillalsoneedawayofhandlingstaticfilesBeegosstaticfolderpathissavedinaglobalvariablecalledStaticDirwhichmapstheURLtocorrespondingpathsTheSetStaticPathsimplementationcanbeseenbelow

func(appApp)SetStaticPath(urlstringpathstring)App

StaticDir[url]=path

returnapp

Theapplicationsstaticroutescanbesetlikeso

beegoSetStaticPath(imgstaticimg)

Forwardingroutes

Customizedrouters

282

WecanforwardroutesbasedontheforwardinginformationcontainedwithinControllerRegistorThedetailedimplementationcanbeseeninthefollowingcodesnippet

AutoRoute

func(pControllerRegistor)ServeHTTP(whttpResponseWriterrhttpRequest)

deferfunc()

iferr=recover()err=nil

ifRecoverPanic

gobacktopanic

panic(err)

else

Critical(Handlercrashedwitherrorerr)

fori=1i+=1

_filelineok=runtimeCaller(i)

ifok

break

Critical(fileline)

()

varstartedbool

forprefixstaticDir=rangeStaticDir

ifstringsHasPrefix(rURLPathprefix)

file=staticDir+rURLPath[len(prefix)]

httpServeFile(wrfile)

started=true

return

requestPath=rURLPath

findamatchingRoute

for_route=rangeprouters

checkifRoutepatternmatchesurl

ifrouteregexMatchString(requestPath)

continue

getsubmatches(params)

matches=routeregexFindStringSubmatch(requestPath)

doublecheckthattheRoutematchestheURLpattern

iflen(matches[0])=len(requestPath)

continue

params=make(map[string]string)

iflen(routeparams)gt0

addurlparameterstothequeryparammap

values=rURLQuery()

forimatch=rangematches[1]

valuesAdd(routeparams[i]match)

params[routeparams[i]]=match

reassemblequeryparamsandaddtoRawQuery

rURLRawQuery=urlValues(values)Encode()+amp+rURLRawQuery

rURLRawQuery=urlValues(values)Encode()

Invoketherequesthandler

vc=reflectNew(routecontrollerType)

init=vcMethodByName(Init)

in=make([]reflectValue2)

ct=ampContextResponseWriterwRequestrParamsparams

in[0]=reflectValueOf(ct)

in[1]=reflectValueOf(routecontrollerTypeName())

initCall(in)

in=make([]reflectValue0)

Customizedrouters

283

method=vcMethodByName(Prepare)

methodCall(in)

ifrMethod==GET

method=vcMethodByName(Get)

methodCall(in)

elseifrMethod==POST

method=vcMethodByName(Post)

methodCall(in)

elseifrMethod==HEAD

method=vcMethodByName(Head)

methodCall(in)

elseifrMethod==DELETE

method=vcMethodByName(Delete)

methodCall(in)

elseifrMethod==PUT

method=vcMethodByName(Put)

methodCall(in)

elseifrMethod==PATCH

method=vcMethodByName(Patch)

methodCall(in)

elseifrMethod==OPTIONS

method=vcMethodByName(Options)

methodCall(in)

ifAutoRender

method=vcMethodByName(Render)

methodCall(in)

method=vcMethodByName(Finish)

methodCall(in)

started=true

break

ifnomatchestourlthrowanotfoundexception

ifstarted==false

httpNotFound(wr)

GettingstartedUsingourrouterdesignwecansolvethethreelimitationsmentionedearlierThethreemainuse-casesare

Registeringroutehandlers

beegoBeeAppRegisterController(ampcontrollersMainController)

Handlingdynamicparameters

beegoBeeAppRegisterController(paramampcontrollersUserController)

Regexmatching

beegoBeeAppRegisterController(usersuid([0-9]+)ampcontrollersUserController)

LinksDirectoryPrevioussectionProjectplanningNextsectionDesigningcontrollers

Customizedrouters

284

Customizedrouters

285

133DesigningcontrollersMosttraditionalMVCframeworksarebasedonsuffixactionmappingNowadaystheRESTstylewebarchitectureisbecomingincreasinglypopularOnecanimplementREST-styleURLsbyfilteringorrewritingthembutwhynotjustdesignanewREST-styleMVCframeworkinsteadThissectionisbasedonthisideaandfocusesondesigningandimplementingacontrollerbasedREST-styleMVCframeworkfromscratchOurgoalistosimplifythedevelopmentofwebapplicationsperhapsevenallowingustowriteasinglelineofcodecapableofservingHelloworld

ThecontrollersroleTheMVCdesignpatterniscurrentlythemostusedframeworkmodelforwebapplicationsBykeepingModelsViewsandControllersseparatedwecankeepourwebapplicationsmodularmaintainabletestableandextensibleAmodelencapsulatesdataandanyofthebusinesslogicthatgovernsthatdatasuchasaccessibilityrulespersistencevalidationetcViewsserveasthedatasrepresentationandinthecaseofwebapplicationstheyusuallyliveastemplateswhicharethenrenderedintoHTMLandservedControllersserveasthegluelogicbetweenModelsandViewsandtypicallyhavemethodsforhandlingdifferentURLsAsdescribedintheprevioussectionwhenaURLrequestisforwardedtoacontrollerbytherouterthecontrollerdelegatescommandstotheModeltoperformsomeactionthennotifiestheViewofanychangesIncertaincasesthereisnoneedformodelstoperformanykindoflogicalordataprocessingorforanyviewstoberenderedForinstanceinthecaseofanHTTP302redirectnoviewneedstoberenderedandnoprocessingneedstobeperformedbytheModelhowevertheControllersjobisstillessential

RESTfuldesigninBeegoTheprevioussectiondescribesregisteringroutehandlerswithRESTfulstructsNowweneedtodesignthebaseclassforalogiccontrollerthatwillbecomposedoftwopartsastructandinterfacetype

typeControllerstruct

CtContext

TpltemplateTemplate

Datamap[interface]interface

ChildNamestring

TplNamesstring

Layout[]string

TplExtstring

typeControllerInterfaceinterface

Init(ctContextcnstring)Initializethecontextandsubclassname

Prepare()someprocessingbeforeexecutionbegins

Get()method=GETprocessing

Post()method=POSTprocessing

Delete()method=DELETEprocessing

Put()method=PUThandling

Head()method=HEADprocessing

Patch()method=PATCHtreatment

Options()method=OPTIONSprocessing

Finish()executedaftercompletionoftreatment

Render()errormethodexecutedafterthecorrespondingmethodtorenderthepage

ThenaddtheroutehandlingfunctiondescribedearlierinthischapterWhenarouteisdefinedtobeaControllerInterfacetypesolongaswecanimplementthisinterfacewecanhaveaccesstothefollowingmethodsofourbaseclasscontroller

func(cController)Init(ctContextcnstring)

cData=make(map[interface]interface)

cLayout=make([]string0)

Designcontrollers

286

cTplNames=

cChildName=cn

cCt=ct

cTplExt=tpl

func(cController)Prepare()

func(cController)Finish()

func(cController)Get()

httpError(cCtResponseWriterMethodNotAllowed405)

func(cController)Post()

httpError(cCtResponseWriterMethodNotAllowed405)

func(cController)Delete()

httpError(cCtResponseWriterMethodNotAllowed405)

func(cController)Put()

httpError(cCtResponseWriterMethodNotAllowed405)

func(cController)Head()

httpError(cCtResponseWriterMethodNotAllowed405)

func(cController)Patch()

httpError(cCtResponseWriterMethodNotAllowed405)

func(cController)Options()

httpError(cCtResponseWriterMethodNotAllowed405)

func(cController)Render()error

iflen(cLayout)gt0

varfilenames[]string

for_file=rangecLayout

filenames=append(filenamespathJoin(ViewsPathfile))

terr=templateParseFiles(filenames)

iferr=nil

Trace(templateParseFileserrerr)

err=tExecuteTemplate(cCtResponseWritercTplNamescData)

iferr=nil

Trace(templateExecuteerrerr)

else

ifcTplNames==

cTplNames=cChildName++cCtRequestMethod++cTplExt

terr=templateParseFiles(pathJoin(ViewsPathcTplNames))

iferr=nil

Trace(templateParseFileserrerr)

err=tExecute(cCtResponseWritercData)

iferr=nil

Trace(templateExecuteerrerr)

returnnil

Designcontrollers

287

func(cController)Redirect(urlstringcodeint)

cCtRedirect(codeurl)

AbovethecontrollerbaseclassalreadyimplementsthefunctionsdefinedintheinterfaceThroughourroutingrulestherequestwillberoutedtotheappropriatecontrollerwhichwillinturnexecutethefollowingmethods

Init()initializationroutine

Prepare()pre-initializationroutineeachinheritingsubclassmayimplementthisfunction

method()dependingontherequestmethodperformdifferentfunctionsGETPOSTPUTHEADetcSubclassesshouldi

mplementthesefunctionsifnotimplementedthenthedefaultis403

Render()optionalmethodDeterminewhetherornottoexecuteaccordingtotheglobalvariableAutoRender

Finish()isexecutedaftertheactionbeencompletedEachinheritingsubclassmayimplementthisfunction

ApplicationguideAbovewevejustfinisheddiscussingBeegosimplementationofthebasecontrollerclassWecannowusethisinformationtodesignourrequesthandlinginheritingfromthebaseclassandimplementingthenecessarymethodsinourowncontroller

packagecontrollers

import(

githubcomastaxiebeego

)

typeMainControllerstruct

beegoController

func(thisMainController)Get()

thisData[Username]=astaxie

thisData[Email]=astaxiegmailcom

thisTplNames=indextpl

InthecodeaboveweveimplementedasubclassofControllercalledMainControllerwhichonlyimplementstheGet()methodIfausertriestoaccesstheresourceusinganyoftheotherHTTPmethods(POSTHEADetc)a403ForbiddenwillbereturnedHoweverifausersubmitsaGETrequesttotheresourceandwehavetheAutoRendervariablesettotruetheresourcescontrollerwillautomaticallycallitsRender()functionrenderingthecorrespondingtemplateandrespondingwiththefollowing

Theindextplcodecanbeseenbelowasyoucanseeparsingmodeldataintoatemplateisquitesimple

ltDOCTYPEhtmlgt

lthtmlgt

ltheadgt

lttitlegtbeegowelcometemplatelttitlegt

ltheadgt

ltbodygt

lth1gtHelloworldUsernameEmaillth1gt

ltbodygt

lthtmlgt

LinksDirectory

Designcontrollers

288

PrevioussectionCustomizingroutersNextsectionLogsandconfigurations

Designcontrollers

289

134Loggingandconfiguration

TheimportanceofloggingandconfigurationPreviouslyinthebookwesawthateventloggingplaysaveryimportantroleinapplicationdevelopmentWithadequateloggingwecanrecordcrucialinformationthatcanlaterbedissectedfordebuggingandoptimizationpurposesInthesectionwherewelookedattheseelogloggingutilitywesawthatithadsettingsforvariousloglevelgradationswhichcanbeessentialforprogramdevelopmentanddeploymentwecansetthelogginglevellowerinadevelopmentenvironmentwhilesettingithighinproductionsothatwecanmaskextraneousinformationwhenwearetryingtodebugourapplication

SettinguptheserverconfigurationmodulefordeployinganapplicationinvolvesanumberofdifferentserversettingsForexamplewetypicallyneedtoprovideinformationregardingdatabaseconfigurationlisteningportsetcviatheconfigurationfileSettingupacentralizedconfigurationfileallowsustheflexibilityofdeployingtheapplicationtodifferentmachinesandconnectingtoremotedatabasesifneeded

TheBeegologgingsystemTheBeegologgersdesignborrowsideasfromseelogandprovidessimilarfunctionalityintermsofsettinglogginglevelsBeegossystemishowevermorelightweightandmakesuseoftheGoslogLoggerinterfaceBydefaultlogsareoutputtoosStdoutbutuserscanimplementthisinterfacethroughbeegoSetLoggertocustomizethisAdetailedexampleofanimplementedinterfacecanbeseenbelow

Loglevelsforcontrollingtheloggingoutput

const(

LevelTrace=iota

LevelDebug

LevelInfo

LevelWarning

LevelError

LevelCritical

)

logLevelcontrolsthegloballoglevelusedbythelogger

varlevel=LevelTrace

LogLevelreturnsthegloballoglevelandcanbeusedin

acustomimplementationsoftheloggerinterface

funcLevel()int

returnlevel

SetLogLevelsetsthegloballoglevelusedbythesimple

logger

funcSetLevel(lint)

level=l

ThissectionimplementstheaboveloggradingsystemThedefaultlevelissettoTraceanduserscancustomizegradinglevelsusingSetLevel

Logsandconfigurations

290

loggerreferencestheusedapplicationlogger

varBeeLogger=logNew(osStdoutlogLdate|logLtime)

SetLoggersetsanewlogger

funcSetLogger(llogLogger)

BeeLogger=l

Tracelogsamessageattracelevel

funcTrace(vinterface)

iflevellt=LevelTrace

BeeLoggerPrintf([T]vnv)

Debuglogsamessageatdebuglevel

funcDebug(vinterface)

iflevellt=LevelDebug

BeeLoggerPrintf([D]vnv)

Infologsamessageatinfolevel

funcInfo(vinterface)

iflevellt=LevelInfo

BeeLoggerPrintf([I]vnv)

Warninglogsamessageatwarninglevel

funcWarn(vinterface)

iflevellt=LevelWarning

BeeLoggerPrintf([W]vnv)

Errorlogsamessageaterrorlevel

funcError(vinterface)

iflevellt=LevelError

BeeLoggerPrintf([E]vnv)

Criticallogsamessageatcriticallevel

funcCritical(vinterface)

iflevellt=LevelCritical

BeeLoggerPrintf([C]vnv)

ThecodesnippetaboveinitializesaBeeLoggerobjectbydefaultoutputtinglogstoosStdoutAsmentioneduserscanimplementbeegoSetLoggertocustomizetheloggersoutputBeeLoggerimplementssixfunctions

Trace(recordgeneralinformationforexample)EnteredparsefunctionvalidationblockValidationenteredsecondifDictionaryDictisemptyUsingdefaultvalue

Debug(debugginginformationforexample)WebpagerequestedhttpsomesitecomParams=ResponsegeneratedResponsesize10000SendingNewfilereceivedTypePNGSize20000

Info(printinggeneralinformationforexample)WebserverrestartedHourlystatisticsRequestedpages12345Errors123ServicepausedWaitingforresumecall

Logsandconfigurations

291

Warn(warningmessagesforexample)Cachecorruptedforfile=testfileReadingfromback-endDatabase19216807DBnotrespondingUsingbackup19216808DBNoresponsefromstatisticsserverStatisticsnotsent

Error(errormessagesforexample)InternalerrorCannotprocessrequest12345ErrorCannotperformlogincredentialsDBnotresponding

Critical(fatalerrorsforexample)CriticalpanicreceivedShuttingdownFatalerrorAppisshuttingdowntopreventdatacorruptionorloss

YoucanseethateachoftheselevelshasaspecificpurposeForinstanceifwesettheloggingleveltoWarn(level=LevelWarning)atthetimeofdeploymentallofthelowerlevellogs(TraceDebugInfo)willnotoutputanything

BeegoconfigurationdesignForprocessingconfigurationinformationBeegoimplementsakey=valuefileparserwhichreadsinformationformattedsimilarlytoiniconfigurationfilesTheparserreadstheconfigurationdataandsavesittoamapFinallyitcallsseveralfunctionsforretrievingthevaluesdatatype(intstringetc)Thedetailedimplementationcanbeseenbelow

Definesomeglobalconstantsfortheiniconfigurationfile

var(

bComment=[]byte

bEmpty=[]byte

bEqual=[]byte=

bDQuote=[]byte

)

Definestheformatoftheconfigurationfile

AConfigrepresentstheconfiguration

typeConfigstruct

filenamestring

commentmap[int][]stringid[]commentkeyid1isformaincomment

datamap[string]stringkeyvalue

offsetmap[string]int64keyoffsetforediting

syncRWMutex

DefinesafunctionforparsingthefileTheprocessbeginsbyopeningthefilethenreadingitlinebylineandparsingcommentsblanklinesandkey=valuedata

Logsandconfigurations

292

ParseFilecreatesanewConfigandparsesthefileconfigurationfromthe

namedfile

funcLoadConfig(namestring)(Configerror)

fileerr=osOpen(name)

iferr=nil

returnnilerr

cfg=ampConfig

fileName()

make(map[int][]string)

make(map[string]string)

make(map[string]int64)

syncRWMutex

cfgLock()

defercfgUnlock()

deferfileClose()

varcommentbytesBuffer

buf=bufioNewReader(file)

fornCommentoff=0int64(1)

line_err=bufReadLine()

iferr==ioEOF

break

ifbytesEqual(linebEmpty)

continue

off+=int64(len(line))

ifbytesHasPrefix(linebComment)

line=bytesTrimLeft(line)

line=bytesTrimLeftFunc(lineunicodeIsSpace)

commentWrite(line)

commentWriteByte(n)

continue

ifcommentLen()=0

cfgcomment[nComment]=[]stringcommentString()

commentReset()

nComment++

val=bytesSplitN(linebEqual2)

ifbytesHasPrefix(val[1]bDQuote)

val[1]=bytesTrim(val[1]``)

key=stringsTrimSpace(string(val[0]))

cfgcomment[nComment-1]=append(cfgcomment[nComment-1]key)

cfgdata[key]=stringsTrimSpace(string(val[1]))

cfgoffset[key]=off

returncfgnil

BelowareanumberoffunctionstheparserusesforreadingtheconfigurationfileThereturnvalueisdeterminedaseitheraboolintfloat64orstring

Logsandconfigurations

293

Boolreturnsthebooleanvalueforagivenkey

func(cConfig)Bool(keystring)(boolerror)

returnstrconvParseBool(cdata[key])

Intreturnstheintegervalueforagivenkey

func(cConfig)Int(keystring)(interror)

returnstrconvAtoi(cdata[key])

Floatreturnsthefloatvalueforagivenkey

func(cConfig)Float(keystring)(float64error)

returnstrconvParseFloat(cdata[key]64)

Stringreturnsthestringvalueforagivenkey

func(cConfig)String(keystring)string

returncdata[key]

ApplicationguideThefollowingfunctionisanexampleofanapplicationIusedtofetchjsondatafromaremoteurladdress

funcGetJson()

resperr=httpGet(beegoAppConfigString(url))

iferr=nil

beegoCritical(httpgetinfoerror)

return

deferrespBodyClose()

bodyerr=ioutilReadAll(respBody)

err=jsonUnmarshal(bodyampAllInfo)

iferr=nil

beegoCritical(errorerr)

BeegosCritical()loggingfunctioniscalledtoreportanyerrorswhichmayoccurintheGetJson()functionbeegoAppConfigString(url)isusedtoobtaininformationfromaconfigurationfile(typicallyappconf)whichmightlooksomethinglikethefollowing

appname=hs

url=httpwwwapicomapihtml

LinksDirectoryPrevioussectionDesigningcontrollersNextsectionAddingdeletingandupdatingblogs

Logsandconfigurations

294

135AddingdeletingandupdatingblogsWevealreadyintroducedtheentireconceptbehindtheBeegoframeworkthroughexamplesandpseudo-codeThissectionwilldescribehowtoimplementabloggingsystemusingBeegoincludingtheabilitytobrowseaddmodifyanddeleteblogposts

BlogdirectoryOurblogsdirectorystructurecanbeseenbelow

maingo

views

viewtpl

newtpl

layouttpl

indextpl

edittpl

modelsmodelgo

controllers

indexgo

viewgo

newgo

deletego

editgo

BlogroutingOurblogsmainroutingrulesareasfollows

ShowblogHome

beegoRegisterController(ampcontrollersIndexController)

Viewblogdetails

beegoRegisterController(viewid([0-9]+)ampcontrollersViewController)

CreateblogBowen

beegoRegisterController(newampcontrollersNewController)

DeleteBowen

beegoRegisterController(deleteid([0-9]+)ampcontrollersDeleteController)

EditBowen

beegoRegisterController(editid([0-9]+)ampcontrollersEditController)

DatabasestructureAtrivialdatabasetabletostorebasicbloginformation

CREATETABLEentries(

idINTAUTO_INCREMENT

titleTEXT

contentTEXT

createdDATETIME

primarykey(id)

)

ControllerIndexController

Adddeleteandupdateblogs

295

typeIndexControllerstruct

beegoController

func(thisIndexController)Get()

thisData[blogs]=modelsGetAll()

thisLayout=layouttpl

thisTplNames=indextpl

ViewController

typeViewControllerstruct

beegoController

func(thisViewController)Get()

inputs=thisInput()

id_=strconvAtoi(thisCtxParams[id])

thisData[Post]=modelsGetBlog(id)

thisLayout=layouttpl

thisTplNames=viewtpl

NewController

typeNewControllerstruct

beegoController

func(thisNewController)Get()

thisLayout=layouttpl

thisTplNames=newtpl

func(thisNewController)Post()

inputs=thisInput()

varblogmodelsBlog

blogTitle=inputsGet(title)

blogContent=inputsGet(content)

blogCreated=timeNow()

modelsSaveBlog(blog)

thisCtxRedirect(302)

EditController

Adddeleteandupdateblogs

296

typeEditControllerstruct

beegoController

func(thisEditController)Get()

inputs=thisInput()

id_=strconvAtoi(thisCtxParams[id])

thisData[Post]=modelsGetBlog(id)

thisLayout=layouttpl

thisTplNames=edittpl

func(thisEditController)Post()

inputs=thisInput()

varblogmodelsBlog

blogId_=strconvAtoi(inputsGet(id))

blogTitle=inputsGet(title)

blogContent=inputsGet(content)

blogCreated=timeNow()

modelsSaveBlog(blog)

thisCtxRedirect(302)

DeleteController

typeDeleteControllerstruct

beegoController

func(thisDeleteController)Get()

id_=strconvAtoi(thisCtxInputParams[id])

blog=modelsGetBlog(id)

thisData[Post]=blog

modelsDelBlog(blog)

thisCtxRedirect(302)

Modellayer

Adddeleteandupdateblogs

297

packagemodels

import(

databasesql

githubcomastaxiebeedb

_githubcomziutekmymysqlgodrv

time

)

typeBlogstruct

Idint`PK`

Titlestring

Contentstring

CreatedtimeTime

funcGetLink()beedbModel

dberr=sqlOpen(mymysqlblogastaxie123456)

iferr=nil

panic(err)

orm=beedbNew(db)

returnorm

funcGetAll()(blogs[]Blog)

db=GetLink()

dbFindAll(ampblogs)

return

funcGetBlog(idint)(blogBlog)

db=GetLink()

dbWhere(id=id)Find(ampblog)

return

funcSaveBlog(blogBlog)(bgBlog)

db=GetLink()

dbSave(ampblog)

returnbg

funcDelBlog(blogBlog)

db=GetLink()

dbDelete(ampblog)

return

Viewlayerlayouttpl

Adddeleteandupdateblogs

298

lthtmlgt

ltheadgt

lttitlegtMyBloglttitlegt

ltstylegt

menu

width200px

floatright

ltstylegt

ltheadgt

ltbodygt

ltulid=menugt

ltligtltahref=gtHomeltagtltligt

ltligtltahref=newgtNewPostltagtltligt

ltulgt

LayoutContent

ltbodygt

lthtmlgt

indextpl

lth1gtBlogpostslth1gt

ltulgt

rangeblogs

ltligt

ltahref=viewIdgtTitleltagt

fromCreated

ltahref=editIdgtEditltagt

ltahref=deleteIdgtDeleteltagt

ltligt

end

ltulgt

viewtpl

lth1gtPostTitlelth1gt

PostCreatedltbrgt

PostContent

newtpl

lth1gtNewBlogPostlth1gt

ltformaction=method=postgt

Titleltinputtype=textname=titlegtltbrgt

Contentlttextareaname=contentcolspan=3rowspan=10gtlttextareagt

ltinputtype=submitgt

ltformgt

edittpl

lth1gtEditPostTitlelth1gt

lth1gtNewBlogPostlth1gt

ltformaction=method=postgt

Titleltinputtype=textname=titlevalue=PostTitlegtltbrgt

Contentlttextareaname=contentcolspan=3rowspan=10gtPostContentlttextareagt

ltinputtype=hiddenname=idvalue=PostIdgt

ltinputtype=submitgt

ltformgt

Adddeleteandupdateblogs

299

LinksDirectoryPrevioussectionLogsandconfigurationsNextsectionSummary

Adddeleteandupdateblogs

300

136SummaryInthischapterwedescribedhowtoimplementthemajorcomponentsofaGowebframeworkWefirstdesignedaroutertomakeupforsomeofshortcomingsinGosbuilt-inhttppackagecreatingaroutercapableofdynamicroutingandRESTsupportWealsodesignedourownRESTfulControllerclassinaccordwiththeprinciplesofMVCborrowingideasfromframeworkssuchasTornadoNextwedesignedandimplementedatemplatelayoutandautomatedrenderingsystemmainlyusingGosbuilt-intemplatingengineWethenimplementedacustomloggerandtalkedaboutframeworkconfigurationtoallowforflexibleapplicationdeploymentThroughthisprocesswehaveimplementedabasicwebframeworkcalledBeegowhichatpresenthasbeenopen-sourcedonGithubLastlyweimplementedasimplebloggingapplicationontopofBeegoAfterhavinggonethroughalloftheseexamplesyouwillhopefullyhavelearnedhowtoquicklydevelopwebsitesinGo

LinksDirectoryPrevioussectionAdddeleteandupdateblogsNextchapterDevelopwebframework

Summary

301

14DevelopingawebframeworkChapter13describedhowtodevelopawebframeworkinGoWeintroducedtheMVCarchitecturearoutingandloggingsystemandwealsolookedatsimpleserverconfigurationThesearethebasicbuildingblocksofmostframeworksanditsagoodstartHoweverformoresophisticatedneedssomeauxiliarytoolsareneededtofacilitaterapidwebsitedevelopmentInthischapterwewillprovidesomequicktipsandtoolsforspeedingupdevelopmentThefirstsectionwillcoverthehow-toshowprocessingstaticfilesandwewillbeusingTwittersopensourceCSSandJavascriptframeworkcalledBootstrapforbeautifyingourwebsiteThesecondsectiondescribeshowtousethepreviouslydescribedsessionsforuserloginprocessingNextthethirdsectiondescribeshowtogenerateformsandhowtoprocesstheseformsforvaliddataWewillalsotalkabouthowtobindmodelsforCRUDoperationsInsection4welldescribehowtoperformsomeuserauthenticationincludingbasicHTTPauthenticationandHTTPdigestauthenticationFinallythelastsectionwilltalkaboutimplementingthepreviouslydescribedi18ntosupportmulti-lingualwebapplications

ByextendingBeegointhischapterwewillbeabletorapidlydevelopfullstackwebapplicationsOfcoursewellgothroughthefeaturesoftheseextensionsstep-by-stepapplyingthemtothebloggingsystemwedevelopedinChapter13ThroughthedevelopmentofacompleteandbeautifulbloggingsystemuserswillhopefullybeabletoseehowBeegocanhelptoboostdeveloperproductivity

LinksDirectoryPreviouschapterChapter13summaryNextsectionStaticfiles

Developwebframework

302

141StaticfilesWevealreadytalkedabouthowtodealwithstaticfilesinprevioussectionsNowletslookathowtosetupandusestaticfilesinsideofBeegoThenthroughintroducingTwittersopensourceHTMLandCSSframeworkBootstrapwellbeablequicklycreatebeautifullookingwebsiteswithouthavingtodotoomuchdesignwork

BeegostaticfilesandsettingsGosnethttppackageprovidesastaticfileserverwithfunctionssuchasServeFileandFileServerBeegosstaticfilehandlingisbasedonthislayeranditsspecificimplementationisasfollow

staticfileserver

forprefixstaticDir=rangeStaticDir

ifstringsHasPrefix(rURLPathprefix)

file=staticDir+rURLPath[len(prefix)]

httpServeFile(wrfile)

wstarted=true

return

StaticDirstorestheURLwhichcorrespondstoastaticfiledirectorysowhenhandlingrequestswesimplyneedtodeterminewhetherornottheURLbeginswithastaticfilepathIfsowecansimplyrespondusinghttpServeFile

Thefollowingisanexample

beegoStaticDir[asset]=static

ThenarequestwithaURLsuchashttpwwwbeegomeassetbootstrapcsswillresultinstaticbootstrapcssbeingservedtotheclient

BootstrapintegrationBootstrapisanopensourceToolkitforfront-enddevelopmentlaunchedbyTwitterFordevelopersBootstrapisoneofthebestfrontendkitsforrapidWebapplicationdevelopmentItisacollectionofHTMLCSSandjavascriptcomponentsusingthelatestHTML5standardsTheseincludearesponsivegridformsbuttonstablesandmanyotherusefulthings

ComponentsBootstrapcontainsawealthofWebcomponentsUsingthesecomponentsyoucanquicklybuildabeautifulfullyfunctionalwebsitewhichincludesthefollowingcomponentsPull-downmenusbuttongroupsbuttondrop-downmenusnavigationnavigationbarsbreadcrumbspaginationlayoutthumbnailswarningdialogsprogressbarsandothermediaobjectsJavaScriptpluginsBootstrapcomeswith13jQueryplug-insforBootstrapcomponentswhichgivesthemlifeTheseincludeModaldialogstabsscrollbarspop-upboxesandsoonBootstrapframeworkcustomizationAllBootstrapcssvariablescanbemodifiedaccordingtoyourneeds

Figure141abootstrapwebsite

NextletsseehowwecanuseBootstrapinsideourBeegoapplicationtoquicklycreateabeautifulwebsite

1 Firstletsdownloadthebootstrapdirectoryintoourprojectsstaticdirectoryasshowninthefollowingscreenshot

Staticfiles

303

Figure142Projectstaticfiledirectorystructure

2 BecauseBeegosetsadefaultvalueforStaticDirifyourstaticfilesdirectoryisstaticthenyouneednotgoanyfurther

StaticDir[static]=static

3 Ourtemplatesusethefollowingassetpaths

cssfile

ltlinkhref=staticcssbootstrapcssrel=stylesheetgt

jsfile

ltscriptsrc=staticjsbootstrap-transitionjsgtltscriptgt

Picturefiles

ltimgsrc=staticimglogopnggt

WiththeabovecodeweareintegratingBootstrapintoourBeegoapplicationThefigurebelowdemonstratestherenderedpage

Figure143websiteintegratedwithBootstrap

ThesetemplatesandformatsallcomeshippedwithBootstrapsowewontrepeatthecompletecodeherehoweveryoucantakealookattheprojectsofficialpagetolearnhowtowriteyourowntemplates

LinksDirectoryPrevioussectionDevelopingawebframeworkNextsectionSessions

Staticfiles

304

142SessionsInchapter6weintroducedsomebasicconceptspertainingtosessionsinGoandweimplementedasessionmanagerTheBeegoframeworkusesthissessionmanagertoimplementsomeconvenientsession-handlingfunctionality

IntegratingsessionsBeegohandlessessionsmainlyaccordingtothefollowingglobalvariables

relatedtosession

SessionOnboolwhetherornottoopenthesessionmoduleDefaultstofalse

SessionProviderstringthedesiredsessionbackendprocessingmoduleDefaultstoanin-memorysessionManager

SessionNamestringthenameoftheclientsavedcookies

SessionGCMaxLifetimeint64cookievalidity

GlobalSessionssessionManagerglobalsessioncontroller

OfcoursethevaluesofthesevariablesshownaboveneedtobeinitializedYoucanalsousethevaluesfromthefollowingconfigurationfilecodetosetthesevalues

ifarerr=AppConfigBool(sessionon)err=nil

SessionOn=false

else

SessionOn=ar

ifar=AppConfigString(sessionprovider)ar==

SessionProvider=memory

else

SessionProvider=ar

ifar=AppConfigString(sessionname)ar==

SessionName=beegosessionID

else

SessionName=ar

ifarerr=AppConfigInt(sessiongcmaxlifetime)err=nilampampar=0

int64val_=strconvParseInt(strconvItoa(ar)1064)

SessionGCMaxLifetime=int64val

else

SessionGCMaxLifetime=3600

AddthefollowingcodeinthebeegoRunfunction

ifSessionOn

GlobalSessions_=sessionNewManager(SessionProviderSessionNameSessionGCMaxLifetime)

goGlobalSessionsGC()

AslongasSessionOnissettotrueitwillopenthesessionbydefaultwithanindependentgoroutinesessionhandler

InordertofacilitateourcustomControllerquicklyusingsessiontheauthorbeegoControllerprovidesthefollowingmethods

ToassistusinquicklyusingsessionsinacustomControllerbeegoControllerprovidesthefollowingmethod

Session

305

func(cController)StartSession()(sesssessionSession)

sess=GlobalSessionsSessionStart(cCtxResponseWritercCtxRequest)

return

UsingsessionsFromthecodeabovewecanseethattheBeegoframeworksimplyinheritsitssessionfunctionalitySohowdoweuseitinourprojects

Firstofallweneedtoopenthesessionattheentrypointofourapplication

beegoSessionOn=true

Wecanthenusethecorrespondingsessionmethodinsideourcontrollerlikeso

func(thisMainController)Get()

varintcountint

sess=thisStartSession()

count=sessGet(count)

ifcount==nil

intcount=0

else

intcount=count(int)

intcount=intcount+1

sessSet(countintcount)

thisData[Username]=astaxie

thisData[Email]=astaxiegmailcom

thisData[Count]=intcount

thisTplNames=indextpl

ThecodeaboveshowshowtousesessionsinthecontrollerlogicTheprocesscanbedividedintotwosteps

1 Gettingsessionobject

GettheobjectsimilarinPHPsession_start()

sess=thisStartSession()

2 Usingthesessionforgeneraloperations

GetthesessionvaluessimilarinPHP$_SESSION[count]

sessGet(count)

Setthesessionvalue

sessSet(countintcount)

AsyoucanseeapplicationsbasedontheBeegoframeworkcaneasilyimplementsessionsTheprocessisverysimilartocallingsession_start()inPHPapplications

LinksDirectoryPrevioussectionStaticfilesNextsectionForms

Session

306

Session

307

143FormsInwebdevelopmentthefollowingworkflowwillprobablylookquitefamiliar

OpenawebpageshowingaformUsersfilloutandsubmittheformIfausersubmitssomeinvalidinformationorhasneglectedtofilloutarequiredfieldtheformwillbereturnedtotheuser(alongwiththefilledindata)withsomedescriptiveinformationabouttheproblemUsersre-filltheinvalidfieldsandcontinueattemptingtosubmittheformuntilitsaccepted

Atthereceivingendthescriptmust

ChecktheusersubmittedformdataVerifywhetherthedataisthecorrecttypeandoftheappropriatestandardForexampleifausernameissubmitteditmustverifythatitcontainsonlyvalidcharactersOtherexampleswouldbecheckingforminimumandmaximumlengthsusernameuniquenessandsoonFilteringdataandcleaningupunsafecharacterstoguaranteethatourapplicationonlyprocessesdatawhichissafeIfnecessarypre-formatthedata(ordatagapsneedtobeclearedthroughtheHTMLcodingandsoon)Preparethedataforinsertionintothedatabase

AlthoughtheprocedureisnotverycomplexitusuallyrequiresalotofboilerplateInadditionwebapplicationsoftenuseavarietyofdifferentcontrolstructurestodisplayerrormessagesonreturnedpagesImplementingformvalidationisasimplebutboringtask

FormsandvalidationFordevelopersthegeneraldevelopmentprocesscanbequitecomplexbutitsmostlyrepetitiveworkSupposeascenarioariseswhereyousuddenlyneedtoaddaformtoyourprojectcausingyoutorewriteallofthelocalcodetiedinwiththeformWeknowthatstructsareaverycommonlyuseddatastructureinGoandBeegousesthemtoitsadvantageforprocessingforminformation

FirstwedefineastructwithfieldscorrespondingtothefieldsinourformelementWecanusestructtagswhichmaptotheformelementasshownbelow

WhendevelopingWebapplicationsfirstdefineastructthatmatchesafieldtoacorrespondingformelementdefinedbyusingastructtagcorrespondingtotheelementinformationandauthenticationinformationasshownbelow

FordevelopersthegeneraldevelopmentprocessisverycomplexandmostlyconsistsofrepeatingthesameworkprocessAssumingascenarioforaprojectwherebyaneedarisestoadddatatoaformthenthelocalcodeoftheentireprocessneedstobemodifiedWeknowinGoastructisacommondatastructuresobeegousesaformstructtoprocessforminformation

Firstdefineastructwithfieldscorrespondingtoourformelementusingstructtagstodefinethecorrespondingformelementandauthenticationinformationlikeso

typeUserstruct

Usernamestring`formtextvalidrequired`

Nicknamestring`formtextvalidrequired`

Ageint`formtextvalidrequired|numeric`

Emailstring`formtextvalidrequired|valid_email`

Introducestring`formtextarea`

Afterdefiningourstructwecanaddthisactioninourcontroller

Form

308

func(thisAddController)Get()

thisData[form]=beegoForm(ampUser)

thisLayout=adminlayouthtml

thisTplNames=adminaddtpl

Theformisdisplayedinourtemplatelikeso

lth1gtNewBlogPostlth1gt

ltformaction=method=postgt

formrender()

ltformgt

AbovewevedefinedtheentirefirststepofdisplayingaformmappedtoastructThenextstepisforuserstofillintheirinformationandsubmittheformafterwhichtheserverwillreceivethedataandverifyitFinallytherecordwillbeinsertedintothedatabase

func(thisAddController)Post()

varuserUser

form=thisGetInput(ampuser)

ifformValidates()

return

modelsUserInsert(ampuser)

thisCtxRedirect(302adminindex)

FormtypeThefollowingtableliststhecorrespondingformelementinformation

lttablecellpadding=0cellspacing=1border=0style=width100class=tablebordergt

lttbodygt

lttrgt

ltthgtNameltthgt

ltthgtparameterltthgt

ltthgtDescriptionltthgt

lttrgt

lttrgt

lttdclass=tdgtltstronggttextltstronggt

lttdgt

lttdclass=tdgtNolttdgt

lttdclass=tdgttextboxinputboxlttdgt

lttrgt

lttrgt

lttdclass=tdgtltstronggtbuttonltstronggt

lttdgt

lttdclass=tdgtNolttdgt

lttdclass=tdgtbuttonlttdgt

lttrgt

lttrgt

lttdclass=tdgtltstronggtcheckboxltstronggt

lttdgt

lttdclass=tdgtNolttdgt

lttdclass=tdgtmulti-selectboxlttdgt

lttrgt

lttrgt

lttdclass=tdgtltstronggtdropdownltstronggt

lttdgt

lttdclass=tdgtNolttdgt

lttdclass=tdgtdrop-downselectionboxlttdgt

Form

309

lttrgt

lttrgt

lttdclass=tdgtltstronggtfileltstronggt

lttdgt

lttdclass=tdgtNolttdgt

lttdclass=tdgtfileuploadlttdgt

lttrgt

lttrgt

lttdclass=tdgtltstronggthiddenltstronggt

lttdgt

lttdclass=tdgtNolttdgt

lttdclass=tdgthiddenelementslttdgt

lttrgt

lttrgt

lttdclass=tdgtltstronggtpasswordltstronggt

lttdgt

lttdclass=tdgtNolttdgt

lttdclass=tdgtpasswordinputboxlttdgt

lttrgt

lttrgt

lttdclass=tdgtltstronggtradioltstronggt

lttdgt

lttdclass=tdgtNolttdgt

lttdclass=tdgtsingleboxlttdgt

lttrgt

lttrgt

lttdclass=tdgtltstronggttextarealtstronggt

lttdgt

lttdclass=tdgtNolttdgt

lttdclass=tdgttextinputboxlttdgt

lttrgt

lttbodygt

lttablegt

FormvalidationThefollowingtablelistssomeformvalidationrulesnativetoBeegothatcanbeused

lttablecellpadding=0cellspacing=1border=0style=width100class=tablebordergt

lttbodygt

lttrgt

ltthgtrulesltthgt

ltthgtparameterltthgt

ltthgtDescriptionltthgt

ltthgtExampleltthgt

lttrgt

lttrgt

lttdclass=tdgtltstronggtrequiredltstronggt

lttdgt

lttdclass=tdgtNolttdgt

lttdclass=tdgtIftheelementisemptyitreturnsFALSElttdgt

lttdclass=tdgtlttdgt

lttrgt

lttrgt

lttdclass=tdgtltstronggtmatchesltstronggt

lttdgt

lttdclass=tdgtYeslttdgt

lttdclass=tdgtiftheformelementsvaluewiththecorrespondingformfieldparametervaluesarenotequalth

enreturn

FALSElttdgt

lttdclass=tdgtmatches[form_item]lttdgt

lttrgt

Form

310

lttrgt

lttdclass=tdgtltstronggtis_uniqueltstronggt

lttdgt

lttdclass=tdgtYeslttdgt

lttdclass=tdgtiftheformelementsvaluewiththespecifiedfieldinatablehasduplicatedataitreturnsF

alse(Translators

NoteForexampleis_unique[UserEmail]thenthevalidationclasswilllookfortheUsertableinthe

Emailfieldthereisnoformelementswiththesamevaluesuchasdepositrepeatitreturnsfalseso

developersdonothavetowriteanotherCallbackverificationcode)lttdgt

lttdclass=tdgtis_unique[tablefield]lttdgt

lttrgt

lttrgt

lttdclass=tdgtltstronggtmin_lengthltstronggt

lttdgt

lttdclass=tdgtYeslttdgt

lttdclass=tdgtformelementvaluesifthecharacterlengthislessthanthenumberofdefinedparametersitre

turnsFALSElttdgt

lttdclass=tdgtmin_length[6]lttdgt

lttrgt

lttrgt

lttdclass=tdgtltstronggtmax_lengthltstronggt

lttdgt

lttdclass=tdgtYeslttdgt

lttdclass=tdgtiftheformelementsvalueisgreaterthanthelengthofthecharacterdefinednumericargument

itreturns

FALSElttdgt

lttdclass=tdgtmax_length[12]lttdgt

lttrgt

lttrgt

lttdclass=tdgtltstronggtexact_lengthltstronggt

lttdgt

lttdclass=tdgtYeslttdgt

lttdclass=tdgtiftheformelementvaluesandparametersdefinedcharacterlengthnumberdoesnotmatchitret

urnsFALSElttdgt

lttdclass=tdgtexact_length[8]lttdgt

lttrgt

lttrgt

lttdclass=tdgtltstronggtgreater_thanltstronggt

lttdgt

lttdclass=tdgtYeslttdgt

lttdclass=tdgtIftheformelementvaluesnon-numerictypesorlessthanthevaluedefinedparametersitret

urnsFALSElttdgt

lttdclass=tdgtgreater_than[8]lttdgt

lttrgt

lttrgt

lttdclass=tdgtltstronggtless_thanltstronggt

lttdgt

lttdclass=tdgtYeslttdgt

lttdclass=tdgtIftheformelementvaluesnon-numerictypesorgreaterthanthevaluedefinedparametersit

returnsFALSElttdgt

lttdclass=tdgtless_than[8]lttdgt

Form

311

lttrgt

lttrgt

lttdclass=tdgtltstronggtalphaltstronggt

lttdgt

lttdclass=tdgtNolttdgt

lttdclass=tdgtIftheformelementvaluecontainscharactersotherthanlettersbesidesitreturnsFALSElttdgt

lttdclass=tdgtlttdgt

lttrgt

lttrgt

lttdclass=tdgtltstronggtalpha_numericltstronggt

lttdgt

lttdclass=tdgtNolttdgt

lttdclass=tdgtIftheformelementvaluescontainedinadditiontolettersandothercharactersotherthannumb

ersitreturns

FALSElttdgt

lttdclass=tdgtlttdgt

lttrgt

lttrgt

lttdclass=tdgtltstronggtalpha_dashltstronggt

lttdgt

lttdclass=tdgtNolttdgt

lttdclass=tdgtIftheformelementvaluecontainsinadditiontotheletternumberunderlinecharactersothe

rthandash

returnsFALSElttdgt

lttdclass=tdgtlttdgt

lttrgt

lttrgt

lttdclass=tdgtltstronggtnumericltstronggt

lttdgt

lttdclass=tdgtNolttdgt

lttdclass=tdgtIftheformelementvaluecontainscharactersotherthannumbersinadditionitreturnsFALSElt

tdgt

lttdclass=tdgtlttdgt

lttrgt

lttrgt

lttdclass=tdgtltstronggtintegerltstronggt

lttdgt

lttdclass=tdgtNolttdgt

lttdclass=tdgtexceptiftheformelementcontainscharactersotherthananintegeritreturnsFALSElttdgt

lttdclass=tdgtlttdgt

lttrgt

lttrgt

lttdclass=tdgtltstronggtdecimalltstronggt

lttdgt

lttdclass=tdgtYeslttdgt

lttdclass=tdgtIftheformelementtype(non-decimal)isnotcompleteitreturnsFALSElttdgt

lttdclass=tdgtlttdgt

lttrgt

lttrgt

lttdclass=tdgtltstronggtis_naturalltstronggt

lttdgt

lttdclass=tdgtNolttdgt

lttdclass=tdgtvalueiftheformelementcontainsanumberofotherunnaturalvalues(othervaluesexcludingz

ero)it

returnsFALSENaturalnumberslikethis0123andsoonlttdgt

lttdclass=tdgtlttdgt

lttrgt

lttrgt

lttdclass=tdgtltstronggtis_natural_no_zeroltstronggt

Form

312

lttdgt

lttdclass=tdgtNolttdgt

lttdclass=tdgtvalueiftheformelementcontainsanumberofotherunnaturalvalues(othervaluesincludingz

ero)it

returnsFALSENonzeronaturalnumbers123andsoonlttdgt

lttdclass=tdgtlttdgt

lttrgt

lttrgt

lttdclass=tdgtltstronggtvalid_emailltstronggt

lttdgt

lttdclass=tdgtNolttdgt

lttdclass=tdgtIftheformelementvaluecontainsinvalidemailaddressitreturnsFALSElttdgt

lttdclass=tdgtlttdgt

lttrgt

lttrgt

lttdclass=tdgtltstronggtvalid_emailsltstronggt

lttdgt

lttdclass=tdgtNolttdgt

lttdclass=tdgtformelementvaluesifanyonevaluecontainsinvalidemailaddress(addressesseparatedbycomm

asinEnglish

)itreturnsFALSElttdgt

lttdclass=tdgtlttdgt

lttrgt

lttrgt

lttdclass=tdgtltstronggtvalid_ipltstronggt

lttdgt

lttdclass=tdgtNolttdgt

lttdclass=tdgtiftheformelementsvalueisnotavalidIPaddressitreturnsFALSElttdgt

lttdclass=tdgtlttdgt

lttrgt

lttrgt

lttdclass=tdgtltstronggtvalid_base64ltstronggt

lttdgt

lttdclass=tdgtNolttdgt

lttdclass=tdgtiftheformelementsvaluecontainsthebase64-encodedcharactersinadditiontootherthanthe

characters

returnsFALSElttdgt

lttdclass=tdgtlttdgt

lttrgt

lttbodygt

lttablegt

LinksDirectoryPrevioussectionSessionsNextsectionUservalidation

Form

313

144UservalidationIntheprocessofdevelopingwebapplicationsuserauthenticationisaproblemwhichdevelopersfrequentlyencounterUserloginregistrationandlogoutamongotheroperationsaswellasgeneralauthenticationcanbedividedintothreeparts

HTTPBasicandHTTPDigestAuthenticationThirdPartyAuthenticationIntegrationQQmicro-bloggingwatercressOPENIDGoogleGitHubFacebookandtwitteretcCustomuserloginregistrationlogoutaregenerallybasedonsessionsandcookieauthentication

BeegodoesnotnativelyprovidesupportforanyofthesethreethingshoweveryoucaneasilymakeuseofexistingthirdpartyopensourcelibrariestoimplementthemThefirsttwoauthenticationsolutionsareonBeegosroadmaptoeventuallybeintegrated

HTTPbasicanddigestauthenticationBothHTTPbasicanddigestauthenticationarerelativelysimpletechniquescommonlyusedbywebapplicationsTherearealreadymanyopensourcethird-partylibrarieswhichsupportthesetwoauthenticationmethodssuchas

githubcomabbotgo-http-auth

ThefollowingcodedemonstrateshowtousethislibrarytoimplementauthenticationinaBeegoapplication

packagecontrollers

import(

githubcomabbotgo-http-auth

githubcomastaxiebeego

)

funcSecret(userrealmstring)string

ifuser==john

passwordishello

return$1$dlPL2MqE$oQmn16q49SqdmhenQuNgs1

return

typeMainControllerstruct

beegoController

func(thisMainController)Prepare()

a=authNewBasicAuthenticator(examplecomSecret)

ifusername=aCheckAuth(thisCtxRequest)username==

aRequireAuth(thisCtxResponseWriterthisCtxRequest)

func(thisMainController)Get()

thisData[Username]=astaxie

thisData[Email]=astaxiegmailcom

thisTplNames=indextpl

TheabovecodetakesadvantageofBeegosprepare()functiontoperformauthenticationbeforeallowingthenormalflowofexecutiontoproceedasyoucanseeitsverysimpletoimplementHTTPauthenticationDigestauthenticationcanbeimplementedinmuchthesameway

Uservalidation

314

OAuthandOAuth2authenticationOAuthandOAuth2arecurrentlytwoofthemostpopularauthenticationmethodsFortunatelytherearethird-partylibrarieswhichimplementthistypeofauthenticationsuchasthegoauthpackageavailableongithub

githubcombradrydzewskigoauth

ThecodebelowdemonstrateshowtousethislibrarytoimplementOAuthauthenticationinBeegousingourGithubcredentials

1 Letsaddsomeroutes

beegoRegisterController(authloginampcontrollersGithubController)

beegoRegisterController(mainpageampcontrollersPageController)

2 ThenwedealwiththeGithubControllerlandingpage

packagecontrollers

import(

githubcomastaxiebeego

githubcombradrydzewskigoauth

)

const(

githubClientKey=a0864ea791ce7e7bd0df

githubSecretKey=a0ec09a647a688a64a28f6190b5a0d2705df56ca

)

typeGithubControllerstruct

beegoController

func(thisGithubController)Get()

settheauthparameters

authConfigCookieSecret=[]byte(7H9xiimk2QdTdYI7rDddfJeV)

authConfigLoginSuccessRedirect=mainpage

authConfigCookieSecure=false

githubHandler=authGithub(githubClientKeygithubSecretKey)

githubHandlerServeHTTP(thisCtxResponseWriterthisCtxRequest)

3 Handlingafterasuccessfullandingpage

Uservalidation

315

packagecontrollers

import(

githubcomastaxiebeego

githubcombradrydzewskigoauth

nethttp

neturl

)

typePageControllerstruct

beegoController

func(thisPageController)Get()

settheauthparameters

authConfigCookieSecret=[]byte(7H9xiimk2QdTdYI7rDddfJeV)

authConfigLoginSuccessRedirect=mainpage

authConfigCookieSecure=false

usererr=authGetUserCookie(thisCtxRequest)

ifnoactiveusersessionthenauthorizeuser

iferr=nil||userId()==

httpRedirect(thisCtxResponseWriterthisCtxRequestauthConfigLoginRedirecthttpStatusSeeOther

)

return

elseaddtheusertotheURLandcontinue

thisCtxRequestURLUser=urlUser(userId())

thisData[pic]=userPicture()

thisData[id]=userId()

thisData[name]=userName()

thisTplNames=hometpl

Thewholeprocessisasfollows

firstopenyourbrowserandentertheaddress

Figure144showsthehomepagewithaloginbutton

Whenclickingonthelinkthefollowingscreenappears

Figure145displayedafterclickingtheloginbuttontoauthenticatewithyourGitHubcredentials

AfterclickingAuthorizeappthefollowingscreenappears

Figure146authorizedGithubinformationgetsdisplayedaftertheloginpage

CustomauthenticationCustomauthenticationisgenerallycombinedwithsessionauthenticationthefollowingcodeisaBeegobasedopensourceblogwhichdemonstratesthis

Loginprocess

func(thisLoginController)Post()

thisTplNames=logintpl

thisCtxRequestParseForm()

username=thisCtxRequestFormGet(username)

Uservalidation

316

password=thisCtxRequestFormGet(password)

md5Password=md5New()

ioWriteString(md5Passwordpassword)

buffer=bytesNewBuffer(nil)

fmtFprintf(bufferxmd5PasswordSum(nil))

newPass=bufferString()

now=timeNow()Format(2006-01-02150405)

userInfo=modelsGetUserInfo(username)

ifuserInfoPassword==newPass

varusersmodelsUser

usersLast_logintime=now

modelsUpdateUserInfo(users)

Setthesessionsuccessfullogin

sess=globalSessionsSessionStart(thisCtxResponseWriterthisCtxRequest)

sessSet(uiduserInfoId)

sessSet(unameuserInfoUsername)

thisCtxRedirect(302)

Registrationprocess

func(thisRegController)Post()

thisTplNames=regtpl

thisCtxRequestParseForm()

username=thisCtxRequestFormGet(username)

password=thisCtxRequestFormGet(password)

usererr=checkUsername(username)

fmtPrintln(usererr)

ifusererr==false

thisData[UsernameErr]=UsernameerrorPleasetoagain

return

passerr=checkPassword(password)

ifpasserr==false

thisData[PasswordErr]=PassworderrorPleasetoagain

return

md5Password=md5New()

ioWriteString(md5Passwordpassword)

buffer=bytesNewBuffer(nil)

fmtFprintf(bufferxmd5PasswordSum(nil))

newPass=bufferString()

now=timeNow()Format(2006-01-02150405)

userInfo=modelsGetUserInfo(username)

ifuserInfoUsername==

varusersmodelsUser

usersUsername=username

usersPassword=newPass

usersCreated=now

usersLast_logintime=now

modelsAddUser(users)

Setthesessionsuccessfullogin

sess=globalSessionsSessionStart(thisCtxResponseWriterthisCtxRequest)

sessSet(uiduserInfoId)

sessSet(unameuserInfoUsername)

thisCtxRedirect(302)

else

thisData[UsernameErr]=Useralreadyexists

Uservalidation

317

funccheckPassword(passwordstring)(bbool)

ifok_=regexpMatchString(^[a-zA-Z0-9]416$password)ok

returnfalse

returntrue

funccheckUsername(usernamestring)(bbool)

ifok_=regexpMatchString(^[a-zA-Z0-9]416$username)ok

returnfalse

returntrue

Onceyouhaveimplementeduserloginandregistrationothermodulescanbeaddedtodeterminewhethertheuserhasbeenloggedinornot

func(thisAddBlogController)Prepare()

sess=globalSessionsSessionStart(thisCtxResponseWriterthisCtxRequest)

sess_uid=sessGet(userid)

sess_username=sessGet(username)

ifsess_uid==nil

thisCtxRedirect(302adminlogin)

return

thisData[Username]=sess_username

LinksDirectoryPrevioussectionFormNextsectionMulti-languagesupport

Uservalidation

318

145Multi-languagesupportInthechapterwhereweintroducedinternationalizationandlocalizationwedevelopedthego-i18nlibraryInthissectionwewillseehowthislibraryisintegratedintotheBeegoframeworkandhowitenablesourBeegoapplicationstosupportbothinternationalizationandlocalization

I18nintegrationBeegofirstsetssomeglobalvariables

Translationi18nIL

Langstringsetthelanguagepackzhen

LangPathstringsetthelanguagepacklocation

Amulti-languageinitializationfunctionisdefined

funcInitLang()

beegoTranslation=i18nNewLocale()

beegoTranslationLoadPath(beegoLangPath)

beegoTranslationSetLocale(beegoLang)

Inordertofacilitatemulti-languagecallsinthetemplatepackagedirectlywedesignedthreefunctionsforhandlingmulti-languageresponses

Multi-languagesupport

319

beegoTplFuncMap[Trans]=i18nI18nT

beegoTplFuncMap[TransDate]=i18nI18nTimeDate

beegoTplFuncMap[TransMoney]=i18nI18nMoney

funcI18nT(argsinterface)string

ok=false

varsstring

iflen(args)==1

sok=args[0](string)

ifok

s=fmtSprint(args)

returnbeegoTranslationTranslate(s)

funcI18nTimeDate(argsinterface)string

ok=false

varsstring

iflen(args)==1

sok=args[0](string)

ifok

s=fmtSprint(args)

returnbeegoTranslationTime(s)

funcI18nMoney(argsinterface)string

ok=false

varsstring

iflen(args)==1

sok=args[0](string)

ifok

s=fmtSprint(args)

returnbeegoTranslationMoney(s)

Multi-languagedevelopment1 Settingthelanguageandlocationofthelanguagepacktheninitializei18nobjects

beegoLang=zh

beegoLangPath=viewslang

beegoInitLang()

2 Designingamulti-languagepackage

Abovewetalkedabouthowtoinitializeamulti-languagepackageNowletslookathowtodesignoneMulti-languagepackagesaretypicallyJSONfilesasyouvealreadyseeninChapter10WemustprovidetranslationfilesforlanguageswewishtosupportonourLangPathsuchasthefollowing

Multi-languagesupport

320

zhjson

zh

submit提交

create创建

enjson

en

submitSubmit

createCreate

3 Usinglanguagepackages

Wecancallthecontrollertogetthetranslatedresponseinthedesiredlanguagelikeso

func(thisMainController)Get()

thisData[create]=beegoTranslationTranslate(create)

thisTplNames=indextpl

Wecanalsodirectlyinterpolatetranslatedresponsesinourtemplates

DirectTexttranslation

create|Trans

Timetotranslate

time|TransDate

Currencytranslation

money|TransMoney

LinksDirectoryPrevioussectionUservalidationNextsectionpprof

Multi-languagesupport

321

146pprofAgreatfeatureofGosstandardlibraryisitscodeperformancemonitoringtoolsThesepackagesexistintwoplaces

nethttppprof

runtimepprof

InfactnethttppprofsimplyexposesruntimeprofilingdatafromtheruntimepprofpackageonanHTTPport

pprofsupportinBeegoTheBeegoframeworkcurrentlysupportspprofhoweveritisnotturnedonbydefaultIfyouneedtotesttheperformanceofyourapplication(forinstancebyviewingtheexecutiongoroutine)suchinformationfromGosdefaultpackagenethttppprofalreadyhasthisfeatureBecausebeegohasrepackagedtheServHTTPfunctionyoucannotopenthedefaultfeatureincludedinpprofThisresultedinbeegosupportingpprofinternally

FirstinourbeegoRunfunctionwechoosewhetherornottoautomaticallyloadtheperformancepackaccordingtoourconfigurationvariable(inthiscasePprofOn)

ifPprofOn

BeeAppRegisterController(`debugpprof`ampProfController)

BeeAppRegisterController(`debugpprofpp([w]+)`ampProfController)

DesigningProfController

packagebeego

import(

nethttppprof

)

typeProfControllerstruct

Controller

func(thisProfController)Get()

switchthisCtxParams[pp]

default

pprofIndex(thisCtxResponseWriterthisCtxRequest)

case

pprofIndex(thisCtxResponseWriterthisCtxRequest)

casecmdline

pprofCmdline(thisCtxResponseWriterthisCtxRequest)

caseprofile

pprofProfile(thisCtxResponseWriterthisCtxRequest)

casesymbol

pprofSymbol(thisCtxResponseWriterthisCtxRequest)

thisCtxResponseWriterWriteHeader(200)

GettingstartedFromtheabovewecanseethatenablingpprofisassimpleassettingthePprofOnconfigurationvariabletotrue

pprof

322

beegoPprofOn=true

YoucanthenopenthefollowingURLinyourbrowsertoseethefollowinginterface

Figure147currentsystemgoroutineheapthreadinformation

Byclickingonagoroutinewecanseealotofdetailedinformation

Figure148showsthecurrentgoroutinedetails

Ofcoursewecanalsogetmoredetailsfromthecommandline

gotoolpprofhttplocalhost8080debugpprofprofile

Thistimetheprogramwillbeginprofilingtheapplicationforaperiodof30secondsduringwhichtimeitwillrepeatedlyrefreshthepageinthebrowserinanattempttogatherCPUusageandperformancedata

(pprof)top10

Total3samples

13333331333MHeap_AllocLocked

13336671333osexec(Cmd)closeDescriptors

133310001333runtimesigprocmask

00010001333MCentral_Grow

00010002667mainCompile

00010002667maincompile

00010002667mainrun

00010001333makeslice1

00010002667nethttp(ServeMux)ServeHTTP

00010002667nethttp(conn)serve

(pprof)web

Figure149showstheexecutionflowofinformation

LinksDirectoryPrevioussectionMulti-languagesupportNextsectionSummary

pprof

323

147SummaryThischapterillustratessomewaysinwhichtheBeegoframeworkcanbeextendedWefirstlookedatstaticfilesupportlearninghowBeegohandlesservingstaticfilesinternallyWesawhowthisfunctionalityallowedustoeasilyintegratestaticassets(suchasBootstrapsCSSfiles)forrapidandgreatlookingwebsitedevelopmentNextwesawhowtointegratesessionManagertopainlesslyfacilitateusersessionsinBeegoWethendescribedformmanagementandvalidationleveragingGosstructstoreducecoderepetitionandforsimplifyingfieldvalidationAfterthatwediscusseduserauthenticationwhichinvolvedthreemainstrategiesHTTPauthentication(basicanddigest)thirdpartyauthenticationandcustomauthenticationWelearnedaboutsomeexistingthirdpartyauthenticationpackagesthathavealreadyimplementedthesestrategieswhichareconvenientlyaccommodatedbyBeegoThenextsectionre-introducedlanguagesupportinBeegowesawhowtointegratethego-i18npackageandlearnedhowtoeasilyloadmultiplelanguagepacksintoourapplicationsasneededLastlywediscussedhowtoworkwithGospprofpackagesinBeegoThepprofpackageisusedforperformanceprofilinginGoandBeegorepackagesitsoitcanservethesamepurposeinBeegoapplicationswithoutmuchadditionalworkThroughthesesixsectionsweveextendedBeegowithmanyfeaturesmakingitintoaversatileframeworksuitablefortherequirementsofmanywebapplicationsUsershavethefreedomofextendingtheframeworktosuittheirindividualneedsthisbriefintroductiontoBeegosimplyoffersasmalltasteofwhatcanbedone

LinksDirectoryPrevioussectionpprofNextchapterAppendixAReferences

Summary

324

AppendixAReferencesThisbookisasummaryofmyGoexperiencesomecontentarefromotherGopherseitherblogsorsitesThankstothem

1 golangblog2 RussCoxsblog3 gobook4 golangtutorials5 轩脉刃de刀光剑影

6 GoProgrammingLanguage7 NetworkprogrammingwithGo8 setup-the-rails-application-for-internationalization9 TheCross-SiteScripting(XSS)FAQ

References

325

1Goenvironmentconfiguration11Installation12$GOPATHandworkspace13Gocommands14Godevelopmenttools15Summary

2Gobasicknowledge21HelloGo22Gofoundation23Controlstatementsandfunctions24struct25Object-oriented26interface27Concurrency28Summary

3Webfoundation31Webworkingprinciples32Buildasimplewebserver33HowGoworkswithweb34Getintohttppackage35Summary

4Userform41Processforminputs42Verificationofinputs43Crosssitescripting44Duplicatesubmissions45Fileupload46Summary

5Database51databasesqlinterface52MySQL53SQLite54PostgreSQL55DevelopORMbasedonbeedb56NoSQLdatabase57Summary

6Datastorageandsession61Sessionandcookies62HowtousesessioninGo63Sessionstorage64Preventhijackofsession65Summary

7Textfiles71XML72JSON73Regexp74Templates75Files76Strings77Summary

8Webservices81Sockets82WebSocket

preface

326

83REST84RPC85Summary

9Securityandencryption91CSRFattacks92Filterinputs93XSSattacks94SQLinjection95Passwordstorage96Encryptanddecryptdata97Summary

10Internationalizationandlocalization101Timezone102Localizedresources103Internationalsites104Summary

11Errorhandlingdebuggingandtesting111Errorhandling112DebuggingbyusingGDB113Writetestcases114Summary

12Deploymentandmaintenance121Logs122Errorsandcrashes123Deployment124Backupandrecovery125Summary

13Buildawebframework131Projectprogram132Customizedrouters133Designcontrollers134Logsandconfigurations135Adddeleteandupdateblogs136Summary

14Developwebframework141Staticfiles142Session143Form144Uservalidation145Multi-languagesupport146pprof147Summary

AppendixAReferences

preface

327

  • Introduction
  • Go Environment Configuration
    • Installation
    • $GOPATH and workspace
    • Go commands
    • Go development tools
    • Summary
      • Go basic knowledge
        • Hello Go
        • Go foundation
        • Control statements and functions
        • struct
        • Object-oriented
        • interface
        • Concurrency
        • Summary
          • Web foundation
            • Web working principles
            • Build a simple web server
            • How Go works with web
            • Get into http package
            • Summary
              • HTTP Form
                • Process form inputs
                • Validation of inputs
                • Cross site scripting
                • Duplicate submissions
                • File upload
                • Summary
                  • Database
                    • databasesql interface
                    • How to use MySQL
                    • How to use SQLite
                    • How to use PostgreSQL
                    • How to use beedb ORM
                    • NOSQL
                    • Summary
                      • Data storage and session
                        • Session and cookies
                        • How to use session in Go
                        • Session storage
                        • Prevent hijack of session
                        • Summary
                          • Text files
                            • XML
                            • JSON
                            • Regexp
                            • Templates
                            • Files
                            • Strings
                            • Summary
                              • Web services
                                • Sockets
                                • WebSocket
                                • REST
                                • RPC
                                • Summary
                                  • Security and encryption
                                    • CSRF attacks
                                    • Filter inputs
                                    • XSS attacks
                                    • SQL injection
                                    • Password storage
                                    • Encrypt and decrypt data
                                    • Summary
                                      • Internationalization and localization
                                        • Time zone
                                        • Localized resources
                                        • International sites
                                        • Summary
                                          • Error handling debugging and testing
                                            • Error handling
                                            • Debugging by using GDB
                                            • Write test cases
                                            • Summary
                                              • Deployment and maintenance
                                                • Logs
                                                • Errors and crashes
                                                • Deployment
                                                • Backup and recovery
                                                • Summary
                                                  • Build a web framework
                                                    • Project program
                                                    • Customized routers
                                                    • Design controllers
                                                    • Logs and configurations
                                                    • Add delete and update blogs
                                                    • Summary
                                                      • Develop web framework
                                                        • Static files
                                                        • Session
                                                        • Form
                                                        • User validation
                                                        • Multi-language support
                                                        • pprof
                                                        • Summary
                                                          • References
                                                          • preface
Page 4: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write

BuildWebApplicationwithGolangPurpose

BecauseIminterestedinwebapplicationdevelopmentIusedmyfreetimetowritethisbookasanopensourceversionItdoesntmeanthatIhaveaverygoodabilitytobuildwebapplicationsIwouldliketosharewhatIvedonewithGoinbuildingwebapplications

ForthoseofyouwhoareworkingwithPHPPythonRubyyouwilllearnhowtobuildawebapplicationwithGoForthoseofyouwhoareworkingwithCC++youwillknowhowthewebworks

IbelievethepurposeofstudyingissharingwithothersThehappiestthinginmylifeissharingeverythingIveknownwithmorepeople

Donate

AliPay

alipay

EnglishDonatedonate

CommunityQQ群386056972

BBShttpgocnio

Acknowledgments四月份平民AprilCitizen(reviewcode)洪瑞琦HongRuiqi(reviewcode)边疆BianJiang(writetheconfigurationsaboutVimandEmacsforGodevelopment)欧林猫OlingCat(reviewcode)吴文磊WenleiWu(providesomepictures)北极星Polaris(reviewwholebook)雨痕RainTrail(reviewchapter2and3)

LicenseThisbookislicensedundertheCCBY-SA30LicensethecodeislicensedunderaBSD3-ClauseLicenseunlessotherwisespecified

GetStarted

Index

Introduction

5

Introduction

6

1GoEnvironmentConfigurationWelcometotheworldofGoletsstartexploring

Goisafast-compiledgarbage-collectedconcurrentsystemsprogramminglanguageIthasthefollowingadvantages

CompilesalargeprojectwithinafewsecondsProvidesasoftwaredevelopmentmodelthatiseasytoreasonaboutavoidingmostoftheproblemsassociatedwithC-styleheaderfilesIsastaticlanguagethatdoesnothavelevelsinitstypesystemsousersdonotneedtospendmuchtimedealingwithrelationsbetweentypesItismorelikealightweightobject-orientedlanguagePerformsgarbagecollectionItprovidesbasicsupportforconcurrencyandcommunicationDesignedformulti-corecomputers

GoisacompiledlanguageItcombinesthedevelopmentefficiencyofinterpretedordynamiclanguageswiththesecurityofstaticlanguagesItisgoingtobethelanguageofchoiceformodernmulti-corecomputerswithnetworkingForthesepurposestherearesomeproblemsthatneedtoinherentlyberesolvedatthelevelofthelanguageofchoicesuchasarichlyexpressivelightweighttypesystemanativeconcurrencymodelandstrictlyregulatedgarbagecollectionForquitesometimenopackagesortoolshaveemergedthathaveaimedtosolvealloftheseproblemsinapragmaticfashionthuswasbornthemotivationfortheGolanguage

InthischapterIwillshowyouhowtoinstallandconfigureyourownGodevelopmentenvironment

LinksDirectoryNextsectionInstallation

GoEnvironmentConfiguration

7

11Installation

ThreewaystoinstallGoTherearemanywaystoconfiguretheGodevelopmentenvironmentonyourcomputerandyoucanchoosewhicheveroneyoulikeThethreemostcommonwaysareasfollows

OfficialinstallationpackagesTheGoteamprovidesconvenientinstallationpackagesinWindowsLinuxMacandotheroperatingsystemsThisisprobablytheeasiestwaytogetstartedYoucangettheinstallersfromtheGolangDownloadPage

InstallityourselffromsourcecodePopularwithdeveloperswhoarefamiliarwithUnix-likesystems

Usingthird-partytoolsTherearemanythird-partytoolsandpackagemanagersforinstallingGolikeapt-getinUbuntuandhomebrewforMac

IncaseyouwanttoinstallmorethanoneversionofGoonacomputeryoushouldtakealookatatoolcalledGVMItisthebesttoolIveseensofarforaccomplishingthistaskotherwiseyoudhavetodealwithityourself

InstallfromsourcecodeTocompileGo15andupwardsyouonlyneedthepreviousversionofGoasGohasachievedbootstrappingYouonlyneedGotocompileGo

TocompileGo14downwardsyouwillneedaCcompilerassomepartsofGoarestillwritteninPlan9CandATampTassembler

OnaMacifyouhaveinstalledXcodeyoualreadyhavethecompiler

OnUnix-likesystemsyouneedtoinstallgccorasimilarcompilerForexampleusingthepackagemanagerapt-get(includedwithUbuntu)onecaninstalltherequiredcompilersasfollows

sudoapt-getinstallgcclibc6-dev

OnWindowsyouneedtoinstallMinGWinordertoinstallgccDontforgettoconfigureyourenvironmentvariablesaftertheinstallationhascompleted(EverythingthatlookslikethismeansitscommentedbyatranslatorIfyouareusing64-bitWindowsyoushouldinstallthe64-bitversionofMinGW)

AtthispointexecutethefollowingcommandstoclonetheGosourcecodeandcompileit(ItwillclonethesourcecodetoyourcurrentdirectorySwitchyourworkpathbeforeyoucontinueThismaytakesometime)

gitclonehttpsgogooglesourcecomgo

cdgosrc

allbash

AsuccessfulinstallationwillendwiththemessageALLTESTSPASSED

OnWindowsyoucanachievethesamebyrunningallbat

IfyouareusingWindowstheinstallationpackagewillsetyourenvironmentvariablesautomaticallyInUnix-likesystemsyouneedtosetthesevariablesmanuallyasfollows(IfyourGoversionisgreaterthan10youdonthavetoset$GOBINanditwillautomaticallyberelatedtoyour$GOROOTbinwhichwewilltalkaboutinthenextsection)

Installation

8

exportGOROOT=$HOMEgo

exportGOBIN=$GOROOTbin

exportPATH=$PATH$GOROOTbin

Ifyouseethefollowinginformationonyourscreenyoureallset

Figure11Informationafterinstallingfromsourcecode

OnceyouseetheusageinformationofGoitmeansyouhavesuccessfullyinstalledGoonyourcomputerIfitsaysnosuchcommandcheckthatyour$PATHenvironmentvariablecontainstheinstallationpathofGo

UsingthestandardinstallationpackagesGohasone-clickinstallationpackagesforeverysupportedoperatingsystemThesepackageswillinstallGoinusrlocalgo(cGoinWindows)bydefaultOfcoursethiscanbemodifiedbutyoualsoneedtochangealltheenvironmentvariablesmanuallyasIveshownabove

Howtocheckifyouroperatingsystemis32-bitor64-bit

Ournextstepdependsonyouroperatingsystemtypesowehavetocheckitbeforewedownloadthestandardinstallationpackages

IfyouareusingWindowspressWin+RandthenrunthecommandtoolTypethesysteminfocommandanditwillshowyousomeusefulsysteminformationFindthelinethatsayssystemtype-ifyouseex64-basedPCthatmeansyouroperatingsystemis64-bit32-bitotherwise

Istronglyrecommenddownloadingthe64-bitpackageifyouareaMacuserasGonolongersupportspure32-bitprocessorsonMacOSX

Linuxuserscantypeuname-aintheterminaltoseesysteminformationA64-bitoperatingsystemwillshowthefollowing

ltsomedescriptiongtx86_64x86_64x86_64GNULinux

somemachinessuchasUbuntu1004willshowasfollowing

x86_64GNULinux

32-bitoperatingsystemsinsteadshow

ltsomedescriptiongti686i686i386GNULinux

Mac

Gotothedownloadpagechoosego142darwin-386pkg(Thelaterversionhasno32-bitdownload)for32-bitsystemsandgo183darwin-amd64pkgfor64-bitsystemsGoingallthewaytotheendbyclickingnext~gobinwillbeaddedtoyoursystems$PATHafteryoufinishtheinstallationNowopentheterminalandtypegoYoushouldseethesameoutputshowninfigure11

Linux

Gotothedownloadpagechoosego183linux-386targzfor32-bitsystemsandgo183linux-amd64targzfor64-bitsystemsSupposeyouwanttoinstallGointhe$GO_INSTALL_DIRpathUncompressthetargztoyourchosenpathusingthecommandtarzxvfgo183linux-amd64targz-C$GO_INSTALL_DIRThensetyour$PATHwiththefollowingexportPATH=$PATH$GO_INSTALL_DIRgobinNowjustopentheterminalandtypegoYoushouldnowseethesameoutputdisplayedinfigure11

Installation

9

Windows

Gotothedownloadpagechoosego183windows-386msifor32-bitsystemsandgo183windows-amd64msifor64-bitsystemsGoingallthewaytotheendbyclickingnextcgobinwillbeaddedtopathNowjustopenacommandlinewindowandtypegoYoushouldnowseethesameoutputdisplayedinfigure11

Usethird-partytools

GVM

GVMisaGomulti-versioncontroltooldevelopedbyathird-partylikervmforrubyItsquiteeasytouseInstallgvmbytypingthefollowingcommandsinyourterminal

bashltlt(curl-s-S-Lhttpsrawgithubcommoovwebgvmmasterbinscriptsgvm-installer)

ThenweinstallGousingthefollowingcommands

gvminstallgo183

gvmusego183

Aftertheprocesshasfinishedyoureallset

apt-get

UbuntuisthemostpopulardesktopreleaseversionofLinuxItusesapt-gettomanagepackagesWecaninstallGousingthefollowingcommands

sudoadd-apt-repositoryppagophersgo

sudoapt-getupdate

sudoapt-getinstallgolang-go

wget

wgethttpsstoragegoogleapiscomgolanggo183linux-amd64targz

sudotar-xzfgo183linux-amd64targz-Cusrlocal

Goenvironment

exportGOROOT=usrlocalgo

exportGOBIN=$GOROOTbin

exportPATH=$PATH$GOBIN

exportGOPATH=$HOMEgopath

Startingfromgo18TheGOPATHenvironmentvariablenowhasadefaultvalueifitisunsetItdefaultsto$HOMEgoonUnixandUSERPROFILEgoonWindows

HomebrewHomebrewisasoftwaremanagementtoolcommonlyusedinMactomanagepackagesJusttypethefollowingcommandstoinstallGo

1 InstallHomebrew

usrbinruby-e$(curl-fsSLhttpsrawgithubusercontentcomHomebrewinstallmasterinstall)

Installation

10

1 InstallGo

brewupdateampampbrewupgrade

brewinstallgo

LinksDirectoryPrevioussectionGoenvironmentconfigurationNextsection$GOPATHandworkspace

Installation

11

12$GOPATHandworkspace

$GOPATHGotakesauniqueapproachtomanagethecodefileswiththeintroductionofa$GOPATHdirectorywhichcontainsallthegocodeinthemachineNotethatthisisdifferentfromthe$GOROOTenvironmentvariablewhichstateswheregoisinstalledonthemachineWehavetodefinethe$GOPATHvariablebeforeusingthelanguageinnixsystemsthereisafilecalledprofileweneedtoappendthebelowexportstatementtothefileTheconceptbehindgopathisanovelonewherewecanlinktoanygocodeatanyinstantoftimewithoutambiguity

Startingfromgo18theGOPATHenvironmentvariablenowhasadefaultvalueifitisunsetItdefaultsto$HOMEgoonUnixandUSERPROFILEgoonWindows

InUnix-likesystemsthevariableshouldbeusedlikethis

exportGOPATH=$HOMEmygo

InWindowsyouneedtocreateanewenvironmentvariablecalledGOPATHthensetitsvaluetocmygo(Thisvaluedependsonwhereyourworkspaceislocated)

ItsOKtohavemorethanonepath(workspace)in$GOPATHbutrememberthatyouhavetouse(inWindows)tobreakthemupAtthispointgogetwillsavethecontenttoyourfirstpathin$GOPATHItishighlyrecommendedtonothavemultiplesversionstheworstcaseistocreateafolderbythenameofyourprojectrightinside$GOPATHitbreakseverythingthatthecreatorswerewishingtochangeinprogrammingwiththecreationofgolanguagebecausewhenyoucreateafolderinside$GOPATHyouwillreferenceyourpackagesasdirectlyasandthisbreaksalltheapplicationswhichwillimportyourpackagebecausethegogetwontfindyourpackagePleasefollowconventionsthereisareasonconventionsarecreated

In$GOPATHyoumusthavethreefoldersasfollows

srcforsourcefileswhosesuffixisgocgspkgforcompiledfileswhosesuffixisabinforexecutablefiles

InthisbookIusemygoasmyonlypathin$GOPATH

PackagedirectoryCreatepackagesourcefilesandfolderslike$GOPATHsrcmymathsqrtgo(mymathisthepackagename)(Authorusesmymathashispackagenameandthesamenameforthefolderthatcontainsthepackagesourcefiles)

EverytimeyoucreateapackageyoushouldcreateanewfolderinthesrcdirectorywiththenotableexceptionofmainforwhichmainfoldercreationisoptionalFoldernamesareusuallythesameasthepackagethatyouaregoingtouseYoucanhavemulti-leveldirectoriesifyouwanttoForexampleifyoucreatethedirectory$GOPATHsrcgithubcomastaxiebeedbthenthepackagepathwouldbegithubcomastaxiebeedbThepackagenamewillbethelastdirectoryinyourpathwhichisbeedbinthiscase

Executefollowingcommands(Nowauthorgoesbacktotalkexamples)

cd$GOPATHsrc

mkdirmymath

Createanewfilecalledsqrtgotypethefollowingcontenttoyourfile

$GOPATHandworkspace

12

Sourcecodeof$GOPATHsrcmymathsqrtgo

packagemymath

funcSqrt(xfloat64)float64

z=00

fori=0ilt1000i++

z-=(zz-x)(2x)

returnz

NowmypackagedirectoryhasbeencreatedanditscodehasbeenwrittenIrecommendthatyouusethesamenameforyourpackagesastheircorrespondingdirectoriesandthatthedirectoriescontainallofthepackagesourcefiles

CompilepackagesWevealreadycreatedourpackageabovebuthowdowecompileitforpracticalpurposesTherearetwowaystodothis

1 Switchyourworkpathtothedirectoryofyourpackagethenexecutethegoinstallcommand2 Executetheabovecommandexceptwithafilenamelikegoinstallmymath

Aftercompilingwecanopenthefollowingfolder

cd$GOPATHpkg$GOOS_$GOARCH

youcanseethefilewasgenerated

mymatha

ThefilewhosesuffixisaisthebinaryfileofourpackageHowdoweuseit

Obviouslyweneedtocreateanewapplicationtouseit

Createanewapplicationpackagecalledmathapp

cd$GOPATHsrc

mkdirmathapp

cdmathapp

vimmaingo

Writethefollowingcontenttomaingo

$GOPATHsrcmathappmaingosourcecode

packagemain

import(

mymath

fmt

)

funcmain()

fmtPrintf(HelloworldSqrt(2)=vnmymathSqrt(2))

Tocompilethisapplicationyouneedtoswitchtotheapplicationdirectorywhichinthiscaseis$GOPATHsrcmathappthenexecutethegoinstallcommandNowyoushouldseeanexecutablefilecalledmathappwasgeneratedinthedirectory$GOPATHbinTorunthisprogramusethemathappcommandYoushouldseethefollowingcontentinyourterminal

HelloworldSqrt(2)=1414213562373095

$GOPATHandworkspace

13

InstallremotepackagesGohasatoolforinstallingremotepackageswhichisacommandcalledgogetItsupportsmostopensourcecommunitiesincludingGithubGoogleCodeBitBucketandLaunchpad

gogetgithubcomastaxiebeedb

Youcanusegoget-uhelliptoupdateyourremotepackagesanditwillautomaticallyinstallallthedependentpackagesaswell

ThistoolwillusedifferentversioncontroltoolsfordifferentopensourceplatformsForexamplegitforGithubandhgforGoogleCodeThereforeyouhavetoinstalltheseversioncontroltoolsbeforeyouusegoget

Afterexecutingtheabovecommandsthedirectorystructureshouldlooklikefollowing

$GOPATH

src

|-githubcom

|-astaxie

|-beedb

pkg

|--$GOOS_$GOARCH

|-githubcom

|-astaxie

|-beedba

Actuallygogetclonessourcecodetothe$GOPATHsrcofthelocalfilesystemthenexecutesgoinstall

Youcanuseremotepackagesinthesamewaythatweuselocalpackages

importgithubcomastaxiebeedb

DirectorycompletestructureIfyouvefollowedalloftheabovestepsyourdirectorystructureshouldnowlooklikethefollowing

bin

mathapp

pkg

$GOOS_$GOARCHsuchasdarwin_amd64linux_amd64

mymatha

githubcom

astaxie

beedba

src

mathapp

maingo

mymath

sqrtgo

githubcom

astaxie

beedb

beedbgo

utilgo

Nowyouareabletoseethedirectorystructureclearlybincontainsexecutablefilespkgcontainscompiledfilesandsrccontainspackagesourcefiles

(TheformatofenvironmentvariablesinWindowsisGOPATHhoweverthisbookmainlyfollowstheUnix-stylesoWindowsusersneedtoreplacetheseyourself)

$GOPATHandworkspace

14

LinksDirectoryPrevioussectionInstallationNextsectionGocommands

$GOPATHandworkspace

15

13Gocommands

GocommandsTheGolanguagecomeswithacompletesetofcommandoperationtoolsYoucanexecutethegocommandontheterminaltoseethem

Figure13Gocommanddisplaysdetailedinformation

TheseareallusefulforusLetsseehowtousesomeofthem

gobuildThiscommandisforcompilingtestsItwillcompilepackagesanddependenciesifitsnecessary

Ifthepackageisnotthemainpackagesuchasmymathinsection12nothingwillbegeneratedafteryouexecutegobuildIfyouneedthepackagefileain$GOPATHpkgusegoinstallinsteadIfthepackageisthemainpackageitwillgenerateanexecutablefileinthesamefolderIfyouwantthefiletobegeneratedin$GOPATHbinusegoinstallorgobuild-o$PATH_HEREaexeIftherearemanyfilesinthefolderbutyoujustwanttocompileoneofthemyoushouldappendthefilenameaftergobuildForexamplegobuildagogobuildwillcompileallthefilesinthefolderYoucanalsoassignthenameofthefilethatwillbegeneratedForinstanceinthemathappproject(insection12)usinggobuild-oastaxieexewillgenerateastaxieexeinsteadofmathappexeThedefaultnameisyourfoldername(non-mainpackage)orthefirstsourcefilename(mainpackage)

(AccordingtoTheGoProgrammingLanguageSpecificationpackagenamesshouldbethenameafterthewordpackageinthefirstlineofyoursourcefilesItdoesnthavetobethesameasthefoldernameandtheexecutablefilenamewillbeyourfoldernamebydefault)

gobuildignoresfileswhosenamesstartwith_orIfyouwanttohavedifferentsourcefilesforeveryoperatingsystemyoucannamefileswiththesystemnameasasuffixSupposetherearesomesourcefilesforloadingarraysTheycouldbenamedasfollows

array_linuxgo|array_darwingo|array_windowsgo|array_freebsdgo

gobuildchoosestheonethatsassociatedwithyouroperatingsystemForexampleitonlycompilesarray_linuxgoinLinuxsystemsandignoresalltheothers

gocleanThiscommandisforcleaningfilesthataregeneratedbycompilersincludingthefollowingfiles

_objolddirectoryofobjectleftbyMakefiles

_testolddirectoryoftestleftbyMakefiles

_testmaingoolddirectoryofgotestleftbyMakefiles

testoutolddirectoryoftestleftbyMakefiles

buildoutolddirectoryoftestleftbyMakefiles

[568ao]objectfilesleftbyMakefiles

DIR(exe)generatedbygobuild

DIRtest(exe)generatedbygotest-c

MAINFILE(exe)generatedbygobuildMAINFILEgo

Gocommands

16

IusuallyusethiscommandtocleanupmyfilesbeforeIuploadmyprojecttoGithubTheseareusefulforlocaltestsbutuselessforversioncontrol

gofmtandgofmtThepeoplewhoareworkingwithCC++shouldknowthatpeoplearealwaysarguingaboutwhichcodestyleisbetterKampR-styleorANSI-styleHoweverinGothereisonlyonecodestylewhichisenforcedForexampleleftbracesmustonlybeinsertedattheendoflinesandtheycannotbeontheirownlinesotherwiseyouwillgetcompileerrorsFortunatelyyoudonthavetoremembertheserulesgofmtdoesthisjobforyouJustexecutethecommandgofmtltFilenamegtgointerminalIdontusethiscommandverymuchbecauseIDEsusuallyexecutethiscommandautomaticallywhenyousavesourcefilesIwilltalkmoreaboutIDEsinthenextsection

gofmtisjustanaliaswhichrunsthecommandgofmt-l-wonthepackagesnamedbytheimportpaths

Weusuallyusegofmt-winsteadofgofmtThelatterwillnotrewriteyoursourcefilesafterformattingcodegofmt-wsrcformatsthewholeproject

gogetThiscommandisforgettingremotepackagesSofaritsupportsBitBucketGithubGoogleCodeandLaunchpadThereareactuallytwothingsthathappenafterweexecutethiscommandThefirstthingisthatGodownloadsthesourcecodethenexecutesgoinstallBeforeyouusethiscommandmakesureyouhaveinstalledalloftherelatedtools

BitBucket(MercurialGit)

Github(git)

GoogleCode(GitMercurialSubversion)

Launchpad(Bazaar)

InordertousethiscommandyouhavetoinstallthesetoolscorrectlyDontforgettoupdatethe$PATHvariableBythewayitalsosupportscustomizeddomainnamesUsegohelpimportpathformoredetailsaboutthis

goinstallThiscommandcompilesallpackagesandgeneratesfilesthenmovesthemto$GOPATHpkgor$GOPATHbin

gotestThiscommandloadsallfileswhosenameinclude_testgoandgeneratestestfilesthenprintsinformationthatlookslikethefollowing

okarchivetar0011s

FAILarchivezip0022s

okcompressgzip0033s

IttestsallyourtestfilesbydefaultUsecommandgohelptestflagformoredetails

godocManypeoplesaythatwedontneedanythird-partydocumentationforprogramminginGo(actuallyIvemadeaCHMalready)Gohasapowerfultooltomanagedocumentationnatively

Gocommands

17

SohowdowelookuppackageinformationindocumentationForinstanceifyouwanttogetmoredetailsaboutthebuiltinpackageusethegodocbuiltincommandSimilarlyusethegodocnethttpcommandtolookupthehttppackagedocumentationIfyouwanttoseemoredetailsaboutspecificfunctionsusethegodocfmtPrintfandgodoc-srcfmtPrintfcommandstoviewthesourcecode

Executethegodoc-http=8080commandthenopen1270018080inyourbrowserYoushouldseealocalizedgolangorgItcannotonlyshowthestandardpackagesinformationbutalsopackagesinyour$GOPATHpkgItsgreatforpeoplewhoaresufferingfromtheGreatFirewallofChina

OthercommandsGoprovidesmorecommandsthanthosewevejusttalkedabout

gofixupgradecodefromanoldversionbeforego1toanewversionaftergo1

goversiongetinformationaboutyourversionofGo

goenvviewenvironmentvariablesaboutGo

golistlistallinstalledpackages

goruncompiletemporaryfilesandruntheapplication

TherearealsomoredetailsaboutthecommandsthatIvetalkedaboutYoucanusegohelpltcommandgttolookthemup

LinksDirectoryPrevioussection$GOPATHandworkspaceNextsectionGodevelopmenttools

Gocommands

18

GodevelopmenttoolsInthissectionImgoingtoshowyouafewIDEsthatcanhelpyoubecomeamoreefficientprogrammerwithcapabilitiessuchasintelligentcodecompletionandauto-formattingTheyareallcross-platformsothestepsIwillbeshowingyoushouldnotbeverydifferentevenifyouarenotusingthesameoperatingsystem

LiteIDELiteIDEisanopensourcelightweightIDEfordevelopingGoprojectsonlydevelopedbyvisualfc

Figure14MainpanelofLiteIDE

LiteIDEfeatures

Cross-platformWindowsLinuxMacOS

Cross-compileManagemultiplecompileenvironmentsSupportscross-compilationofGo

ProjectmanagementstandardDocumentationviewbasedon$GOPATHCompilationsystembasedon$GOPATHAPIdocumentationindexbasedon$GOPATH

GosourcecodeeditorCodeoutliningFullsupportofgocodeGodocumentationviewandAPIindexViewcodeexpressionusingF1FunctiondeclarationjumpusingF2GdbsupportAuto-formatwithgofmt

OthersMulti-languagePluginsystemTexteditorthemesSyntaxsupportbasedonKateintelligentcompletionbasedonfull-textCustomizedshortcutsMarkdownsupport

Real-timepreviewCustomizedCSSExportHTMLandPDFConvertandmergetoHTMLandPDF

LiteIDEinstallationInstallLiteIDE

Downloadpage

Godevelopmenttools

19

Sourcecode

YouneedtoinstallGofirstthendownloadtheversionappropriateforyouroperatingsystemDecompressthepackagetodirectlyuseit

Installgocode

Youhavetoinstallgocodeinordertouseintelligentcompletion

goget-ugithubcomnsfgocode

Compilationenvironment

SwitchconfigurationinLiteIDEtosuityouroperatingsystemInWindowsandusingthe64-bitversionofGoyoushouldchoosewin64astheconfigurationenvironmentinthetoolbarThenchooseOptionsfindLiteEnvintheleftlistandopenfilewin64envintherightlist

GOROOT=cgo

GOBIN=

GOARCH=amd64

GOOS=windows

CGO_ENABLED=1

PATH=GOBINGOROOTbinPATH

ReplaceGOROOT=cgotoyourGoinstallationpathsaveitIfyouhaveMinGW64addcMinGW64bintoyourpathenvironmentvariableforcgosupport

InLinuxandusingthe64-bitversionofGoyoushouldchooselinux64astheconfigurationenvironmentinthetoolbarThenchooseOptionsfindLiteEnvintheleftlistandopenthelinux64envfileintherightlist

GOROOT=$HOMEgo

GOBIN=

GOARCH=amd64

GOOS=linux

CGO_ENABLED=1

PATH=$GOBIN$GOROOTbin$PATH

ReplaceGOROOT=$HOMEgotoyourGoinstallationpathsaveit

$GOPATH$GOPATHisthepaththatcontainsalistofprojectsOpenthecommandtool(orpressCtrl+`inLiteIDE)thentypegohelpgopathformoredetailsItsveryeasytoviewandchange$GOPATHinLiteIDEFollowView-SetupGOPATHtoviewandchangethesevalues

SublimeTextHereImgoingtointroduceyoutheSublimeText3(Sublimeforshort)+GoSublime+gocodeLetmeexplainwhy

Intelligentcompletion

Figure15Sublimeintelligentcompletion

Auto-formatsourcefilesProjectmanagement

Godevelopmenttools

20

Figure16Sublimeprojectmanagement

Syntaxhighlight

FreetrialforeverwithnofunctionallimitationsYoumaybepromptedonceinawhiletoremindyoutopurchasealicensebutyoucansimplyignoreitifyouwishOfcourseifyoudofindthatitenhancesyourproductivityandyoureallyenjoyusingitpleasepurchaseacopyofitandsupportitscontinueddevelopment

FirstdownloadtheversionofSublimesuitableforyouroperatingsystem

1 PressCtrl+`openthecommandtoolandinputthefollowingcommands

ApplicabletoSublimeText3

importurllibrequestospf=PackageControlsublime-packageipp=sublimeinstalled_packages_path()urllibrequesti

nstall_opener(urllibrequestbuild_opener(urllibrequestProxyHandler()))open(ospathjoin(ipppf)wb)write(urlli

brequesturlopen(httpsublimewbondnet+pfreplace(20))read())

ApplicabletoSublimeText2

importurllib2ospf=PackageControlsublime-packageipp=sublimeinstalled_packages_path()osmakedirs(ipp)ifnotos

pathexists(ipp)elseNoneurllib2install_opener(urllib2build_opener(urllib2ProxyHandler()))open(ospathjoin(ipp

pf)wb)write(urllib2urlopen(httpsublimewbondnet+pfreplace(20))read())print(PleaserestartSubl

imeTexttofinishinstallation)

RestartSublimeTextwhentheinstallationhasfinishedYoushouldthenfinda`PackageControl`optioninthePref

erencesmenu

[](images14sublime3pngraw=true)

Figure17SublimePackageControl

1 ToinstallGoSublimeSidebarEnhancementsandGoBuildpressCtrl+Shift+ptoopenPackageControlthentypepcip(shortforPackageControlInstallPackage)

Figure18SublimeInstallPackages

NowtypeinGoSublimepressOKtoinstallthepackageandrepeatthesamestepsforinstallingSidebarEnhancementsandGoBuildOnceagainrestarttheeditorwhenitcompletestheinstallation

2 ToverifythattheinstallationissuccessfulopenSublimethenopenthemaingofiletoseeifithasthepropersyntaxhighlightingTypeimporttoseeifcodecompletionpromptsappearAftertypingimportfmttypefmtanywhereaftertheimportdeclarationtoseewhetherornotintelligentcodecompletionforfunctionswassuccessfullyenabled

Ifeverythingisfineyoureallset

Ifnotcheckyour$PATHagainOpenaterminaltypegocodeIfitdoesnotrunyour$PATHwasnotconfiguredcorrectly

VimVimisapopulartexteditorforprogrammerswhichevolvedfromitsslimmerpredecessorViIthasfunctionsforintelligentcompletioncompilationandjumpingtoerrors

vim-goisvimaboveanopen-sourcegolanguageusingthemostextensivedevelopmentenvironmentplug-ins

Thepluginaddressgithubcomfatihvim-go

Godevelopmenttools

21

VimpluginmanagementarethemainstreamPathogenandVundleButtheaspectsthereofaredifferentPathogenistosolveeachplug-inaftertheinstallationoffilesscatteredtomultipledirectoriesandpoormanagementoftheexistenceVundleistosolvetheautomaticsearchanddownloadplug-insexistThesetwoplug-inscanbeusedsimultaneously

1InstallVundle

mkdir~vimbundle

gitclonehttpsgithubcomgmarikVundlevimgit~vimbundleVundlevim

EditvimrcVundletherelevantconfigurationwillbeplacedinthebeginning(RefertotheVundledocumentationfordetails)

setnocompatiblebeiMprovedrequired

filetypeoffrequired

settheruntimepathtoincludeVundleandinitialize

setrtp+=~vimbundleVundlevim

callvundlebegin()

letVundlemanageVundlerequired

PlugingmarikVundlevim

AllofyourPluginsmustbeaddedbeforethefollowingline

callvundleend()required

filetypepluginindentonrequired

2InstallVim-go

Edit~vimrcAddalinebetweenvundlebeginandvundleend

Pluginfatihvim-go

ExecutedwithinVimPluginInstall

3InstallYCM(YourCompleteMe)toAutoCompleteAddalineto~vimrc

PluginValloricYouCompleteMe

ExecutedwithinVimPluginInstall

Figure18VimintelligentcompletionforGo

1 SyntaxhighlightingforGo

cp-r$GOROOTmiscvim~vim

2 Enablingsyntaxhighlighting

filetypepluginindenton

syntaxon

3 Installgocode

goget-ugithubcomnsfgocode

gocodewillbeinstalledin$GOBINasdefault

Godevelopmenttools

22

4 Configuregocode

~cd$GOPATHsrcgithubcomnsfgocodevim

~updatesh

~gocodesetpropose-builtinstrue

propose-builtinstrue

~gocodesetlib-pathhomebordergocodepkglinux_amd64

lib-pathhomebordergocodepkglinux_amd64

~gocodeset

propose-builtinstrue

lib-pathhomebordergocodepkglinux_amd64

Explanationofgocodeconfiguration

propose-builtinsspecifieswhetherornottoopenintelligentcompletionfalsebydefaultlib-pathgocodeonlysearchesforpackagesin$GOPATHpkg$GOOS_$GOARCHand$GOROOTpkg$GOOS_$GOARCHThissettingcanbeusedtoaddadditionalpaths

5 CongratulationsTryemaingotoexperiencetheworldofGo

EmacsEmacsistheso-calledWeaponofGodSheisnotonlyaneditorbutalsoapowerfulIDE

Figure110EmacsmainpanelofGoeditor

1 Syntaxhighlighting

cp$GOROOTmiscemacs~emacsd

2 Installgocode

goget-ugithubcomnsfgocode

gocodewillbeinstalledin$GOBINasdefault

3 Configuregocode

~cd$GOPATHsrcgithubcomnsfgocodevim

~updatebash

~gocodesetpropose-builtinstrue

propose-builtinstrue

~gocodesetlib-pathhomebordergocodepkglinux_amd64

lib-pathhomebordergocodepkglinux_amd64

~gocodeset

propose-builtinstrue

lib-pathhomebordergocodepkglinux_amd64

4 InstallAutoCompletionDownloadanduncompress

~makeinstallDIR=$HOMEemacsdauto-complete

Configure~emacsfile

Godevelopmenttools

23

auto-complete

(requireauto-complete-config)

(add-to-listac-dictionary-directories~emacsdauto-completeac-dict)

(ac-config-default)

(local-set-key(kbdM-)semantic-complete-analyze-inline)

(local-set-keysemantic-complete-self-insert)

(local-set-keygtsemantic-complete-self-insert)

Followthislinkformoredetails

5 Configureemacs

golangmode

(requirego-mode-load)

(requirego-autocomplete)

speedbar

(speedbar1)

(speedbar-add-supported-extensiongo)

(add-hook

go-mode-hook

(lambda()

gocode

(auto-complete-mode1)

(setqac-sources(ac-source-go))

ImenuampSpeedbar

(setqimenu-generic-expression

((type^type([^tnrf])1)

(func^func()1)))

(imenu-add-to-menubarIndex)

Outlinemode

(make-local-variableoutline-regexp)

(setqoutline-regexp|[^rnf][^rnf]|pack|func|impo|cons|var|type|tt)

(outline-minor-mode1)

(local-set-keyM-aoutline-previous-visible-heading)

(local-set-keyM-eoutline-next-visible-heading)

Menubar

(requireeasymenu)

(defconstgo-hooked-menu

(Gotools

[Gorunbuffergot]

[Goreformatbuffergo-fmt-buffert]

[Gocheckbuffergo-fix-buffert]))

(easy-menu-define

go-added-menu

(current-local-map)

Gotools

go-hooked-menu)

Other

(setqshow-trailing-whitespacet)

))

helperfunction

(defungo()

runcurrentbuffer

(interactive)

(compile(concatgorun(buffer-file-name))))

helperfunction

(defungo-fmt-buffer()

rungofmtoncurrentbuffer

(interactive)

(ifbuffer-read-only

(progn

(ding)

(messageBufferisreadonly))

(let((p(line-number-at-pos))

(filename(buffer-file-name))

(old-max-mini-window-heightmax-mini-window-height))

(show-all)

(if(get-bufferGoReformatErrors)

Godevelopmenttools

24

(progn

(delete-windows-onGoReformatErrors)

(kill-bufferGoReformatErrors)))

(setqmax-mini-window-height1)

(if(=0(shell-command-on-region(point-min)(point-max)gofmtGoReformatOutputnilGoRefor

matErrorst))

(progn

(erase-buffer)

(insert-buffer-substringGoReformatOutput)

(goto-char(point-min))

(forward-line(1-p)))

(with-current-bufferGoReformatErrors

(progn

(goto-char(point-min))

(while(re-search-forwardltstandardinputgtnilt)

(replace-matchfilename))

(goto-char(point-min))

(compilation-mode))))

(setqmax-mini-window-heightold-max-mini-window-height)

(delete-windows-onGoReformatOutput)

(kill-bufferGoReformatOutput))))

helperfunction

(defungo-fix-buffer()

rungofixoncurrentbuffer

(interactive)

(show-all)

(shell-command-on-region(point-min)(point-max)gotoolfix-diff))

6 CongratulationsyouredoneSpeedbarisclosedbydefault-removethecommentsymbolsintheline(speedbar1)toenablethisfeatureoryoucanuseitthroughM-xspeedbar

EclipseEclipseisalsoagreatdevelopmenttoolIllshowyouhowtouseittowriteGoprograms

Figure11EclipsemainpanelforeditingGo

1 DownloadandinstallEclipse2 DownloadgoclipsehttpcodegooglecompgoclipsewikiInstallationInstructions3 Downloadgocode

gocodeinGithub

httpsgithubcomnsfgocode

YouneedtoinstallgitinWindowsusuallyweusemsysgit

Installgocodeinthecommandtool

goget-ugithubcomnsfgocode

Youcaninstallfromsourcecodeifyoulike

4 DownloadandinstallMinGW5 Configureplugins

Windows-gtPreferences-gtGo

(1)ConfigureGocompiler

Godevelopmenttools

25

Figure112GoSettinginEclipse

(2)Configuregocode(optional)setgocodepathtowherethegocodeexeis

Figure113gocodeSetting

(3)Configuregdb(optional)setgdbpathtowherethegdbexeis

Figure114gdbSetting

6 Checktheinstallation

CreateanewGoprojectandhellogofileasfollowing

Figure115Createanewprojectandfile

Testinstallationasfollows(youneedtotypecommandinconsoleinEclipse)

Figure116TestGoprograminEclipse

IntelliJIDEAPeoplewhohaveworkedwithJavashouldbefamiliarwiththisIDEItsupportsGosyntaxhighlightingandintelligentcodecompletionimplementedbyaplugin

1 DownloadIDEAthereisnodifferencebetweentheUltimateandCommunityeditions

2 InstalltheGopluginChooseFile-Setting-PluginsthenclickBrowserrepo

3 Searchgolangdoubleclickdownloadandinstallandwaitforthedownloadtocomplete

ClickApplythenrestart

4 NowyoucancreateaGoproject

InputthepositionofyourGosdkinthenextstep-basicallyitsyour$GOROOT

(SeeablogpostforsetupanduseIntelliJIDEAwithGostepbystep)

VisualStudioVSCodeThisisanawesometexteditorreleasedasopensourcecrossplatformmyMicrosoftwhichtakesthedevelopmentexperiencetoawholenewlevelhttpscodevisualstudiocomIthaseverythingamoderntexteditorisexpectedtohaveanddespitebeingbasedonthesamebackendthatatomioisbaseditisveryfast

ItworkswithWindowsMacLinuxIthasgopackagebuiltitprovidescodelinting

Godevelopmenttools

26

AtomAtomisanawesometexteditorreleasedasopensourcecrossplatformbuiltonElectronandbasedoneverythingweloveaboutourfavoriteeditorsWedesignedittobedeeplycustomizablebutstillapproachableusingthedefaultconfiguration

Downloadhttpsatomio

GoglandGoglandisthecodenameforanewcommercialIDEbyJetBrainsaimedatprovidinganergonomicenvironmentforGodevelopment

Theofficialversionisnotyetreleased

Downloadhttpswwwjetbrainscomgo

LinksDirectoryPrevioussectionGocommandsNextsectionSummary

Godevelopmenttools

27

15SummaryInthischapterwetalkedabouthowtoinstallGousingthreedifferentmethodsincludingfromsourcecodethestandardpackageandviathird-partytoolsThenweshowedyouhowtoconfiguretheGodevelopmentenvironmentmainlycoveringhowtosetupyour$GOPATHAfterthatweintroducedsomestepsforcompilinganddeployingGoprogramsWethencoveredGocommandsincludingthecompileinstallformatandtestcommandsFinallytherearemanypowerfultoolstodevelopGoprogramssuchasLiteIDESublimeTextVSCodeAtomGoglangVimEmacsEclipseIntelliJIDEAetcYoucanchooseanyoneyoulikeexploringtheworldofGo

LinksDirectoryPrevioussectionGodevelopmenttoolsNextchapterGobasicknowledge

Summary

28

2GobasicknowledgeGoisacompiledsystemprogramminglanguageanditbelongstotheC-familyHoweveritscompilationspeedismuchfasterthanotherC-familylanguagesIthasonly25keywordsevenlessthanthe26lettersoftheEnglishalphabetLetstakealookatthesekeywordsbeforewegetstarted

breakdefaultfuncinterfaceselect

casedefergomapstruct

chanelsegotopackageswitch

constfallthroughifrangetype

continueforimportreturnvar

InthischapterImgoingtoteachyousomebasicGoknowledgeYouwillfindouthowconcisetheGoprogramminglanguageisandthebeautifuldesignofthelanguageProgrammingcanbeveryfuninGoAfterwecompletethischapteryoullbefamiliarwiththeabovekeywords

LinksDirectoryPreviouschapterChapter1SummaryNextsectionHelloGo

Gobasicknowledge

29

WhatmakesGodifferentfromotherlanguagesTheGoprogramminglanguagewascreatedwithonegoalinmindtobeabletobuildscalableweb-applicationsforlargescaleaudiencesinalargeteamSothatisthereasontheymadethelanguageasstandardizedaspossiblehencethegofmttoolandthestrictusageguidelinestothelanguagewasforthesakeofnothavingtwofactionsinthedeveloperbaseinotherlanguagestherearereligiouswarsonwheretokeeptheopeningbrace

publicstaticvoidmain()

or

publicstaticvoidmain()

orforpythonshouldweuse4spacesor6spacesoratabortwotabsandotheruserpreferencesIfyouknowpythonthenyoumightbeawareofPEP8whichisasetofguidelinesabouthowtowriteelegantcode

WhilethismightseemtobeashallowproblemwhenthecodebasegrowsandmoreandmorepeopleworkonthesamecodebaseitisbecomesincreasinglydifficulttomaintainthecodesbeautyWeliveinaworldwhererobotscandriveacarsoweshouldntjustwritecodeweshouldwriteelegantcode

ForotherlanguagestherearemanyvariableswhenitcomestowritingcodeEverylanguageisgoodforitsusecasebutGoisalittlespecialbecauseitwasdesignedatacompanywhichistheverysynonymoftheInternet(anddistributedcomputing)TypicallyinordertooptimizeprogramsdeveloperschoosetowriteJavaoverPythonandC++overJavabutalmostallavailablelanguageswidelyinusewerewrittendecadesagowhen1GBstoragewasmuchpricierNowstorageandcomputingisrelativelycheapandcomputersaregettingmultiplescoresbuttheoldlanguagesarenotharnessingconcurrencyinawaythatgodoesItsnotbecausethoselanguagesarebadutilizingconcurrencywasntarelevantusecasewhiletheolderlanguagesevolved

TomitigatealltheproblemsthatGooglefacedwithcurrenttoolstheywroteasystemslanguagecalledGowhichyouareabouttolearnTherearemanyadvantagestousinggolangandtherearedisadvantagestooforeverycoinhasbothsidesOneofthesignificantimprovementsinincodeformattingGooglehasdesignedthelanguagetoavoiddebatesoncodeformattingGocodewrittenbyanyoneintheworld(assumingtheyknowandusegofmt)willlookexactlythesameThiswontseemtomatteruntilyouworkinateamAlsowhenthecompanyusesautomatedcoderevieworsomeotherfancytechniquetheformattedcodemaybreakinotherlanguageswhichdonthavestrictandstandardformattingrulesbutnotingo

Gowasdesignedwithconcurrencyinmindpleasenotethatparallelism=concurrencythereisanamazingpostbyRobPikeonthegolangblogyouwillfinditthereitiswortharead

AnotherveryimportantchangethatistheconceptofGOPATHGonearethedayswhenyouhadtocreateafoldercalledcodeandthencreateworkspacesforeclipseandwhatnotNowyouhavetokeeponefoldertreeforgocodewhichwillbeupdatedbythepackagemanagerautomaticallyItisalsorecommendedtocreatefolderswitheitheracustomdomainorthegithubdomainforexampleIcreatedataskmanagerusinggolangsoIcreatedasetoffolders~gosrcgithubcomthewhitetulipTasks

NoteInnixsystems~standsforhomedirectorywhichisthewindowsequivalentofCUsersusernameNowthe~goistheuniverseforthegocodeinyourmachineThisisasignificantimprovementoverotherlanguageswecanstorethecodeefficientlywithouthasslesWhileitmightseemstrangeatfirstthisapproachmakealotofsensethantheridiculouspackagenamesiepackagenamesgeneratedforotherlanguagesusingreversedomains

NoteAlongwithsrctherearetwofolderspkgwhichisforpackagesandbinwhichisforbinary

HelloGo

30

ThisGOPATHadvantageisntjustrestrictedtostoringcodeinparticularfolderWhenyouhavecreatedfivepackagesforyourprojectyoudonthavetoimportthemlikeimportdbInsteadyoucanuseimportgithubcomthewhitetulipTasksdbsothatwhenexecutinggogetonmyrepothegotoolwillfindthepackagefromgithubcompathifitwasntdownloadedinitiallyThisstandardizesalotofscrewedupthingsintheprogrammingdiscipline(lt--Toremoveandreplacewithactualexplanationofwhythisisbetter)

Whiletheremaybesomefoundedcomplaintsthatgocreatorshaveignoredalllanguageresearchdonesincethepast30yrsyoucannotcreateaproductoralanguagewhicheveryonewillfallinlovewithTherearealwayssomeortheotherusecasesorconstraintswhichthecreatorsshouldconsiderConsideringalltheadvantagesatleastforwebdevelopmentIdonotthinkanylanguagegetsclosetotheadvantageswhichgohasevenifyouignoreallthatIsaidaboveGoisacompiledlanguagewhichmeansinproductionyouwonthavetosetupaJVMoravirtualenvandwillinsteadhaveasinglestaticbinaryLikeanicingonacakeallthemodernlibrariesareinthestandardlibrarysuchasthehttpliballowingyoutocreatewebappsingolangwithoutusingathirdpartywebframework

21HelloGoBeforewestartbuildinganapplicationinGoweneedtolearnhowtowriteasimpleprogramYoucantexpecttobuildabuildingwithoutfirstknowinghowtobuilditsfoundationThereforewearegoingtolearnthebasicsyntaxtorunsomesimpleprogramsinthissection

ProgramAccordingtointernationalpracticebeforeyoulearnhowtoprograminsomelanguagesyouwillwanttoknowhowtowriteaprogramtoprintHelloworld

AreyoureadyLetsGo

packagemain

importfmt

funcmain()

fmtPrintf(Helloworldor你好世界orΚαλημέρακόσμεorこんにちは世界n)

Itprintsfollowinginformation

Helloworldor你好世界orΚαλημέρακόσμεorこんにちは世界

ExplanationOnethingthatyoushouldknowinthefirstisthatGoprogramsarecomposedbypackage

packageltpkgNamegt(Inthiscaseispackagemain)tellsusthissourcefilebelongstomainpackageandthekeywordmaintellsusthispackagewillbecompiledtoaprograminsteadofpackagefileswhoseextensionsarea

Everyexecutableprogramhasoneandonlyonemainpackageandyouneedanentryfunctioncalledmainwithoutanyargumentsorreturnvaluesinthemainpackage

InordertoprintHelloworldhellipwecalledafunctioncalledPrintfThisfunctioniscomingfromfmtpackagesoweimportthispackageinthethirdlineofsourcecodewhichisimportfmt

ThewaytothinkaboutpackagesinGoissimilartoPythonandtherearesomeadvantagesModularity(breakupyourprogramintomanymodules)andreusability(everymodulecanbereusedinmanyprograms)Wejusttalkedaboutconceptsregardingpackagesandwewillmakeourownpackageslater

HelloGo

31

OnthefifthlineweusethekeywordfunctodefinethemainfunctionThebodyofthefunctionisinsideofjustlikeCC++andJava

AsyoucanseetherearenoargumentsWewilllearnhowtowritefunctionswithargumentsinjustasecondandyoucanalsohavefunctionsthathavenoreturnvalueorhaveseveralreturnvalues

OnthesixthlinewecalledthefunctionPrintfwhichisfromthepackagefmtThiswascalledbythesyntaxltpkgNamegtltfuncNamegtwhichisverylikePython-style

Aswementionedinchapter1thepackagesnameandthenameofthefolderthatcontainsthatpackagecanbedifferentHeretheltpkgNamegtcomesfromthenameinpackageltpkgNamegtnotthefoldersname

Youmaynoticethattheexampleabovecontainsmanynon-ASCIIcharactersThepurposeofshowingthisistotellyouthatGosupportsUTF-8bydefaultYoucanuseanyUTF-8characterinyourprograms

EachgofileisinsomepackageandthatpackageshouldbeadistinctfolderintheGOPATHbutmainisaspecialpackagewhichdoesntrequireamainfolderThisisoneaspectwhichtheyleftoutforstandardizationButshouldyouchoosetomakeamainfolderthenyouhavetoensurethatyourunthebinaryproperlyAlsoonegocodecanthavemorethanonemaingofile

~gosrcgithubcomthewhitetulipTasksmain$gobuild~gosrcgithubcomthewhitetulipTasks$mainmain

thethinghereisthatwhenyourcodeisusingsomestaticfilesorsomethingelsethenyououghttorunthebinaryfromtherootoftheapplicationasweseeinthesecondlineaboveIamrunningthemainbinaryoutsidethemainpackagesometimesyoumightwonderwhyyourapplicationisntworkingthenthismightbeoneofthepossibleproblemspleasekeepthisinmind

Onethingyouwillnoticehereisthatgodoesntseetousesemicolonstoendastatementwellitdoesjustthereisaminorcatchtheprogrammerisntexpectedtoputsemicolonsthecompileraddssemicolonstothegocodewhenitcompileswhichisthereasonthatthis(thankfully)isasyntaxerror

funcmain()

becausethecompileraddsasemicolonattheendofmain()whichisasyntaxerrorandasstatedaboveithelpsavoidreligiouswarsiwishtheycombinevimandemacsandcreateauniversaleditorwhichllhelpsavesomemorewarsButfornowwelllearnGo

ConclusionGousespackage(likemodulesinPython)toorganizeprogramsThefunctionmainmain()(thisfunctionmustbeinthemainpackage)istheentrypointofanyprogramGostandardizeslanguageandmostoftheprogrammingmethodologysavingtimeofdeveloperswhichtheydhavewastedinreligiouswarsTherecanbeonlyonemainpackageandonlyonemainfunctioninsideagomainpackageGosupportsUTF-8charactersbecauseoneofthecreatorsofGoisacreatorofUTF-8soGohassupportedmultiplelanguagesfromthetimeitwasborn

LinksDirectoryPrevioussectionGobasicknowledgeNextsectionGofoundation

HelloGo

32

HelloGo

33

22GofoundationInthissectionwearegoingtoteachyouhowtodefineconstantsvariableswithelementarytypesandsomeskillsinGoprogramming

DefinevariablesTherearemanyformsofsyntaxthatcanbeusedtodefinevariablesinGo

ThekeywordvaristhebasicformtodefinevariablesnoticethatGoputsthevariabletypeafterthevariablename

defineavariablewithnameldquovariableNamerdquoandtypetype

varvariableNametype

Definemultiplevariables

definethreevariableswhichtypesaretype

varvname1vname2vname3type

Defineavariablewithinitialvalue

defineavariablewithnameldquovariableNamerdquotypetypeandvaluevalue

varvariableNametype=value

Definemultiplevariableswithinitialvalues

Definethreevariableswithtypetypeandinitializetheirvalues

vname1isv1vname2isv2vname3isv3

varvname1vname2vname3type=v1v2v3

DoyouthinkthatitstootedioustodefinevariablesusethewayaboveDontworrybecausetheGoteamhasalsofoundthistobeaproblemThereforeifyouwanttodefinevariableswithinitialvalueswecanjustomitthevariabletypesothecodewilllooklikethisinstead

Definethreevariableswithouttypetypeandinitializetheirvalues

vname1isv1vname2isv2vname3isv3

varvname1vname2vname3=v1v2v3

WellIknowthisisstillnotsimpleenoughforyouLetsseehowwefixit

Definethreevariableswithouttypetypeandwithoutkeywordvarandinitializetheirvalues

vname1isv1vname2isv2vname3isv3

vname1vname2vname3=v1v2v3

NowitlooksmuchbetterUse=toreplacevarandtypethisiscalledashortassignmentIthasonelimitationthisformcanonlybeusedinsideofafunctionsYouwillgetcompileerrorsifyoutrytouseitoutsideoffunctionbodiesThereforeweusuallyusevartodefineglobalvariables

Gofoundation

34

_(blank)isaspecialvariablenameAnyvaluethatisgiventoitwillbeignoredForexamplewegive35tobanddiscard34(ThisexamplejustshowyouhowitworksItlooksuselessherebecauseweoftenusethissymbolwhenwegetfunctionreturnvalues)

_b=3435

IfyoudontusevariablesthatyouvedefinedinyourprogramthecompilerwillgiveyoucompilationerrorsTrytocompilethefollowingcodeandseewhathappens

packagemain

funcmain()

variint

ConstantsSo-calledconstantsarethevaluesthataredeterminedduringcompiletimeandyoucannotchangethemduringruntimeInGoyoucanusenumberbooleanorstringastypesofconstants

Defineconstantsasfollows

constconstantName=value

youcanassigntypeofconstantsifitsnecessary

constPifloat32=31415926

Moreexamples

constPi=31415926

consti=10000

constMaxThread=10

constprefix=astaxie_

Elementarytypes

Boolean

InGoweusebooltodefineavariableasbooleantypethevaluecanonlybetrueorfalseandfalsewillbethedefaultvalue(Youcannotconvertvariablestypebetweennumberandboolean)

samplecode

varisActiveboolglobalvariable

varenableddisabled=truefalseomittypeofvariables

functest()

varavailableboollocalvariable

valid=falsebriefstatementofvariable

available=trueassignvaluetovariable

Numericaltypes

IntegertypesincludebothsignedandunsignedintegertypesGohasintanduintatthesametimetheyhavesamelengthbutspecificlengthdependsonyouroperatingsystemTheyuse32-bitin32-bitoperatingsystemsand64-bitin64-bitoperatingsystemsGoalsohastypesthathavespecificlengthincludingruneint8int16int32int64byteuint8uint16uint32uint64Notethatruneisaliasofint32andbyteisaliasofuint8

Gofoundation

35

Oneimportantthingyoushouldknowthatyoucannotassignvaluesbetweenthesetypesthisoperationwillcausecompileerrors

varaint8

varbint32

c=a+b

Althoughint32hasalongerlengththanint8andhasthesametypeasintyoucannotassignvaluesbetweenthem(cwillbeassertedastypeinthere)

Floattypeshavethefloat32andfloat64typesandnotypecalledfloatThelatteroneisthedefaulttypeifusingbriefstatement

ThatsallNoGosupportscomplexnumbersaswellcomplex128(witha64-bitrealand64-bitimaginarypart)isthedefaulttypeifyouneedasmallertypethereisonecalledcomplex64(witha32-bitrealand32-bitimaginarypart)ItsformisRE+IMiwhereREisrealpartandIMisimaginarypartthelastiistheimaginarynumberThereisaexampleofcomplexnumber

varccomplex64=5+5i

output(5+5i)

fmtPrintf(Valueisvc)

String

WejusttalkedabouthowGousestheUTF-8charactersetStringsarerepresentedbydoublequotesorbackticks `

samplecode

varfrenchHellostringbasicformtodefinestring

varemptyStringstring=defineastringwithemptystring

functest()

noyesmaybe=noyesmaybebriefstatement

japaneseHello=Ohaiou

frenchHello=Bonjourbasicformofassignvalues

ItsimpossibletochangestringvaluesbyindexYouwillgeterrorswhenyoucompilethefollowingcode

varsstring=hello

s[0]=c

WhatifIreallywanttochangejustonecharacterinastringTrythefollowingcode

s=hello

c=[]byte(s)convertstringto[]bytetype

c[0]=c

s2=string(c)convertbacktostringtype

fmtPrintf(sns2)

Youusethe+operatortocombinetwostrings

s=hello

m=world

a=s+m

fmtPrintf(sna)

andalso

Gofoundation

36

s=hello

s=c+s[1]youcannotchangestringvaluesbyindexbutyoucangetvaluesinstead

fmtPrintf(sns)

WhatifIwanttohaveamultiple-linestring

m=`hello

world`

willnotescapeanycharactersinastring

ErrortypesGohasoneerrortypeforpurposeofdealingwitherrormessagesThereisalsoapackagecallederrorstohandleerrors

err=errorsNew(emitmachodwarfelfheadercorrupted)

iferr=nil

fmtPrint(err)

Underlyingdatastructure

ThefollowingpicturecomesfromanarticleaboutGodatastructureinRussCoxsBlogAsyoucanseeGoutilizesblocksofmemorytostoredata

Figure21Gounderlyingdatastructure

Someskills

Definebygroup

Ifyouwanttodefinemultipleconstantsvariablesorimportpackagesyoucanusethegroupform

Basicform

importfmt

importos

consti=100

constpi=31415

constprefix=Go_

variint

varpifloat32

varprefixstring

Groupform

Gofoundation

37

import(

fmt

os

)

const(

i=100

pi=31415

prefix=Go_

)

var(

iint

pifloat32

prefixstring

)

Unlessyouassignthevalueofconstantisiotathefirstvalueofconstantinthegroupconst()willbe0IffollowingconstantsdontassignvaluesexplicitlytheirvalueswillbethesameasthelastoneIfthevalueoflastconstantisiotathevaluesoffollowingconstantswhicharenotassignedareiotaalso

iotaenumerate

Gohasonekeywordcallediotathiskeywordistomakeenumitbeginswith0increasedby1

const(

x=iotax==0

y=iotay==1

z=iotaz==2

wIfthereisnoexpressionaftertheconstantsnameitusesthelastexpression

soitssayingw=iotaimplicitlyThereforew==3andyandzbothcanomit=iotaaswell

)

constv=iotaonceiotameetskeyword`const`itresetsto`0`sov=0

const(

efg=iotaiotaiotae=0f=0g=0valuesofiotaaresameinoneline

)

Somerules

ThereasonthatGoisconcisebecauseithassomedefaultbehaviors

AnyvariablethatbeginswithacapitallettermeansitwillbeexportedprivateotherwiseThesameruleappliesforfunctionsandconstantsnopublicorprivatekeywordexistsinGo

arrayslicemap

array

arrayisanarrayobviouslywedefineoneasfollows

vararr[n]type

in[n]typenisthelengthofthearraytypeisthetypeofitselementsLikeotherlanguagesweuse[]togetorsetelementvalueswithinarrays

Gofoundation

38

vararr[10]intanarrayoftype[10]int

arr[0]=42arrayis0-based

arr[1]=13assignvaluetoelement

fmtPrintf(Thefirstelementisdnarr[0])

getelementvalueitreturns42

fmtPrintf(Thelastelementisdnarr[9])

itreturnsdefaultvalueof10thelementinthisarraywhichis0inthiscase

Becauselengthisapartofthearraytype[3]intand[4]intaredifferenttypessowecannotchangethelengthofarraysWhenyouusearraysasargumentsfunctionsgettheircopiesinsteadofreferencesIfyouwanttousereferencesyoumaywanttousesliceWelltalkaboutlater

Itspossibletouse=whenyoudefinearrays

a=[3]int123defineanintarraywith3elements

b=[10]int123

defineaintarraywith10elementsofwhichthefirstthreeareassigned

Therestofthemusethedefaultvalue0

c=[]int456use`hellip`toreplacethelengthparameterandGowillcalculateitforyou

YoumaywanttousearraysasarrayselementsLetsseehowtodothis

defineatwo-dimensionalarraywith2elementsandeachelementhas4elements

doubleArray=[2][4]int[4]int1234[4]int5678

Thedeclarationcanbewrittenmoreconciselyasfollows

easyArray=[2][4]int12345678

Arrayunderlyingdatastructure

Figure22Multidimensionalarraymappingrelationship

sliceInmanysituationsthearraytypeisnotagoodchoice-forinstancewhenwedontknowhowlongthearraywillbewhenwedefineitThusweneedadynamicarrayThisiscalledsliceinGo

sliceisnotreallyadynamicarrayItsareferencetypeslicepointstoanunderlyingarraywhosedeclarationissimilartoarraybutdoesntneedlength

justlikedefininganarraybutthistimeweexcludethelength

varfslice[]int

Thenwedefineasliceandinitializeitsdata

slice=[]byteabcd

slicecanredefineexistingslicesorarrayssliceusesarray[ij]toslicewhereiisthestartindexandjisendindexbutnoticethatarray[j]willnotbeslicedsincethelengthofthesliceisj-i

Gofoundation

39

defineanarraywith10elementswhosetypesarebytes

varar=[10]byteabcdefghij

definetwosliceswithtype[]byte

varab[]byte

apointstoelementsfrom3rdto5thinarrayar

a=ar[25]

nowahaselementsar[2]ar[3]andar[4]

bisanothersliceofarrayar

b=ar[35]

nowbhaselementsar[3]andar[4]

NoticethedifferencesbetweensliceandarraywhenyoudefinethemWeuse[hellip]toletGocalculatelengthbutuse[]todefinesliceonly

Theirunderlyingdatastructure

Figure23Correspondencebetweensliceandarray

slicehassomeconvenientoperations

sliceis0-basedar[n]equalstoar[0n]Thesecondindexwillbethelengthofsliceifomittedar[n]equalstoar[nlen(ar)]Youcanusear[]toslicewholearrayreasonsareexplainedinfirsttwostatements

Moreexamplespertainingtoslice

defineanarray

vararray=[10]byteabcdefghij

definetwoslices

varaSlicebSlice[]byte

someconvenientoperations

aSlice=array[3]equalstoaSlice=array[03]aSlicehaselementsabc

aSlice=array[5]equalstoaSlice=array[510]aSlicehaselementsfghij

aSlice=array[]equalstoaSlice=array[010]aSlicehasallelements

slicefromslice

aSlice=array[37]aSlicehaselementsdefglen=4cap=7

bSlice=aSlice[13]bSlicecontainsaSlice[1]aSlice[2]soithaselementsef

bSlice=aSlice[3]bSlicecontainsaSlice[0]aSlice[1]aSlice[2]soithasdef

bSlice=aSlice[05]slicecouldbeexpandedinrangeofcapnowbSlicecontainsdefgh

bSlice=aSlice[]bSlicehassameelementsasaSlicedoeswhicharedefg

sliceisareferencetypesoanychangeswillaffectothervariablespointingtothesamesliceorarrayForinstanceinthecaseofaSliceandbSliceaboveifyouchangethevalueofanelementinaSlicebSlicewillbechangedaswell

sliceislikeastructbydefinitionanditcontains3parts

ApointerthatpointstowhereslicestartsThelengthofsliceCapacitythelengthfromstartindextoendindexofslice

Array_a=[10]byteabcdefghij

Slice_a=Array_a[25]

Theunderlyingdatastructureofthecodeaboveasfollows

Gofoundation

40

Figure24Arrayinformationofslice

Therearesomebuilt-infunctionsforslice

lengetsthelengthofslicecapgetsthemaximumlengthofsliceappendappendsoneormoreelementstosliceandreturnsslicecopycopieselementsfromoneslicetotheotherandreturnsthenumberofelementsthatwerecopied

AttentionappendwillchangethearraythatslicepointstoandaffectotherslicesthatpointtothesamearrayAlsoifthereisnotenoughlengthfortheslice((cap-len)==0)appendreturnsanewarrayforthissliceWhenthishappensotherslicespointingtotheoldarraywillnotbeaffected

map

mapbehaveslikeadictionaryinPythonUsetheformmap[keyType]valueTypetodefineit

LetsseesomecodeThesetandgetvaluesinmaparesimilartoslicehowevertheindexinslicecanonlybeoftypeintwhilemapcanusemuchmorethanthatforexampleintstringorwhateveryouwantAlsotheyareallabletouse==and=tocomparevalues

usestringasthekeytypeintasthevaluetypeand`make`initializeit

varnumbersmap[string]int

anotherwaytodefinemap

numbers=make(map[string]int)

numbers[one]=1assignvaluebykey

numbers[ten]=10

numbers[three]=3

fmtPrintln(Thethirdnumberisnumbers[three])getvalues

ItprintsThethirdnumberis3

Somenoteswhenyouusemap

mapisdisorderlyEverytimeyouprintmapyouwillgetdifferentresultsItsimpossibletogetvaluesbyindex-youhavetousekeymapdoesnthaveafixedlengthItsareferencetypejustlikeslicelenworksformapalsoItreturnshowmanykeysthatmaphasItsquiteeasytochangethevaluethroughmapSimplyusenumbers[one]=11tochangethevalueofkeyoneto11

Youcanuseformkeyvaltoinitializemapsvaluesandmaphasbuilt-inmethodstocheckifthekeyexists

Usedeletetodeleteanelementinmap

Initializeamap

rating=map[string]float32C5Go45Python45C++2

maphastworeturnvaluesForthesecondreturnvalueifthekeydoesnt

existokreturnsfalseItreturnstrueotherwise

csharpRatingok=rating[C]

ifok

fmtPrintln(CisinthemapanditsratingiscsharpRating)

else

fmtPrintln(WehavenoratingassociatedwithCinthemap)

delete(ratingC)deleteelementwithkeyc

AsIsaidabovemapisareferencetypeIftwomapspointtosameunderlyingdataanychangewillaffectbothofthem

Gofoundation

41

m=make(map[string]string)

m[Hello]=Bonjour

m1=m

m1[Hello]=Salutnowthevalueofm[hello]isSalut

makenewmakedoesmemoryallocationforbuilt-inmodelssuchasmapsliceandchannelwhilenewisfortypesmemoryallocation

new(T)allocateszero-valuetotypeTsmemoryreturnsitsmemoryaddresswhichisthevalueoftypeTByGosdefinitionitreturnsapointerwhichpointstotypeTszero-value

newreturnspointers

Thebuilt-infunctionmake(Targs)hasdifferentpurposesthannew(T)makecanbeusedforslicemapandchannelandreturnsatypeTwithaninitialvalueThereasonfordoingthisisbecausetheunderlyingdataofthesethreetypesmustbeinitializedbeforetheypointtothemForexampleaslicecontainsapointerthatpointstotheunderlyingarraylengthandcapacityBeforethesedataareinitializedsliceisnilsoforslicemapandchannelmakeinitializestheirunderlyingdataandassignssomesuitablevalues

makereturnsnon-zerovalues

Thefollowingpictureshowshownewandmakearedifferent

Figure25Underlyingmemoryallocationofmakeandnew

Zero-valuedoesnotmeanemptyvalueItsthevaluethatvariablesdefaulttoinmostcasesHereisalistofsomezero-values

int0

int80

int320

int640

uint0x0

rune0theactualtypeofruneisint32

byte0x0theactualtypeofbyteisuint8

float320lengthis4byte

float640lengthis8byte

boolfalse

string

LinksDirectoryPrevioussectionHelloGoNextsectionControlstatementsandfunctions

Gofoundation

42

23ControlstatementsandfunctionsInthissectionwearegoingtotalkaboutcontrolstatementsandfunctionoperationsinGo

ControlstatementThegreatestinventioninprogrammingisflowcontrolBecauseofthemyouareabletousesimplecontrolstatementsthatcanbeusedtorepresentcomplexlogicTherearethreecategoriesofflowcontrolconditionalcyclecontrolandunconditionaljump

if

ifwillmostlikelybethemostcommonkeywordinyourprogramsIfitmeetstheconditionsthenitdoessomethinganditdoessomethingelseifnot

ifdoesntneedparenthesesinGo

ifxgt10

fmtPrintln(xisgreaterthan10)

else

fmtPrintln(xislessthanorequalto10)

ThemostusefulthingconcerningifinGoisthatitcanhaveoneinitializationstatementbeforetheconditionalstatementThescopeofthevariablesdefinedinthisinitializationstatementareonlyavailableinsidetheblockofthedefiningif

initializexthencheckifxgreaterthan

ifx=computedValue()xgt10

fmtPrintln(xisgreaterthan10)

else

fmtPrintln(xislessthan10)

thefollowingcodewillnotcompile

fmtPrintln(x)

Useif-elseformultipleconditions

ifinteger==3

fmtPrintln(Theintegerisequalto3)

elseifintegerlt3

fmtPrintln(Theintegerislessthan3)

else

fmtPrintln(Theintegerisgreaterthan3)

gotoGohasagotokeywordbutbecarefulwhenyouuseitgotoreroutesthecontrolflowtoapreviouslydefinedlabelwithinthebodyofsamecodeblock

Controlstatementsandfunctions

43

funcmyFunc()

i=0

Herelabelendswith

fmtPrintln(i)

i++

gotoHerejumptolabelHere

Thelabelnameiscasesensitive

for

foristhemostpowerfulcontrollogicinGoItcanreaddatainloopsanditerativeoperationsjustlikewhile

forexpression1expression2expression3

expression1expression2andexpression3areallexpressionswhereexpression1andexpression3arevariabledefinitionsorreturnvaluesfromfunctionsandexpression2isaconditionalstatementexpression1willbeexecutedoncebeforeloopingandexpression3willbeexecutedaftereachloop

Examplesaremoreusefulthanwords

packagemain

importfmt

funcmain()

sum=0

forindex=0indexlt10index++

sum+=index

fmtPrintln(sumisequaltosum)

Printsumisequalto45

SometimesweneedmultipleassignmentsbutGodoesnthavetheoperatorsoweuseparallelassignmentlikeij=i+1j-1

Wecanomitexpression1andexpression3iftheyarenotnecessary

sum=1

forsumlt1000

sum+=sum

OmitaswellFeelfamiliarYesitsidenticaltowhile

sum=1

forsumlt1000

sum+=sum

TherearetwoimportantoperationsinloopswhicharebreakandcontinuebreakjumpsoutoftheloopandcontinueskipsthecurrentloopandstartsthenextoneIfyouhavenestedloopsusebreakalongwithlabels

Controlstatementsandfunctions

44

forindex=10indexgt0index--

ifindex==5

breakorcontinue

fmtPrintln(index)

breakprints109876

continueprints1098764321

forcanreaddatafromarrayslicemapandstringwhenitisusedtogetherwithrange

forkv=rangemap

fmtPrintln(mapskeyk)

fmtPrintln(mapsvalv)

BecauseGosupportsmulti-valuereturnsandgivescompileerrorswhenyoudontusevaluesthatweredefinedyoumaywanttouse_todiscardcertainreturnvalues

for_v=rangemap

fmtPrintln(mapsvalv)

Withgoyoucanaswellcreateaninfiniteloopwhichisequivalenttowhiletrueinotherlanguges

for

yourlogic

switchSometimesyoumayfindthatyouareusingtoomanyif-elsestatementstoimplementsomelogicwhichmaymakeitdifficulttoreadandmaintaininthefutureThisistheperfecttimetousetheswitchstatementtosolvethisproblem

switchsExpr

caseexpr1

someinstructions

caseexpr2

someotherinstructions

caseexpr3

someotherinstructions

default

othercode

ThetypeofsExprexpr1expr2andexpr3mustbethesameswitchisveryflexibleConditionsdonthavetobeconstantsanditexecutesfromtoptobottomuntilitmatchesconditionsIfthereisnostatementafterthekeywordswitchthenitmatchestrue

i=10

switchi

case1

fmtPrintln(iisequalto1)

case234

fmtPrintln(iisequalto23or4)

case10

fmtPrintln(iisequalto10)

default

fmtPrintln(AllIknowisthatiisaninteger)

Controlstatementsandfunctions

45

InthefifthlineweputmanyvaluesinonecaseandwedontneedtoaddthebreakkeywordattheendofcasesbodyItwilljumpoutoftheswitchbodyonceitmatchedanycaseIfyouwanttocontinuetomatchingmorecasesyouneedtousethefallthroughstatement

integer=6

switchinteger

case4

fmtPrintln(integerlt=4)

fallthrough

case5

fmtPrintln(integerlt=5)

fallthrough

case6

fmtPrintln(integerlt=6)

fallthrough

case7

fmtPrintln(integerlt=7)

fallthrough

case8

fmtPrintln(integerlt=8)

fallthrough

default

fmtPrintln(defaultcase)

Thisprogramprintsthefollowinginformation

integerlt=6

integerlt=7

integerlt=8

defaultcase

FunctionsUsethefunckeywordtodefineafunction

funcfuncName(input1type1input2type2)(output1type1output2type2)

functionbody

multi-valuereturn

returnvalue1value2

Wecanextrapolatethefollowinginformationfromtheexampleabove

UsekeywordfunctodefineafunctionfuncNameFunctionshavezerooneormorethanoneargumentsTheargumenttypecomesaftertheargumentnameandargumentsareseparatedbyFunctionscanreturnmultiplevaluesTherearetworeturnvaluesnamedoutput1andoutput2youcanomittheirnamesandusetheirtypeonlyIfthereisonlyonereturnvalueandyouomittedthenameyoudontneedbracketsforthereturnvaluesIfthefunctiondoesnthavereturnvaluesyoucanomitthereturnparametersaltogetherIfthefunctionhasreturnvaluesyouhavetousethereturnstatementsomewhereinthebodyofthefunction

Letsseeonepracticalexample(calculatemaximumvalue)

Controlstatementsandfunctions

46

packagemain

importfmt

returngreatervaluebetweenaandb

funcmax(abint)int

ifagtb

returna

returnb

funcmain()

x=3

y=4

z=5

max_xy=max(xy)callfunctionmax(xy)

max_xz=max(xz)callfunctionmax(xz)

fmtPrintf(max(dd)=dnxymax_xy)

fmtPrintf(max(dd)=dnxzmax_xz)

fmtPrintf(max(dd)=dnyzmax(yz))callfunctionhere

IntheaboveexampletherearetwoargumentsinthefunctionmaxtheirtypesarebothintsothefirsttypecanbeomittedForinstanceabintinsteadofaintbintThesamerulesapplyforadditionalargumentsNoticeherethatmaxonlyhasonereturnvaluesoweonlyneedtowritethetypeofitsreturnvalue-thisistheshortformofwritingit

Multi-valuereturn

OnethingthatGoisbetteratthanCisthatitsupportsmulti-valuereturns

Wellusethefollowingexamplehere

packagemain

importfmt

returnresultsofA+BandAB

funcSumAndProduct(ABint)(intint)

returnA+BAB

funcmain()

x=3

y=4

xPLUSyxTIMESy=SumAndProduct(xy)

fmtPrintf(d+d=dnxyxPLUSy)

fmtPrintf(dd=dnxyxTIMESy)

Theaboveexamplereturnstwovalueswithoutnames-youhavetheoptionofnamingthemalsoIfwenamedthereturnvalueswewouldjustneedtousereturntoreturnthevaluessincetheyareinitializedinthefunctionautomaticallyNoticethatifyourfunctionsaregoingtobeusedoutsideofthepackagewhichmeansyourfunctionnamesstartwithacapitalletteryoudbetterwritecompletestatementsforreturnitmakesyourcodemorereadable

funcSumAndProduct(ABint)(addintmultipliedint)

add=A+B

multiplied=AB

return

Controlstatementsandfunctions

47

Variadicfunctions

GosupportsfunctionswithavariablenumberofargumentsThesefunctionsarecalledvariadicwhichmeansthefunctionallowsanuncertainnumbersofarguments

funcmyfunc(argint)

arghellipinttellsGothatthisisafunctionthathasvariableargumentsNoticethattheseargumentsaretypeintInthebodyoffunctiontheargbecomesasliceofint

for_n=rangearg

fmtPrintf(Andthenumberisdnn)

Passbyvalueandpointers

Whenwepassanargumenttothefunctionthatwascalledthatfunctionactuallygetsthecopyofourvariablessoanychangewillnotaffecttotheoriginalvariable

Letsseeoneexampleinordertoprovewhatimsaying

packagemain

importfmt

simplefunctiontoadd1toa

funcadd1(aint)int

a=a+1wechangevalueofa

returnareturnnewvalueofa

funcmain()

x=3

fmtPrintln(x=x)shouldprintx=3

x1=add1(x)calladd1(x)

fmtPrintln(x+1=x1)shouldprintx+1=4

fmtPrintln(x=x)shouldprintx=3

CanyouseethatEventhoughwecalledadd1withxtheoriginvalueofxdoesntchange

Thereasonisverysimplewhenwecalledadd1wegaveacopyofxtoitnotthexitself

NowyoumayaskhowIcanpasstherealxtothefunction

WeneedusepointershereWeknowvariablesarestoredinmemoryandtheyhavesomememoryaddressesSoifwewanttochangethevalueofavariablewemustchangeitsmemoryaddressThereforethefunctionadd1hastoknowthememoryaddressofxinordertochangeitsvalueHerewepassampxtothefunctionandchangetheargumentstypetothepointertypeintBeawarethatwepassacopyofthepointernotcopyofvalue

Controlstatementsandfunctions

48

packagemain

importfmt

simplefunctiontoadd1toa

funcadd1(aint)int

a=a+1wechangedvalueofa

returnareturnnewvalueofa

funcmain()

x=3

fmtPrintln(x=x)shouldprintx=3

x1=add1(ampx)calladd1(ampx)passmemoryaddressofx

fmtPrintln(x+1=x1)shouldprintx+1=4

fmtPrintln(x=x)shouldprintx=4

NowwecanchangethevalueofxinthefunctionsWhydoweusepointersWhataretheadvantages

AllowsustousemorefunctionstooperateononevariableLowcostbypassingmemoryaddresses(8bytes)copyisnotanefficientwaybothintermsoftimeandspacetopassvariableschannelsliceandmaparereferencetypessotheyusepointerswhenpassingtofunctionsbydefault(AttentionIfyouneedtochangethelengthofsliceyouhavetopasspointersexplicitly)

deferGohasawelldesignedkeywordcalleddeferYoucanhavemanydeferstatementsinonefunctiontheywillexecuteinreverseorderwhentheprogramexecutestotheendoffunctionsInthecasewheretheprogramopenssomeresourcefilesthesefileswouldhavetobeclosedbeforethefunctioncanreturnwitherrorsLetsseesomeexamples

funcReadWrite()bool

fileOpen(file)

Dosomework

iffailureX

fileClose()

returnfalse

iffailureY

fileClose()

returnfalse

fileClose()

returntrue

WesawsomecodebeingrepeatedseveraltimesdefersolvesthisproblemverywellItdoesntonlyhelpyoutowritecleancodebutalsomakesyourcodemorereadable

Controlstatementsandfunctions

49

funcReadWrite()bool

fileOpen(file)

deferfileClose()

iffailureX

returnfalse

iffailureY

returnfalse

returntrue

IftherearemorethanonedeferstheywillexecutebyreverseorderThefollowingexamplewillprint43210

fori=0ilt5i++

deferfmtPrintf(di)

Functionsasvaluesandtypes

FunctionsarealsovariablesinGowecanusetypetodefinethemFunctionsthathavethesamesignaturecanbeseenasthesametype

typetypeNamefunc(input1inputType1input2inputType2[])(result1resultType1[])

WhatstheadvantageofthisfeatureTheansweristhatitallowsustopassfunctionsasvalues

packagemain

importfmt

typetestIntfunc(int)booldefineafunctiontypeofvariable

funcisOdd(integerint)bool

returninteger2=0

funcisEven(integerint)bool

returninteger2==0

passthefunction`f`asanargumenttoanotherfunction

funcfilter(slice[]intftestInt)[]int

varresult[]int

for_value=rangeslice

iff(value)

result=append(resultvalue)

returnresult

varslice=[]int123457

funcmain()

odd=filter(sliceisOdd)

even=filter(sliceisEven)

fmtPrintln(slice=slice)

fmtPrintln(Oddelementsofsliceareodd)

fmtPrintln(Evenelementsofsliceareeven)

Controlstatementsandfunctions

50

ItsveryusefulwhenweuseinterfacesAsyoucanseetestIntisavariablethathasafunctionastypeandthereturnedvaluesandargumentsoffilterarethesameasthoseoftestIntThereforewecanhavecomplexlogicinourprogramswhilemaintainingflexibilityinourcode

PanicandRecover

Godoesnthavetry-catchstructurelikeJavadoesInsteadofthrowingexceptionsGousespanicandrecovertodealwitherrorsHoweveryoushouldntusepanicverymuchalthoughitspowerful

Panicisabuilt-infunctiontobreakthenormalflowofprogramsandgetintopanicstatusWhenafunctionFcallspanicFwillnotcontinueexecutingbutitsdeferfunctionswillcontinuetoexecuteThenFgoesbacktothebreakpointwhichcausedthepanicstatusTheprogramwillnotterminateuntilallofthesefunctionsreturnwithpanictothefirstlevelofthatgoroutinepaniccanbeproducedbycallingpanicintheprogramandsomeerrorsalsocausepaniclikearrayaccessoutofboundserrors

Recoverisabuilt-infunctiontorecovergoroutinesfrompanicstatusCallingrecoverindeferfunctionsisusefulbecausenormalfunctionswillnotbeexecutedwhentheprogramisinthepanicstatusItcatchespanicvaluesiftheprogramisinthepanicstatusanditgetsniliftheprogramisnotinpanicstatus

Thefollowingexampleshowshowtousepanic

varuser=osGetenv(USER)

funcinit()

ifuser==

panic(novaluefor$USER)

Thefollowingexampleshowshowtocheckpanic

functhrowsPanic(ffunc())(bbool)

deferfunc()

ifx=recover()x=nil

b=true

()

f()iffcausespanicitwillrecover

return

mainfunctionandinitfunction

GohastworetentionswhicharecalledmainandinitwhereinitcanbeusedinallpackagesandmaincanonlybeusedinthemainpackageThesetwofunctionsarenotabletohaveargumentsorreturnvaluesEventhoughwecanwritemanyinitfunctionsinonepackageIstronglyrecommendwritingonlyoneinitfunctionforeachpackage

Goprogramswillcallinit()andmain()automaticallysoyoudontneedtocallthembyyourselfForeverypackagetheinitfunctionisoptionalbutpackagemainhasoneandonlyonemainfunction

ProgramsinitializeandbeginexecutionfromthemainpackageIfthemainpackageimportsotherpackagestheywillbeimportedinthecompiletimeIfonepackageisimportedmanytimesitwillbeonlycompiledonceAfterimportingpackagesprogramswillinitializetheconstantsandvariableswithintheimportedpackagesthenexecutetheinitfunctionifitexistsandsoonAfteralltheotherpackagesareinitializedprogramswillinitializeconstantsandvariablesinthemainpackagethenexecutetheinitfunctioninsidethepackageifitexistsThefollowingfigureshowstheprocess

Figure26FlowofprogramsinitializationinGo

Controlstatementsandfunctions

51

import

WeuseimportveryofteninGoprogramsasfollows

import(

fmt

)

Thenweusefunctionsinthatpackageasfollows

fmtPrintln(helloworld)

fmtisfromGostandardlibraryitislocatedwithin$GOROOTpkgGosupportsthird-partypackagesintwoways

1 RelativepathimportmodelloadpackageinthesamedirectoryIdontrecommendthisway2 Absolutepathimportshorturlmodelloadpackageinpath$GOPATHpkgshorturlmodel

Therearesomespecialoperatorswhenweimportpackagesandbeginnersarealwaysconfusedbytheseoperators

1 DotoperatorSometimeweseepeopleusefollowingwaytoimportpackages

import(

fmt

)

ThedotoperatormeansyoucanomitthepackagenamewhenyoucallfunctionsinsideofthatpackageNowfmtPrintf(Helloworld)becomestoPrintf(Helloworld)

2 AliasoperationItchangesthenameofthepackagethatweimportedwhenwecallfunctionsthatbelongtothatpackage

import(

ffmt

)

NowfmtPrintf(Helloworld)becomestofPrintf(Helloworld)3 _operatorThisistheoperatorthatisdifficulttounderstandwithoutsomeoneexplainingittoyou

import(

databasesql

_githubcomziutekmymysqlgodrv

)

The_operatoractuallymeanswejustwanttoimportthatpackageandexecuteitsinitfunctionandwearenotsureifwewanttousethefunctionsbelongingtothatpackage

LinksDirectoryPrevioussectionGofoundationNextsectionstruct

Controlstatementsandfunctions

52

24struct

structWecandefinenewtypesofcontainersofotherpropertiesorfieldsinGojustlikeinotherprogramminglanguagesForexamplewecancreateatypecalledpersontorepresentapersonwithfieldsnameandageWecallthiskindoftypeastruct

typepersonstruct

namestring

ageint

Lookhoweasyitistodefineastruct

Therearetwofields

nameisastringusedtostoreapersonsnameageisaintusedtostoreapersonsage

Letsseehowtouseit

typepersonstruct

namestring

ageint

varPpersonpispersontype

Pname=AstaxieassignAstaxietothefieldnameofp

Page=25assign25tofieldageofp

fmtPrintf(ThepersonsnameissnPname)accessfieldnameofp

Therearethreemorewaystoinitializeastruct

Assigninitialvaluesbyorder

P=personTom25

Usetheformatfieldvaluetoinitializethestructwithoutorder

P=personage24nameBob

Defineananonymousstructtheninitializeit

P=structnamestringageintAmy18

Letsseeacompleteexample

struct

53

packagemain

importfmt

defineanewtype

typepersonstruct

namestring

ageint

structispassedbyvalue

comparetheageoftwopeoplethenreturntheolderpersonanddifferencesofage

funcOlder(p1p2person)(personint)

ifp1agegtp2age

returnp1p1age-p2age

returnp2p2age-p1age

funcmain()

vartomperson

tomnametomage=Tom18

bob=personage25nameBob

paul=personPaul43

tb_Oldertb_diff=Older(tombob)

tp_Oldertp_diff=Older(tompaul)

bp_Olderbp_diff=Older(bobpaul)

fmtPrintf(Ofsandssisolderbydyearsntomnamebobnametb_Oldernametb_diff)

fmtPrintf(Ofsandssisolderbydyearsntomnamepaulnametp_Oldernametp_diff)

fmtPrintf(Ofsandssisolderbydyearsnbobnamepaulnamebp_Oldernamebp_diff)

embeddedfieldsinstructIvejustintroducedtoyouhowtodefineastructwithfieldnamesandtypeInfactGosupportsfieldswithoutnamesbutwithtypesWecalltheseembeddedfields

Whentheembeddedfieldisastructallthefieldsinthatstructwillimplicitlybethefieldsinthestructinwhichithasbeenembedded

Letsseeoneexample

struct

54

packagemain

importfmt

typeHumanstruct

namestring

ageint

weightint

typeStudentstruct

HumanembeddedfielditmeansStudentstructincludesallfieldsthatHumanhas

specialtystring

funcmain()

instantiateandinitializeastudent

mark=StudentHumanMark25120ComputerScience

accessfields

fmtPrintln(Hisnameismarkname)

fmtPrintln(Hisageismarkage)

fmtPrintln(Hisweightismarkweight)

fmtPrintln(Hisspecialtyismarkspecialty)

modifymarksspecialty

markspecialty=AI

fmtPrintln(Markchangedhisspecialty)

fmtPrintln(Hisspecialtyismarkspecialty)

fmtPrintln(MarkbecomeoldHeisnotanathleteanymore)

markage=46

markweight+=60

fmtPrintln(Hisageismarkage)

fmtPrintln(Hisweightismarkweight)

Figure27EmbeddinginStudentandHuman

WeseethatwecanaccesstheageandnamefieldsinStudentjustlikewecaninHumanThisishowembeddedfieldsworkItsverycoolisntitHoldontheressomethingcoolerYoucanevenuseStudenttoaccessHumaninthisembeddedfield

markHuman=HumanMarcus55220

markHumanage-=1

AllthetypesinGocanbeusedasembeddedfields

struct

55

packagemain

importfmt

typeSkills[]string

typeHumanstruct

namestring

ageint

weightint

typeStudentstruct

Humanstructasembeddedfield

Skillsstringsliceasembeddedfield

intbuilt-intypeasembeddedfield

specialtystring

funcmain()

initializeStudentJane

jane=StudentHumanHumanJane35100specialtyBiology

accessfields

fmtPrintln(Hernameisjanename)

fmtPrintln(Herageisjaneage)

fmtPrintln(Herweightisjaneweight)

fmtPrintln(Herspecialtyisjanespecialty)

modifyvalueofskillfield

janeSkills=[]stringanatomy

fmtPrintln(HerskillsarejaneSkills)

fmtPrintln(Sheacquiredtwonewones)

janeSkills=append(janeSkillsphysicsgolang)

fmtPrintln(HerskillsnowarejaneSkills)

modifyembeddedfield

janeint=3

fmtPrintln(Herpreferrednumberisjaneint)

Intheaboveexamplewecanseethatalltypescanbeembeddedfieldsandwecanusefunctionstooperateonthem

ThereisonemoreproblemhoweverIfHumanhasafieldcalledphoneandStudenthasafieldwithsamenamewhatshouldwedo

GouseaverysimplewaytosolveitTheouterfieldsgetupperaccesslevelswhichmeanswhenyouaccessstudentphonewewillgetthefieldcalledphoneinstudentnottheoneintheHumanstructThisfeaturecanbesimplyseenasfieldoverloading

struct

56

packagemain

importfmt

typeHumanstruct

namestring

ageint

phonestringHumanhasphonefield

typeEmployeestruct

Human

specialtystring

phonestringphoneinemployee

funcmain()

Bob=EmployeeHumanBob34777-444-XXXXDesigner333-222

fmtPrintln(BobsworkphoneisBobphone)

fmtPrintln(BobspersonalphoneisBobHumanphone)

LinksDirectoryPrevioussectionControlstatementsandfunctionsNextsectionObject-oriented

struct

57

Object-orientedWetalkedaboutfunctionsandstructsinthelasttwosectionsbutdidyoueverconsiderusingfunctionsasfieldsofastructInthissectionIwillintroduceyoutoanotherformoffunctionthathasareceiverwhichiscalledamethod

methodSupposeyoudefinearectanglestructandyouwanttocalculateitsareaWedtypicallyusethefollowingcodetoachievethisgoal

packagemain

importfmt

typeRectanglestruct

widthheightfloat64

funcarea(rRectangle)float64

returnrwidthrheight

funcmain()

r1=Rectangle122

r2=Rectangle94

fmtPrintln(Areaofr1isarea(r1))

fmtPrintln(Areaofr2isarea(r2))

TheaboveexamplecancalculatearectanglesareaWeusethefunctioncalledareabutitsnotamethodoftherectanglestruct(likeclassmethodsinclassicobject-orientedlanguages)Thefunctionandstructaretwoindependentthingsasyoumaynotice

ItsnotaproblemsofarHoweverifyoualsohavetocalculatetheareaofacirclesquarepentagonoranyotherkindofshapeyouaregoingtoneedtoaddadditionalfunctionswithverysimilarnames

Figure28Relationshipbetweenfunctionandstruct

ObviouslythatsnotcoolAlsotheareashouldreallybethepropertyofacircleorrectangle

ThisiswhereamethodcomestoplayThemethodisafunctionaffiliatedwithatypeIthassimilarsyntaxasfunctionexceptafterthefunckeywordhasaparametercalledthereceiverwhichisthemainbodyofthatmethod

UsingthesameexampleRectangleArea()belongsdirectlytorectangleinsteadofasaperipheralfunctionMorespecificallylengthwidthandArea()allbelongtorectangle

AsRobPikesaid

Amethodisafunctionwithanimplicitfirstargumentcalledareceiver

Syntaxofmethod

func(rReceiverType)funcName(parameters)(results)

Letschangeourexampleusingmethodinstead

Object-oriented

58

packagemain

import(

fmt

math

)

typeCirclestruct

radiusfloat64

typeRectanglestruct

widthheightfloat64

method

func(cCircle)Area()float64

returncradiuscradiusmathPi

method

func(rRectangle)Area()float64

returnrwidthrheight

funcmain()

c1=Circle10

c2=Circle25

r1=Rectangle94

r2=Rectangle122

fmtPrintln(Areaofc1isc1Area())

fmtPrintln(Areaofc2isc2Area())

fmtPrintln(Areaofr1isr1Area())

fmtPrintln(Areaofr2isr2Area())

Notesforusingmethods

IfthenameofmethodsarethesamebuttheydontsharethesamereceiverstheyarenotthesameMethodsareabletoaccessfieldswithinreceiversUsetocallamethodinthestructthesamewayfieldsarecalled

Figure29Methodsaredifferentindifferentstructs

IntheexampleabovetheArea()methodsbelongtobothRectangleandCirclerespectivelysothereceiversareRectangleandCircle

OnethingthatsworthnotingisthatthemethodwithadottedlinemeansthereceiverispassedbyvaluenotbyreferenceThedifferencebetweenthemisthatamethodcanchangeitsreceiversvalueswhenthereceiverispassedbyreferenceanditgetsacopyofthereceiverwhenthereceiverispassedbyvalue

CanthereceiveronlybeastructOfcoursenotAnytypecanbethereceiverofamethodYoumaybeconfusedaboutcustomizedtypesStructisaspecialkindofcustomizedtype-therearemorecustomizedtypes

Usethefollowingformattodefineacustomizedtype

typetypeNametypeLiteral

Examplesofcustomizedtypes

Object-oriented

59

typeageint

typemoneyfloat32

typemonthsmap[string]int

m=months

January31

February28

December31

IhopethatyouknowhowtousecustomizedtypesnowSimilartotypedefinCweuseagestosubstituteintintheaboveexample

Letsgetbacktotalkingaboutmethod

Youcanuseasmanymethodsincustomtypesasyouwant

packagemain

importfmt

const(

WHITE=iota

BLACK

BLUE

RED

YELLOW

)

typeBoxstruct

widthheightdepthfloat64

colorColor

typeColorbyte

typeBoxList[]Boxasliceofboxes

method

func(bBox)Volume()float64

returnbwidthbheightbdepth

methodwithapointerreceiver

func(bBox)SetColor(cColor)

bcolor=c

method

func(blBoxList)BiggestsColor()Color

v=000

k=Color(WHITE)

for_b=rangebl

ifbVolume()gtv

v=bVolume()

k=bcolor

returnk

method

func(blBoxList)PaintItBlack()

fori_=rangebl

bl[i]SetColor(BLACK)

method

func(cColor)String()string

Object-oriented

60

strings=[]stringWHITEBLACKBLUEREDYELLOW

returnstrings[c]

funcmain()

boxes=BoxList

Box444RED

Box10101YELLOW

Box1120BLACK

Box10101BLUE

Box10301WHITE

Box202020YELLOW

fmtPrintf(Wehavedboxesinoursetnlen(boxes))

fmtPrintln(Thevolumeofthefirstoneisboxes[0]Volume()cmsup3)

fmtPrintln(Thecolorofthelastoneisboxes[len(boxes)-1]colorString())

fmtPrintln(ThebiggestoneisboxesBiggestsColor()String())

Letspaintthemallblack

boxesPaintItBlack()

fmtPrintln(Thecolorofthesecondoneisboxes[1]colorString())

fmtPrintln(ObviouslynowthebiggestoneisboxesBiggestsColor()String())

Wedefinesomeconstantsandcustomizedtypes

UseColorasaliasofbyteDefineastructBoxwhichhasfieldsheightwidthlengthandcolorDefineastructBoxListwhichhasBoxasitsfield

Thenwedefinedsomemethodsforourcustomizedtypes

Volume()usesBoxasitsreceiverandreturnsthevolumeofBoxSetColor(cColor)changesBoxscolorBiggestsColor()returnsthecolorwhichhasthebiggestvolumePaintItBlack()setscolorforallBoxinBoxListtoblackString()useColorasitsreceiverreturnsthestringformatofcolorname

IsitmuchclearerwhenweusewordstodescribeourrequirementsWeoftenwriteourrequirementsbeforewestartcoding

Usepointerasreceiver

LetstakealookatSetColormethodItsreceiverisapointerofBoxYesyoucanuseBoxasareceiverWhydoweuseapointerhereBecausewewanttochangeBoxscolorinthismethodThusifwedontuseapointeritwillonlychangethevalueinsideacopyofBox

Ifweseethatareceiveristhefirstargumentofamethoditsnothardtounderstandhowitworks

Youmightbeaskingwhywearentusing(b)Color=cinsteadofbColor=cintheSetColor()methodEitheroneisOKherebecauseGoknowshowtointerprettheassignmentDoyouthinkGoismorefascinatingnow

Youmayalsobeaskingwhetherweshoulduse(ampbl[i])SetColor(BLACK)inPaintItBlackbecausewepassapointertoSetColorAgaineitheroneisOKbecauseGoknowshowtointerpretit

Inheritanceofmethod

WelearnedaboutinheritanceoffieldsinthelastsectionSimilarlywealsohavemethodinheritanceinGoIfananonymousfieldhasmethodsthenthestructthatcontainsthefieldwillhaveallthemethodsfromitaswell

Object-oriented

61

packagemain

importfmt

typeHumanstruct

namestring

ageint

phonestring

typeStudentstruct

Humananonymousfield

schoolstring

typeEmployeestruct

Human

companystring

defineamethodinHuman

func(hHuman)SayHi()

fmtPrintf(HiIamsyoucancallmeonsnhnamehphone)

funcmain()

sam=EmployeeHumanSam45111-888-XXXXGolangInc

mark=StudentHumanMark25222-222-YYYYMIT

samSayHi()

markSayHi()

MethodOverridingIfwewantEmployeetohaveitsownmethodSayHiwecandefineamethodthathasthesamenameinEmployeeanditwillhideSayHiinHumanwhenwecallit

Object-oriented

62

packagemain

importfmt

typeHumanstruct

namestring

ageint

phonestring

typeStudentstruct

Human

schoolstring

typeEmployeestruct

Human

companystring

func(hHuman)SayHi()

fmtPrintf(HiIamsyoucancallmeonsnhnamehphone)

func(eEmployee)SayHi()

fmtPrintf(HiIamsIworkatsCallmeonsnename

ecompanyephone)Yesyoucansplitinto2lineshere

funcmain()

sam=EmployeeHumanSam45111-888-XXXXGolangInc

mark=StudentHumanMark25222-222-YYYYMIT

samSayHi()

markSayHi()

YouareabletowriteanObject-orientedprogramnowandmethodsuseruleofcapitallettertodecidewhetherpublicorprivateaswell

LinksDirectoryPrevioussectionstructNextsectioninterface

Object-oriented

63

26Interface

InterfaceOneofthesubtlestdesignfeaturesinGoareinterfacesAfterreadingthissectionyouwilllikelybeimpressedbytheirimplementation

Whatisaninterface

Inshortaninterfaceisasetofmethodsthatweusetodefineasetofactions

LiketheexamplesinprevioussectionsbothStudentandEmployeecanSayHi()buttheydontdothesamething

LetsdosomemoreworkWelladdonemoremethodSing()tothemalongwiththeBorrowMoney()methodtoStudentandtheSpendSalary()methodtoEmployee

NowStudenthasthreemethodscalledSayHi()Sing()andBorrowMoney()andEmployeehasSayHi()Sing()andSpendSalary()

ThiscombinationofmethodsiscalledaninterfaceandisimplementedbybothStudentandEmployeeSoStudentandEmployeeimplementtheinterfaceSayHi()andSing()AtthesametimeEmployeedoesntimplementtheinterfaceBorrowMoney()andStudentdoesntimplementtheinterfaceSpendSalary()ThisisbecauseEmployeedoesnthavethemethodBorrowMoney()andStudentdoesnthavethemethodSpendSalary()

TypeofInterfaceAninterfacedefinesasetofmethodssoifatypeimplementsallthemethodswesaythatitimplementstheinterface

interface

64

typeHumanstruct

namestring

ageint

phonestring

typeStudentstruct

Human

schoolstring

loanfloat32

typeEmployeestruct

Human

companystring

moneyfloat32

defineinterfaces

typeMeninterface

SayHi()

Sing(lyricsstring)

Guzzle(beerSteinstring)

typeYoungChapinterface

SayHi()

Sing(songstring)

BorrowMoney(amountfloat32)

typeElderlyGentinterface

SayHi()

Sing(songstring)

SpendSalary(amountfloat32)

func(hHuman)SayHi()

fmtPrintf(HiIamsyoucancallmeonsnhnamehphone)

func(hHuman)Sing(lyricsstring)

fmtPrintln(Lalalalalalalalalalalyrics)

func(hHuman)Guzzle(beerSteinstring)

fmtPrintln(GuzzleGuzzleGuzzlebeerStein)

EmployeeoverloadsSayHi

func(eEmployee)SayHi()

fmtPrintf(HiIamsIworkatsCallmeonsnename

ecompanyephone)Yesyoucansplitinto2lineshere

func(sStudent)BorrowMoney(amountfloat32)

sloan+=amount(againandagainand)

func(eEmployee)SpendSalary(amountfloat32)

emoney-=amountMorevodkapleaseGetmethroughtheday

Weknowthataninterfacecanbeimplementedbyanytypeandonetypecanimplementmanyinterfacessimultaneously

Notethatanytypeimplementstheemptyinterfaceinterfacebecauseitdoesnthaveanymethodsandalltypeshavezeromethodsbydefault

Valueofinterface

interface

65

SowhatkindofvaluescanbeputintheinterfaceIfwedefineavariableasatypeinterfaceanytypethatimplementstheinterfacecanassignedtothisvariable

LiketheaboveexampleifwedefineavariablemasinterfaceMenthenanyoneofStudentHumanorEmployeecanbeassignedtomSowecouldhaveasliceofMenandanytypethatimplementsinterfaceMencanassigntothissliceBeawarehoweverthatthesliceofinterfacedoesnthavethesamebehaviorasasliceofothertypes

packagemain

importfmt

typeHumanstruct

namestring

ageint

phonestring

typeStudentstruct

Human

schoolstring

loanfloat32

typeEmployeestruct

Human

companystring

moneyfloat32

InterfaceMenimplementedbyHumanStudentandEmployee

typeMeninterface

SayHi()

Sing(lyricsstring)

method

func(hHuman)SayHi()

fmtPrintf(HiIamsyoucancallmeonsnhnamehphone)

method

func(hHuman)Sing(lyricsstring)

fmtPrintln(Lalalalalyrics)

method

func(eEmployee)SayHi()

fmtPrintf(HiIamsIworkatsCallmeonsnename

ecompanyephone)Yesyoucansplitinto2lineshere

funcmain()

mike=StudentHumanMike25222-222-XXXMIT000

paul=StudentHumanPaul26111-222-XXXHarvard100

sam=EmployeeHumanSam36444-222-XXXGolangInc1000

tom=EmployeeHumanSam36444-222-XXXThingsLtd5000

defineinterfacei

variMen

icanstoreStudent

i=mike

fmtPrintln(ThisisMikeaStudent)

iSayHi()

iSing(Novemberrain)

icanstoreEmployee

i=tom

fmtPrintln(ThisisTomanEmployee)

iSayHi()

interface

66

iSing(Borntobewild)

sliceofMen

fmtPrintln(LetsuseasliceofMenandseewhathappens)

x=make([]Men3)

thesethreeelementsaredifferenttypesbuttheyallimplementedinterfaceMen

x[0]x[1]x[2]=paulsammike

for_value=rangex

valueSayHi()

Aninterfaceisasetofabstractmethodsandcanbeimplementedbynon-interfacetypesItcannotthereforeimplementitself

Emptyinterface

AnemptyinterfaceisaninterfacethatdoesntcontainanymethodssoalltypesimplementanemptyinterfaceThisfactisveryusefulwhenwewanttostorealltypesatsomepointandissimilartovoidinC

defineaasemptyinterface

varvoidinterface

vars

i=5

s=Helloworld

acanstorevalueofanytype

void=i

void=s

Ifafunctionusesanemptyinterfaceasitsargumenttypeitcanacceptanytypeifafunctionusesemptyinterfaceasitsreturnvaluetypeitcanreturnanytype

Methodargumentsofaninterface

AnyvariablecanbeusedinaninterfaceSohowcanweusethisfeaturetopassanytypeofvariabletoafunction

ForexampleweusefmtPrintlnalotbuthaveyouevernoticedthatitcanacceptanytypeofargumentLookingattheopensourcecodeoffmtweseethefollowingdefinition

typeStringerinterface

String()string

ThismeansanytypethatimplementsinterfaceStringercanbepassedtofmtPrintlnasanargumentLetsproveit

interface

67

packagemain

import(

fmt

strconv

)

typeHumanstruct

namestring

ageint

phonestring

HumanimplementsfmtStringer

func(hHuman)String()string

returnName+hname+Age+strconvItoa(hage)+yearsContact+hphone

funcmain()

Bob=HumanBob39000-7777-XXX

fmtPrintln(ThisHumanisBob)

LookingbacktotheexampleofBoxyouwillfindthatColorimplementsinterfaceStringeraswellsoweareabletocustomizetheprintformatIfwedontimplementthisinterfacefmtPrintlnprintsthetypewithitsdefaultformat

fmtPrintln(ThebiggestoneisboxesBiggestsColor()String())

fmtPrintln(ThebiggestoneisboxesBiggestsColor())

AttentionIfthetypeimplementedtheinterfaceerrorfmtwillcallError()soyoudonthavetoimplementStringeratthispoint

TypeofvariableinaninterfaceIfavariableisthetypethatimplementsaninterfaceweknowthatanyothertypethatimplementsthesameinterfacecanbeassignedtothisvariableThequestionishowcanweknowthespecifictypestoredintheinterfaceTherearetwowayswhichIwillshowyou

AssertionofComma-okpattern

Gohasthesyntaxvalueok=element(T)ThischeckstoseeifthevariableisthetypethatweexpectwherevalueisthevalueofthevariableokisavariableofbooleantypeelementistheinterfacevariableandtheTisthetypeofassertion

Iftheelementisthetypethatweexpectokwillbetruefalseotherwise

Letsuseanexampletoseemoreclearly

interface

68

packagemain

import(

fmt

strconv

)

typeElementinterface

typeList[]Element

typePersonstruct

namestring

ageint

func(pPerson)String()string

return(name+pname+-age+strconvItoa(page)+years)

funcmain()

list=make(List3)

list[0]=1anint

list[1]=Helloastring

list[2]=PersonDennis70

forindexelement=rangelist

ifvalueok=element(int)ok

fmtPrintf(list[d]isanintanditsvalueisdnindexvalue)

elseifvalueok=element(string)ok

fmtPrintf(list[d]isastringanditsvalueissnindexvalue)

elseifvalueok=element(Person)ok

fmtPrintf(list[d]isaPersonanditsvalueissnindexvalue)

else

fmtPrintf(list[d]isofadifferenttypenindex)

Itsquiteeasytousethispatternbutifwehavemanytypestotestwedbetteruseswitch

switchtest

Letsuseswitchtorewritetheaboveexample

interface

69

packagemain

import(

fmt

strconv

)

typeElementinterface

typeList[]Element

typePersonstruct

namestring

ageint

func(pPerson)String()string

return(name+pname+-age+strconvItoa(page)+years)

funcmain()

list=make(List3)

list[0]=1anint

list[1]=Helloastring

list[2]=PersonDennis70

forindexelement=rangelist

switchvalue=element(type)

caseint

fmtPrintf(list[d]isanintanditsvalueisdnindexvalue)

casestring

fmtPrintf(list[d]isastringanditsvalueissnindexvalue)

casePerson

fmtPrintf(list[d]isaPersonanditsvalueissnindexvalue)

default

fmtPrintln(list[d]isofadifferenttypeindex)

Onethingyoushouldrememberisthatelement(type)cannotbeusedoutsideoftheswitchbodywhichmeansinthatcaseyouhavetousethecomma-okpattern

Embeddedinterfaces

ThemostbeautifulthingisthatGohasalotofbuilt-inlogicsyntaxsuchasanonymousfieldsinstructNotsuprisinglywecanuseinterfacesasanonymousfieldsaswellbutwecallthemEmbeddedinterfacesHerewefollowthesamerulesasanonymousfieldsMorespecificallyifaninterfacehasanotherinterfaceembeddedwithinititwillbehaveasifithasallthemethodsthattheembeddedinterfacehas

Wecanseethatthesourcefileincontainerheaphasthefollowingdefinition

typeInterfaceinterface

sortInterfaceembeddedsortInterface

Push(xinterface)aPushmethodtopushelementsintotheheap

Pop()interfaceaPopmethodthatpopselementsfromtheheap

WeseethatsortInterfaceisanembeddedinterfacesotheaboveInterfacehasthethreemethodscontainedwithinthesortInterfaceimplicitly

interface

70

typeInterfaceinterface

Lenisthenumberofelementsinthecollection

Len()int

Lessreturnswhethertheelementwithindexishouldsort

beforetheelementwithindexj

Less(ijint)bool

Swapswapstheelementswithindexesiandj

Swap(ijint)

AnotherexampleistheioReadWriterinpackageio

ioReadWriter

typeReadWriterinterface

Reader

Writer

Reflection

ReflectioninGoisusedfordetermininginformationatruntimeWeusethereflectpackageandTheLawsofReflectionpostexplainshowreflectworksinGo

TherearethreestepsinvolvedwhenusingreflectFirstweneedtoconvertaninterfacetoreflecttypes(reflectTypeorreflectValuethisdependsonthesituation)

t=reflectTypeOf(i)getmeta-dataintypeiandusettogetallelements

v=reflectValueOf(i)getactualvalueintypeiandusevtochangeitsvalue

Afterthatwecanconvertthereflectedtypestogetthevaluesthatweneed

varxfloat64=34

t=reflectTypeOf(x)

v=reflectValueOf(x)

fmtPrintln(typet)

fmtPrintln(valuev)

fmtPrintln(kindisfloat64vKind()==reflectFloat64)

FinallyifwewanttochangethevaluesofthereflectedtypesweneedtomakeitmodifiableAsdiscussedearlierthereisadifferencebetweenpassbyvalueandpassbyreferenceThefollowingcodewillnotcompile

varxfloat64=34

v=reflectValueOf(x)

vSetFloat(71)

Insteadwemustusethefollowingcodetochangethevaluesfromreflecttypes

varxfloat64=34

p=reflectValueOf(ampx)

v=pElem()

vSetFloat(71)

Wehavejustdiscussedthebasicsofreflectionhoweveryoumustpracticemoreinordertounderstandmore

Links

interface

71

DirectoryPrevioussectionObject-orientedNextsectionConcurrency

interface

72

ConcurrencyItissaidthatGoistheCofthe21stcenturyIthinktherearetworeasonsforitFirstGoisasimplelanguageSecondconcurrencyisahottopicintodaysworldandGosupportsthisfeatureatthelanguagelevel

goroutinegoroutinesandconcurrencyarebuiltintothecoredesignofGoTheyresimilartothreadsbutworkdifferentlyGoalsogivesyoufullsupporttosharingmemoryinyourgoroutinesOnegoroutineusuallyuses4~5KBofstackmemoryThereforeitsnothardtorunthousandsofgoroutinesonasinglecomputerAgoroutineismorelightweightmoreefficientandmoreconvenientthansystemthreads

goroutinesrunonthethreadmanageratruntimeinGoWeusethegokeywordtocreateanewgoroutinewhichisafunctionattheunderlyinglevel(main()isagoroutine)

gohello(abc)

Letsseeanexample

packagemain

import(

fmt

runtime

)

funcsay(sstring)

fori=0ilt5i++

runtimeGosched()

fmtPrintln(s)

funcmain()

gosay(world)createanewgoroutine

say(hello)currentgoroutine

Output

hello

world

hello

world

hello

world

hello

world

hello

WeseethatitsveryeasytouseconcurrencyinGobyusingthekeywordgoIntheaboveexamplethesetwogoroutinessharesomememorybutwewouldbetterofffollowingthedesignrecipeDontuseshareddatatocommunicateusecommunicationtosharedata

runtimeGosched()meanslettheCPUexecuteothergoroutinesandcomebackatsomepoint

InGo15theruntimenowsetsthedefaultnumberofthreadstorunsimultaneouslydefinedbyGOMAXPROCStothenumberofcoresavailableontheCPU

Concurrency

73

BeforeGo15ThescheduleronlyusesonethreadtorunallgoroutineswhichmeansitonlyimplementsconcurrencyIfyouwanttousemoreCPUcoresinordertotakeadvantageofparallelprocessingyouhavetocallruntimeGOMAXPROCS(n)tosetthenumberofcoresyouwanttouseIfnlt1itchangesnothing

channelsgoroutinesruninthesamememoryaddressspacesoyouhavetomaintainsynchronizationwhenyouwanttoaccesssharedmemoryHowdoyoucommunicatebetweendifferentgoroutinesGousesaverygoodcommunicationmechanismcalledchannelAchannelisliketwo-waypipelineinUnixshellsusechanneltosendorreceivedataTheonlydatatypethatcanbeusedinchannelsisthetypechannelandthekeywordchanBeawarethatyouhavetousemaketocreateanewchannel

ci=make(chanint)

cs=make(chanstring)

cf=make(chaninterface)

channelusestheoperatorlt-tosendorreceivedata

chlt-vsendvtochannelch

v=lt-chreceivedatafromchandassigntov

Letsseemoreexamples

packagemain

importfmt

funcsum(a[]intcchanint)

total=0

for_v=rangea

total+=v

clt-totalsendtotaltoc

funcmain()

a=[]int728-940

c=make(chanint)

gosum(a[len(a)2]c)

gosum(a[len(a)2]c)

xy=lt-clt-creceivefromc

fmtPrintln(xyx+y)

SendingandreceivingdatainchannelsblocksbydefaultsoitsmucheasiertousesynchronousgoroutinesWhatImeanbyblockisthatagoroutinewillnotcontinuewhenreceivingdatafromanemptychannelie(value=lt-ch)untilothergoroutinessenddatatothischannelOntheotherhandthegoroutinewillnotcontinueuntilthedataitsendstoachannelie(chlt-5)isreceived

BufferedchannelsIintroducednon-bufferedchannelsaboveGoalsohasbufferedchannelsthatcanstoremorethanasingleelementForexamplech=make(chanbool4)herewecreateachannelthatcanstore4booleanelementsSointhischannelweareabletosend4elementsintoitwithoutblockingbutthegoroutinewillbeblockedwhenyoutrytosendafifthelementandnogoroutinereceivesit

Concurrency

74

ch=make(chantypen)

n==0non-buffer(block)

ngt0buffer(non-blockuntilnelementsinthechannel)

Youcantrythefollowingcodeonyourcomputerandchangesomevalues

packagemain

importfmt

funcmain()

c=make(chanint2)change2to1willhaveruntimeerrorbut3isfine

clt-1

clt-2

fmtPrintln(lt-c)

fmtPrintln(lt-c)

RangeandCloseWecanuserangetooperateonbufferchannelsasinsliceandmap

packagemain

import(

fmt

)

funcfibonacci(nintcchanint)

xy=11

fori=0iltni++

clt-x

xy=yx+y

close(c)

funcmain()

c=make(chanint10)

gofibonacci(cap(c)c)

fori=rangec

fmtPrintln(i)

fori=rangecwillnotstopreadingdatafromchanneluntilthechannelisclosedWeusethekeywordclosetoclosethechannelinaboveexampleItsimpossibletosendorreceivedataonaclosedchannelyoucanusevok=lt-chtotestifachannelisclosedIfokreturnsfalseitmeansthethereisnodatainthatchannelanditwasclosed

Remembertoalwaysclosechannelsinproducersandnotinconsumersoritsveryeasytogetintopanicstatus

AnotherthingyouneedtorememberisthatchannelsarenotlikefilesYoudonthavetoclosethemfrequentlyunlessyouaresurethechanneliscompletelyuselessoryouwanttoexitrangeloops

SelectIntheaboveexamplesweonlyuseonechannelbuthowcanwedealwithmorethanonechannelGohasakeywordcalledselecttolistentomanychannels

Concurrency

75

selectisblockingbydefaultanditcontinuestoexecuteonlywhenoneofchannelshasdatatosendorreceiveIfseveralchannelsarereadytouseatthesametimeselectchooseswhichtoexecuterandomly

packagemain

importfmt

funcfibonacci(cquitchanint)

xy=11

for

select

caseclt-x

xy=yx+y

caselt-quit

fmtPrintln(quit)

return

funcmain()

c=make(chanint)

quit=make(chanint)

gofunc()

fori=0ilt10i++

fmtPrintln(lt-c)

quitlt-0

()

fibonacci(cquit)

selecthasadefaultcaseaswelljustlikeswitchWhenallthechannelsarenotreadyforuseitexecutesthedefaultcase(itdoesntwaitforthechannelanymore)

select

casei=lt-c

usei

default

executesherewhencisblocked

TimeoutSometimesagoroutinebecomesblockedHowcanweavoidthistopreventthewholeprogramfromblockingItssimplewecansetatimeoutintheselect

funcmain()

c=make(chanint)

o=make(chanbool)

gofunc()

for

select

casev=lt-c

println(v)

caselt-timeAfter(5timeSecond)

println(timeout)

olt-true

break

()

lt-o

Concurrency

76

RuntimegoroutineThepackageruntimehassomefunctionsfordealingwithgoroutines

runtimeGoexit()

Exitsthecurrentgoroutinebutdeferedfunctionswillbeexecutedasusual

runtimeGosched()

Letstheschedulerexecuteothergoroutinesandcomesbackatsomepoint

runtimeNumCPU()int

ReturnsthenumberofCPUcores

runtimeNumGoroutine()int

Returnsthenumberofgoroutines

runtimeGOMAXPROCS(nint)int

SetshowmanyCPUcoresyouwanttouse

LinksDirectoryPrevioussectioninterfaceNextsectionSummary

Concurrency

77

28SummaryInthischapterwemainlyintroducedthe25GokeywordsLetsreviewwhattheyareandwhattheydo

breakdefaultfuncinterfaceselect

casedefergomapstruct

chanelsegotopackageswitch

constfallthroughifrangetype

continueforimportreturnvar

varandconstareusedtodefinevariablesandconstantspackageandimportareforpackageusefuncisusedtodefinefunctionsandmethodsreturnisusedtoreturnvaluesinfunctionsormethodsdeferisusedtodefinedeferfunctionsgoisusedtostartanewgoroutineselectisusedtoswitchovermultiplechannelsforcommunicationinterfaceisusedtodefineinterfacesstructisusedtodefinespecialcustomizedtypesbreakcasecontinueforfallthroughelseifswitchgotoanddefaultwereintroducedinsection23chanisthetypeofchannelforcommunicationamonggoroutinestypeisusedtodefinecustomizedtypesmapisusedtodefinemapwhichissimilartohashtablesinotherlanguagesrangeisusedforreadingdatafromslicemapandchannel

Ifyouunderstandhowtousethese25keywordsyouvelearnedalotofGoalready

LinksDirectoryPrevioussectionConcurrencyNextchapterWebfoundation

Summary

78

3WebfoundationThereasonyouarereadingthisbookisthatyouwanttolearntobuildwebapplicationsinGoAsIvesaidbeforeGoprovidesmanypowerfulpackageslikehttpThesepackagescanhelpyoualotwhentryingtobuildwebapplicationsIllteachyoueverythingyouneedtoknowinthefollowingchaptersandwelltalkaboutsomeconceptsofthewebandhowtorunwebapplicationsinGointhischapter

LinksDirectoryPreviouschapterChapter2SummaryNextsectionWebworkingprinciples

Webfoundation

79

WebworkingprinciplesEverytimeyouopenyourbrowserstypesomeURLsandpressenteryouwillseebeautifulwebpagesappearonyourscreenButdoyouknowwhatishappeningbehindthesesimpleactions

NormallyyourbrowserisaclientAfteryoutypeaURLittakesthehostpartoftheURLandsendsittoaDomainNameServer(DNS)inordertogettheIPaddressofthehostThenitconnectstotheIPaddressandaskstosetupaTCPconnectionThebrowsersendsHTTPrequeststhroughtheconnectionTheserverhandlesthemandreplieswithHTTPresponsescontainingthecontentthatmakeupthewebpageFinallythebrowserrendersthebodyofthewebpageanddisconnectsfromtheserver

Figure31Processesofusersvisitawebsite

AwebserveralsoknownasanHTTPserverusestheHTTPprotocoltocommunicatewithclientsAllwebbrowserscanbeconsideredclients

Wecandividethewebsworkingprinciplesintothefollowingsteps

ClientusesTCPIPprotocoltoconnecttoserverClientsendsHTTPrequestpackagestoserverServerreturnsHTTPresponsepackagestoclientIftherequestedresourcesincludedynamicscriptsservercallsscriptenginefirstClientdisconnectsfromserverstartsrenderingHTML

ThisisasimpleworkflowofHTTPaffairs-noticethattheserverclosesitsconnectionsafteritsendsdatatotheclientsthenwaitsforthenextrequest

URLandDNSresolutionWealwaysuseURLstoaccesswebpagesbutdoyouknowhowURLswork

ThefullnameofaURLisUniformResourceLocatorItsfordescribingresourcesontheinternetanditsbasicformisasfollows

schemehost[port]path[query-string][anchor]

schemeassignunderlyingprotocol(suchasHTTPHTTPSFTP)

hostIPordomainnameofHTTPserver

portdefaultportis80anditcanbeomittedinthiscase

IfyouwanttouseotherportsyoumustspecifywhichportForexample

httpwwwcnblogscom8080

pathresourcespath

query-stringdataaresenttoserver

anchoranchor

DNSisanabbreviationofDomainNameSystemItsthenamingsystemforcomputernetworkservicesanditconvertsdomainnamestoactualIPaddressesjustlikeatranslator

Figure32DNSworkingprinciples

TounderstandmoreaboutitsworkingprincipleletsseethedetailedDNSresolutionprocessasfollows

1 AftertypingthedomainnamewwwqqcominthebrowsertheoperatingsystemwillcheckifthereareanymappingrelationshipsinthehostsfilesforthisdomainnameIfsothenthedomainnameresolutioniscomplete

2 IfnomappingrelationshipsexistinthehostsfilestheoperatingsystemwillcheckifanycacheexistsintheDNSIfso

Webworkingprinciples

80

thenthedomainnameresolutioniscomplete3 IfnomappingrelationshipsexistinboththehostandDNScachetheoperatingsystemfindsthefirstDNSresolution

serverinyourTCPIPsettingswhichislikelyyourlocalDNSserverWhenthelocalDNSserverreceivesthequeryifthedomainnamethatyouwanttoqueryiscontainedwithinthelocalconfigurationofitsregionalresourcesitreturnstheresultstotheclientThisDNSresolutionisauthoritative

4 IfthelocalDNSserverdoesntcontainthedomainnamebutamappingrelationshipexistsinthecachethelocalDNSservergivesbackthisresulttotheclientThisDNSresolutionisnotauthoritative

5 IfthelocalDNSservercannotresolvethisdomainnameeitherbyconfigurationofregionalresourcesorcacheitwillproceedtothenextstepwhichdependsonthelocalDNSserverssettings-IfthelocalDNSserverdoesntenableforwardingitroutestherequesttotherootDNSserverthenreturnstheIPaddressofatoplevelDNSserverwhichmayknowthedomainnamecominthiscaseIfthefirsttoplevelDNSserverdoesntrecognizethedomainnameitagainreroutestherequesttothenexttoplevelDNSserveruntilitreachesonethatrecognizesthedomainnameThenthetoplevelDNSserverasksthisnextlevelDNSserverfortheIPaddresscorrespondingtowwwqqcom-IfthelocalDNSserverhasforwardingenableditsendstherequesttoanupperlevelDNSserverIftheupperlevelDNSserveralsodoesntrecognizethedomainnamethentherequestkeepsgettingreroutedtohigherlevelsuntilitfinallyreachesaDNSserverwhichrecognizesthedomainname

WhetherornotthelocalDNSserverenablesforwardingtheIPaddressofthedomainnamealwaysreturnstothelocalDNSserverandthelocalDNSserversendsitbacktotheclient

Figure33DNSresolutionworkflow

RecursivequeryprocesssimplymeansthattheenquirerschangeintheprocessEnquirersdonotchangeinIterativequeryprocesses

NowweknowclientsgetIPaddressesintheendsothebrowsersarecommunicatingwithserversthroughIPaddresses

HTTPprotocolTheHTTPprotocolisacorepartofwebservicesItsimportanttoknowwhattheHTTPprotocolisbeforeyouunderstandhowthewebworks

HTTPistheprotocolthatisusedtofacilitatecommunicationbetweenbrowserandwebserverItisbasedontheTCPprotocolandusuallyusesport80onthesideofthewebserverItisaprotocolthatutilizestherequest-responsemodel-clientssendrequestsandserversrespondAccordingtotheHTTPprotocolclientsalwayssetupnewconnectionsandsendHTTPrequeststoserversServersarenotabletoconnecttoclientsproactivelyorestablishcallbackconnectionsTheconnectionbetweenaclientandaservercanbeclosedbyeithersideForexampleyoucancancelyourdownloadrequestandHTTPconnectionandyourbrowserwilldisconnectfromtheserverbeforeyoufinishdownloading

TheHTTPprotocolisstatelesswhichmeanstheserverhasnoideaabouttherelationshipbetweenthetwoconnectionseventhoughtheyarebothfromsameclientTosolvethisproblemwebapplicationsusecookiestomaintainthestateofconnections

BecausetheHTTPprotocolisbasedontheTCPprotocolallTCPattackswillaffectHTTPcommunicationsinyourserverExamplesofsuchattacksareSYNfloodingDoSandDDoSattacks

HTTPrequestpackage(browserinformation)

RequestpackagesallhavethreepartsrequestlinerequestheaderandbodyThereisoneblanklinebetweenheaderandbody

Webworkingprinciples

81

GETdomainsexampleHTTP11requestlinerequestmethodURLprotocolanditsversion

Hostwwwianaorgdomainname

User-AgentMozilla50(WindowsNT61)AppleWebKit5374(KHTMLlikeGecko)Chrome220122994Safari5374

browserinformation

Accepttexthtmlapplicationxhtml+xmlapplicationxmlq=09q=08mimethatclientscanaccept

Accept-Encodinggzipdeflatesdchstreamcompression

Accept-CharsetUTF-8q=05charactersetinclientside

blankline

bodyrequestresourcearguments(forexampleargumentsinPOST)

Weusefiddlertogetthefollowingrequestinformation

Figure34InformationofaGETrequestcaughtbyfiddler

Figure35InformationofaPOSTrequestcaughtbyfiddler

WecanseethatGETdoesnothavearequestbodyunlikePOSTwhichdoes

TherearemanymethodsyoucanusetocommunicatewithserversinHTTPGETPOSTPUTandDELETEarethe4basicmethodsthatwetypicallyuseAURLrepresentsaresourceonanetworksothese4methodsdefinethequerychangeaddanddeleteoperationsthatcanactontheseresourcesGETandPOSTareverycommonlyusedinHTTPGETcanappendqueryparameterstotheURLusingtoseparatetheURLandparametersandampbetweentheargumentslikeEditPostsaspxname=test1ampid=123456POSTputsdataintherequestbodybecausetheURLimplementsalengthlimitationviathebrowserThusPOSTcansubmitmuchmoredatathanGETAlsowhenwesubmitusernamesandpasswordswedontwantthiskindofinformationtoappearintheURLsoweusePOSTtokeeptheminvisible

HTTPresponsepackage(serverinformation)Letsseewhatinformationiscontainedintheresponsepackages

HTTP11200OKstatusline

Servernginx108webserversoftwareanditsversionintheservermachine

DateDateTue30Oct2012041425GMTrespondedtime

Content-Typetexthtmlrespondeddatatype

Transfer-Encodingchunkeditmeansdataweresentinfragments

Connectionkeep-alivekeepconnection

Content-Length90lengthofbody

blankline

ltDOCTYPEhtmlPUBLIC-W3CDTDXHTML10TransitionalENmessagebody

ThefirstlineiscalledthestatuslineItsuppliestheHTTPversionstatuscodeandstatusmessage

ThestatuscodeinformstheclientofthestatusoftheHTTPserversresponseInHTTP115kindsofstatuscodesweredefined

-1xxInformational

-2xxSuccess

-3xxRedirection

-4xxClientError

-5xxServerError

Letsseemoreexamplesaboutresponsepackages200meansserverrespondedcorrectly302meansredirection

Figure36Fullinformationforvisitingawebsite

HTTPisstatelessandConnectionkeep-alive

Webworkingprinciples

82

ThetermstatelessdoesntmeanthattheserverhasnoabilitytokeepaconnectionItsimplymeansthattheserverdoesntrecognizeanyrelationshipsbetweenanytworequests

InHTTP11Keep-aliveisusedbydefaultIfclientshaveadditionalrequeststheywillusethesameconnectionforthem

NoticethatKeep-alivecannotmaintainoneconnectionforevertheapplicationrunningintheserverdeterminesthelimitwithwhichtokeeptheconnectionaliveforandinmostcasesyoucanconfigurethislimit

Requestinstance

Figure37Allpackagesforopeningonewebpage

WecanseetheentirecommunicationprocessbetweenclientandserverfromtheabovepictureYoumaynoticethattherearemanyresourcefilesinthelistthesearecalledstaticfilesandGohasspecializedprocessingmethodsforthesefiles

ThisisthemostimportantfunctionofbrowserstorequestforaURLandretrievedatafromwebserversthenrendertheHTMLIfitfindssomefilesintheDOMsuchasCSSorJSfilesbrowserswillrequesttheseresourcesfromtheserveragainuntilalltheresourcesfinishrenderingonyourscreen

ReducingHTTPrequesttimesisonewayofimprovingtheloadingspeedofwebpagesByreducingthenumberofCSSandJSfilesthatneedtobeloadedbothrequestlatenciesandpressureonyourwebserverscanbereducedatthesametime

LinksDirectoryPrevioussectionWebfoundationNextsectionBuildasimplewebserver

Webworkingprinciples

83

32BuildasimplewebserverWevediscussedthatwebapplicationsarebasedontheHTTPprotocolandGoprovidesfullHTTPsupportinthenethttppackageItsveryeasytosetawebserverupusingthispackage

Usehttppackagesetupawebserver

packagemain

import(

fmt

nethttp

strings

log

)

funcsayhelloName(whttpResponseWriterrhttpRequest)

rParseForm()parseargumentsyouhavetocallthisbyyourself

fmtPrintln(rForm)printforminformationinserverside

fmtPrintln(pathrURLPath)

fmtPrintln(schemerURLScheme)

fmtPrintln(rForm[url_long])

forkv=rangerForm

fmtPrintln(keyk)

fmtPrintln(valstringsJoin(v))

fmtFprintf(wHelloastaxie)senddatatoclientside

funcmain()

httpHandleFunc(sayhelloName)setrouter

err=httpListenAndServe(9090nil)setlistenport

iferr=nil

logFatal(ListenAndServeerr)

Afterweexecutetheabovecodetheserverbeginslisteningtoport9090inlocalhost

Openyourbrowserandvisithttplocalhost9090YoucanseethatHelloastaxieisonyourscreen

Letstryanotheraddresswithadditionalargumentshttplocalhost9090url_long=111ampurl_long=222

Nowletsseewhathappensonboththeclientandserversides

Youshouldseethefollowinginformationontheserverside

Figure38Serverprintedinformation

Asyoucanseeweonlyneedtocalltwofunctionsinordertobuildasimplewebserver

IfyouareworkingwithPHPyoureprobablyaskingwhetherornotweneedsomethinglikeNginxorApacheTheansweriswedontsinceGolistenstotheTCPportbyitselfandthefunctionsayhelloNameisthelogicfunctionjustlikeacontrollerinPHP

IfyouareworkingwithPythonyoushouldknowtornadoandtheaboveexampleisverysimilartothat

IfyouareworkingwithRubyyoumaynoticeitislikescriptserverinROR(RubyonRails)

Buildasimplewebserver

84

WeusedtwosimplefunctionstosetupasimplewebserverinthissectionandthissimpleserveralreadyhasthecapacityforhighconcurrencyoperationsWewilltalkabouthowtoutilizethisinthenexttwosections

LinksDirectoryPrevioussectionWebworkingprinciplesNextsectionHowGoworkswithweb

Buildasimplewebserver

85

33HowGoworkswithwebWelearnedtousethenethttppackagetobuildasimplewebserverintheprevioussectionandallthoseworkingprinciplesarethesameasthosewewilltalkaboutinthefirstsectionofthischapter

ConceptsinwebprinciplesRequestrequestdatafromusersincludingPOSTGETCookieandURL

Responseresponsedatafromservertoclients

Connconnectionsbetweenclientsandservers

HandlerRequesthandlinglogicandresponsegeneration

httppackageoperatingmechanismThefollowingpictureshowstheworkflowofaGowebserver

Figure39httpworkflow

1 Createalisteningsocketlistentoaportandwaitforclients2 Acceptrequestsfromclients3 HandlerequestsreadHTTPheaderIftherequestusesPOSTmethodreaddatainthemessagebodyandpassthem

tohandlersFinallysocketreturnsresponsedatatoclients

OnceweknowtheanswerstothethreefollowingquestionsitseasytoknowhowthewebworksinGo

HowdowelistentoaportHowdoweacceptclientrequestsHowdoweallocatehandlers

IntheprevioussectionwesawthatGousesListenAndServetohandlethesestepsinitializeaserverobjectcallnetListen(tcpaddr)tosetupaTCPlistenerandlistentoaspecificaddressandport

Letstakealookatthehttppackagessourcecode

HowGoworkswithweb

86

Buildversiongo112

func(srvServer)Serve(lnetListener)error

deferlClose()

vartempDelaytimeDurationhowlongtosleeponacceptfailure

for

rwe=lAccept()

ife=nil

ifneok=e(netError)okampampneTemporary()

iftempDelay==0

tempDelay=5timeMillisecond

else

tempDelay=2

ifmax=1timeSecondtempDelaygtmax

tempDelay=max

logPrintf(httpAccepterrorvretryinginvetempDelay)

timeSleep(tempDelay)

continue

returne

tempDelay=0

cerr=srvnewConn(rw)

iferr=nil

continue

gocserve()

HowdoweacceptclientrequestsafterwebeginlisteningtoaportInthesourcecodewecanseethatsrvServe(netListener)iscalledtohandleclientrequestsInthebodyofthefunctionthereisaforItacceptsarequestcreatesanewconnectionthenstartsanewgoroutinepassingtherequestdatatothegocserve()goroutineThisishowGosupportshighconcurrencyandeverygoroutineisindependent

HowdoweusespecificfunctionstohandlerequestsconnparsesrequestcReadRequest()atfirstthengetsthecorrespondinghandlerhandler=shsrvHandlerwhichisthesecondargumentwepassedwhenwecalledListenAndServeBecausewepassednilGousesitsdefaulthandlerhandler=DefaultServeMuxSowhatisDefaultServeMuxdoinghereWellitstheroutervariablewhichcancallhandlerfunctionsforspecificURLsDidwesetthisYeswedidWedidthisinthefirstlinewhereweusedhttpHandleFunc(sayhelloName)WereusingthisfunctiontoregistertherouterruleforthepathWhentheURListheroutercallsthefunctionsayhelloNameDefaultServeMuxcallsServerHTTPtogethandlerfunctionsfordifferentpathscallingsayhelloNameinthisspecificcaseFinallytheserverwritesdataandrespondstoclients

Detailedworkflow

Figure310WorkflowofhandlinganHTTPrequest

IthinkyoushouldknowhowGorunswebserversnow

LinksDirectoryPrevioussectionBuildasimplewebserverNextsectionGetintohttppackage

HowGoworkswithweb

87

HowGoworkswithweb

88

34GetintohttppackageInprevioussectionswelearnedabouttheworkflowofthewebandtalkedalittlebitaboutGoshttppackageInthissectionwearegoingtolearnabouttwocorefunctionsinthehttppackageConnandServeMux

goroutineinConnUnlikenormalHTTPserversGousesgoroutinesforeveryjobinitiatedbyConninordertoachievehighconcurrencyandperformancesoeveryjobisindependent

Gousesthefollowingcodetowaitfornewconnectionsfromclients

cerr=srvnewConn(rw)

iferr=nil

continue

gocserve()

Asyoucanseeitcreatesanewgoroutineforeveryconnectionandpassesthehandlerthatisabletoreaddatafromtherequesttothegoroutine

CustomizedServeMuxWeusedGosdefaultrouterinprevioussectionswhendiscussingconnserverwiththerouterpassingrequestdatatoaback-endhandler

Thestructofthedefaultrouter

typeServeMuxstruct

musyncRWMutexbecauseofconcurrencywehavetouseamutexhere

mmap[string]muxEntryrouterruleseverystringmappingtoahandler

ThestructofmuxEntry

typemuxEntrystruct

explicitboolexactmatchornot

hHandler

TheinterfaceofHandler

typeHandlerinterface

ServeHTTP(ResponseWriterRequest)routingimplementer

HandlerisaninterfacebutifthefunctionsayhelloNamedidntimplementthisinterfacethenhowdidweadditashandlerTheanswerliesinanothertypecalledHandlerFuncinthehttppackageWecalledHandlerFunctodefineoursayhelloNamemethodsosayhelloNameimplementedHandleratthesametimeItslikewerecallingHandlerFunc(f)andthefunctionfisforceconvertedtotypeHandlerFunc

Getintohttppackage

89

typeHandlerFuncfunc(ResponseWriterRequest)

ServeHTTPcallsf(wr)

func(fHandlerFunc)ServeHTTP(wResponseWriterrRequest)

f(wr)

Howdoestheroutercallhandlersafterwesettherouterrules

TheroutercallsmuxhandlerServeHTTP(wr)whenitreceivesrequestsInotherwordsitcallstheServeHTTPinterfaceofthehandlerswhichhaveimplementedit

Nowletsseehowmuxhandlerworks

func(muxServeMux)handler(rRequest)Handler

muxmuRLock()

defermuxmuRUnlock()

Host-specificpatterntakesprecedenceovergenericones

h=muxmatch(rHost+rURLPath)

ifh==nil

h=muxmatch(rURLPath)

ifh==nil

h=NotFoundHandler()

returnh

TherouterusestherequestsURLasakeytofindthecorrespondinghandlersavedinthemapthencallshandlerServeHTTPtoexecutefunctionstohandlethedata

YoushouldunderstandthedefaultroutersworkflowbynowandGoactuallysupportscustomizedroutersThesecondargumentofListenAndServeisforconfiguringcustomizedroutersItsaninterfaceofHandlerThereforeanyrouterthatimplementstheHandlerinterfacecanbeused

Thefollowingexampleshowshowtoimplementasimplerouter

packagemain

import(

fmt

nethttp

)

typeMyMuxstruct

func(pMyMux)ServeHTTP(whttpResponseWriterrhttpRequest)

ifrURLPath==

sayhelloName(wr)

return

httpNotFound(wr)

return

funcsayhelloName(whttpResponseWriterrhttpRequest)

fmtFprintf(wHellomyroute)

funcmain()

mux=ampMyMux

httpListenAndServe(9090mux)

Getintohttppackage

90

RoutingIfyoudonotwanttouseaRouteryoucanstillachievewhatwewroteintheabovesectionbyreplacingthesecondargumenttoListenAndServetonilandregisteringtheURLsusingaHandleFuncfunctionwhichgoesthroughalltheregisteredURLstofindthebestmatchsocaremustbetakenabouttheorderoftheregistering

samplecode

httpHandleFunc(viewsShowAllTasksFunc)

httpHandleFunc(completeviewsCompleteTaskFunc)

httpHandleFunc(deleteviewsDeleteTaskFunc)

ShowAllTasksFuncisusedtohandletheURLwhichisthedefaultons

TODOaddhttp404error

funcShowAllTasksFunc(whttpResponseWriterrhttpRequest)

ifrMethod==GET

context=dbGetTasks(pending)truewhenyouwantnondeletedtasks

dbisapackagewhichinteractswiththedatabase

ifmessage=

contextMessage=message

homeTemplateExecute(wcontext)

message=

else

message=Methodnotallowed

httpRedirect(wrhttpStatusFound)

ThisisfineforsimpleapplicationswhichdoesntrequiresparameterizedroutingwhatwhenyouneedthatYoucaneitherusetheexistingtoolkitsorframeworksbutsincethisbookisaboutwritingwebappsingolangwearegoingtoteachhowtohandlethisscenarioaswell

WhenthematchismadeontheHandleFuncfunctiontheURLismatchedsosupposewearewritingatodolistmanagerandwewanttodeleteatasksotheURLwedecideforthatapplicationisdelete1soweregisterthedeleteURLlikethishttpHandleFunc(deleteviewsDeleteTaskFunc)delete1thisURLmatchesclosestwiththedeleteURLthananyotherURLsointherURLpathwegettheentireURLoftherequest

httpHandleFunc(deleteviewsDeleteTaskFunc)

DeleteTaskFuncisusedtodeleteatasktrash=movetorecyclebindelete=permanentdelete

funcDeleteTaskFunc(whttpResponseWriterrhttpRequest)

ifrMethod==DELETE

id=rURLPath[len(delete)]

ifid==all

dbDeleteAll()

httpRedirect(wrhttpStatusFound)

else

iderr=strconvAtoi(id)

iferr=nil

fmtPrintln(err)

else

err=dbDeleteTask(id)

iferr=nil

message=Errordeletingtask

else

message=Taskdeleted

httpRedirect(wrhttpStatusFound)

else

message=Methodnotallowed

httpRedirect(wrhttpStatusFound)

Getintohttppackage

91

linkhttpsgithubcomthewhitetulipTasksblobmasterviewsviewsgoL170-L195

InthisabovemethodwhatwebasicallydoisinthefunctionwhichhandlesthedeleteURLwetakeitscompeleteURLwhichisdelete1thenwetakeasliceofthestringandextracteverythingwhichstartsafterthedeletewordwhichistheactualparameterinthiscaseitis1ThenweusethestrconvpackagetoconvertittoanintegeranddeletethetaskwiththattaskID

InmorecomplexscenariostoowecanusethismethodtheadvantageisthatwedonthavetouseanythirdpartytoolkitbutthenagainthirdpartytoolkitsareusefulintheirownrightyouneedtomakeadecisionwhichmethodyoudpreferNoansweristherightanswer

GocodeexecutionflowLetstakealookatthewholeexecutionflow

CallhttpHandleFunc1 CallHandleFuncofDefaultServeMux2 CallHandleofDefaultServeMux3 Addrouterrulestomap[string]muxEntryofDefaultServeMux

CallhttpListenAndServe(9090nil)1 InstantiateServer2 CallListenAndServemethodofServer3 CallnetListen(tcpaddr)tolistentoport4 Startaloopandacceptrequestsintheloopbody5 InstantiateaConnandstartagoroutineforeveryrequestgocserve()6 Readrequestdatawerr=creadRequest()7 CheckwhetherhandlerisemptyornotifitsemptythenuseDefaultServeMux8 CallServeHTTPofhandler9 ExecutecodeinDefaultServeMuxinthiscase10 ChoosehandlerbyURLandexecutecodeinthathandlerfunctionmuxhandlerServeHTTP(wr)11 HowtochoosehandlerACheckrouterrulesforthisURLBCallServeHTTPinthathandlerifthereisoneCCall

ServeHTTPofNotFoundHandlerotherwise

LinksDirectoryPrevioussectionHowGoworkswithwebNextsectionSummary

Getintohttppackage

92

35SummaryInthischapterweintroducedHTTPDNSresolutionflowandhowtobuildasimplewebserverThenwetalkedabouthowGoimplementswebserversforusbylookingatthesourcecodeofthenethttppackage

IhopethatyounowknowmuchmoreaboutwebdevelopmentandyoushouldseethatitsquiteeasyandflexibletobuildawebapplicationinGo

LinksDirectoryPrevioussectionGetintohttppackageNextchapterUserform

Summary

93

4UserformAuserformissomethingthatisverycommonlyusedwhendevelopingwebapplicationsItprovidestheabilitytocommunicatebetweenclientsandserversYoumustbeveryfamiliarwithformsifyouareawebdeveloperifyouareaCC++programmeryoumaywanttoaskwhatisauserform

AformisanareathatcontainsformelementsUserscaninputinformationintoformelementsliketextboxesdropdownlistsradiobuttonscheckboxesetcWeusetheformtagltformgttodefineforms

ltformgt

inputelements

ltformgt

GoalreadyhasmanyconvenientfunctionstodealwithuserformsYoucaneasilygetformdatainHTTPrequestsandtheyareeasytointegrateintoyourownwebapplicationsInsection41wearegoingtotalkabouthowtohandleformdatainGoAlsosinceyoucannottrustanydatacomingfromtheclientsideyoumustfirstvalidatethedatabeforeusingitWellgothroughsomeexamplesabouthowtovalidateformdatainsection42

WesaythatHTTPisstatelessHowcanweidentifythatcertainformsarefromthesameuserAndhowdowemakesurethatoneformcanonlybesubmittedonceWelllookatsomedetailsconcerningcookies(acookieisinformationthatcanbesavedontheclientsideandaddedtotherequestheaderwhentherequestissenttotheserver)inbothsections43and44

Anothercommonuse-caseforformsisuploadingfilesInsection45youwilllearnhowtodothisaswellascontrollingthefileuploadsizebeforeitbeginsuploadinginGo

LinksDirectoryPreviouschapterChapter3SummaryNextsectionProcessforminputs

HTTPForm

94

41ProcessforminputsBeforewebeginletstakealookatasimpleexampleofatypicaluserformsavedaslogingtplinyourprojectfolder

lthtmlgt

ltheadgt

lttitlegtlttitlegt

ltheadgt

ltbodygt

ltformaction=loginmethod=postgt

Usernameltinputtype=textname=usernamegt

Passwordltinputtype=passwordname=passwordgt

ltinputtype=submitvalue=Logingt

ltformgt

ltbodygt

lthtmlgt

ThisformwillsubmittologinontheserverAftertheuserclickstheloginbuttonthedatawillbesenttotheloginhandlerregisteredbytheserverrouterThenweneedtoknowwhetheritusesthePOSTmethodorGET

ThisiseasytofindoutusingthehttppackageLetsseehowtohandletheformdataontheloginpage

Processforminputs

95

packagemain

import(

fmt

htmltemplate

log

nethttp

strings

)

funcsayhelloName(whttpResponseWriterrhttpRequest)

rParseForm()ParseurlparameterspassedthenparsetheresponsepacketforthePOSTbody(requestbody)

attentionIfyoudonotcallParseFormmethodthefollowingdatacannotbeobtainedform

fmtPrintln(rForm)printinformationonserverside

fmtPrintln(pathrURLPath)

fmtPrintln(schemerURLScheme)

fmtPrintln(rForm[url_long])

forkv=rangerForm

fmtPrintln(keyk)

fmtPrintln(valstringsJoin(v))

fmtFprintf(wHelloastaxie)writedatatoresponse

funclogin(whttpResponseWriterrhttpRequest)

fmtPrintln(methodrMethod)getrequestmethod

ifrMethod==GET

t_=templateParseFiles(logingtpl)

tExecute(wnil)

else

rParseForm()

logicpartoflogin

fmtPrintln(usernamerForm[username])

fmtPrintln(passwordrForm[password])

funcmain()

httpHandleFunc(sayhelloName)settingrouterrule

httpHandleFunc(loginlogin)

err=httpListenAndServe(9090nil)settinglisteningport

iferr=nil

logFatal(ListenAndServeerr)

HereweuserMethodtogettherequestmethodanditreturnsanhttpverb-GETPOSTPUTetc

IntheloginfunctionweuserMethodtocheckwhetheritsaloginpageorloginprocessinglogicInotherwordswechecktoseewhethertheuserissimplyopeningthepageortryingtologinServeshowsthepageonlywhentherequestcomesinviatheGETmethodanditexecutestheloginlogicwhentherequestusesthePOSTmethod

Youshouldseethefollowinginterfaceafteropeninghttp1270019090logininyourbrowser

Figure41Userlogininterface

TheserverwillnotprintanythinguntilafterwetypeinausernameandpasswordbecausethehandlerdoesntparsetheformuntilwecallrParseForm()LetsaddrParseForm()beforefmtPrintln(usernamerForm[username])compileourprogramandtestitagainYouwillfindthattheinformationisprintedontheserversidenow

rFormcontainsalloftherequestargumentsforinstancethequery-stringintheURLandthedatainPOSTandPUTIfthedatahasconflictsforexampleparametersthathavethesamenametheserverwillsavethedataintoaslicewithmultiplevaluesTheGodocumentationstatesthatGowillsavethedatafromGETandPOSTrequestsindifferentplaces

Processforminputs

96

Trychangingthevalueoftheactionintheformhttp1270019090logintohttp1270019090loginusername=astaxieinthelogingtplfiletestitagainandyouwillseethatthesliceisprintedontheserverside

Figure42Serverprintsrequestdata

ThetypeofrequestFormisurlValueItsavesdatawiththeformatkey=value

v=urlValues

vSet(nameAva)

vAdd(friendJess)

vAdd(friendSarah)

vAdd(friendZoe)

vEncode()==name=Avaampfriend=Jessampfriend=Sarahampfriend=Zoe

fmtPrintln(vGet(name))

fmtPrintln(vGet(friend))

fmtPrintln(v[friend])

TipsRequestshavetheabilitytoaccessformdatausingtheFormValue()methodForexampleyoucanchangerForm[username]torFormValue(username)andGocallsrParseFormautomaticallyNoticethatitreturnsthefirstvalueifthereareargumentswiththesamenameanditreturnsanemptystringifthereisnosuchargument

LinksDirectoryPrevioussectionUserformNextsectionVerificationofinputs

Processforminputs

97

42VerificationofinputsOneofthemostimportantprinciplesinwebdevelopmentisthatyoucannottrustanythingfromclientsideuserformsYouhavetovalidateallincomingdatabeforeuseitManywebsitesareaffectedbythisproblemwhichissimpleyetcrucial

TherearetwowaysofverifyingformdatathatareincommonuseThefirstisJavaScriptvalidationonthefront-endandthesecondisservervalidationontheback-endInthissectionwearegoingtotalkaboutserversidevalidationinwebdevelopment

RequiredfieldsSometimeswerequirethatusersinputsomefieldsbuttheyfailtocompletethefieldForexampleintheprevioussectionwhenwerequiredausernameYoucanusethelenfunctiontogetthelengthofafieldinordertoensurethatusershaveenteredsomething

iflen(rForm[username][0])==0

codeforemptyfield

rFormtreatsdifferentformelementtypesdifferentlywhentheyareblankForemptytextboxestextareasandfileuploadsitreturnsanemptystringforradiobuttonsandcheckboxesitdoesntevencreatethecorrespondingitemsInsteadyouwillgeterrorsifyoutrytoaccessitThereforeitssafertouserFormGet()togetfieldvaluessinceitwillalwaysreturnemptyifthevaluedoesnotexistOntheotherhandrFormGet()canonlygetonefieldvalueatatimesoyouneedtouserFormtogetthemapofvalues

NumbersSometimesyourequirenumbersratherthanothertextforthefieldvalueForexampleletssaythatyourequiretheageofauserinintegerformonlyie50or10insteadofoldenoughoryoungmanIfwerequireapositivenumberwecanconvertthevaluetotheinttypefirstthenprocessit

getinterr=strconvAtoi(rFormGet(age))

iferr=nil

erroroccurswhenconverttonumberitmaynotanumber

checkrangeofnumber

ifgetintgt100

toobig

Anotherwaytodothisisbyusingregularexpressions

ifm_=regexpMatchString(^[0-9]+$rFormGet(age))m

returnfalse

ForhighperformancepurposesregularexpressionsarenotefficienthoweversimpleregularexpressionsareusuallyfastenoughIfyouarefamiliarwithregularexpressionsitsaveryconvenientwaytoverifydataNoticethatGousesRE2soallUTF-8charactersaresupported

Chinese

Validationofinputs

98

SometimesweneeduserstoinputtheirChinesenamesandwehavetoverifythattheyalluseChineseratherthanrandomcharactersForChineseverificationregularexpressionsaretheonlyway

ifm_=regexpMatchString(^[x4e00-x9fa5]+$rFormGet(realname))m

returnfalse

EnglishlettersSometimesweneeduserstoinputonlyEnglishlettersForexamplewerequiresomeonesEnglishnamelikeastaxieinsteadofasta谢Wecaneasilyuseregularexpressionstoperformourverification

ifm_=regexpMatchString(^[a-zA-Z]+$rFormGet(engname))m

returnfalse

E-mailaddressIfyouwanttoknowwhetherusershaveenteredvalidE-mailaddressesyoucanusethefollowingregularexpression

ifm_=regexpMatchString(`^([w_]210)(w1)([a-z]24)$`rFormGet(email))m

fmtPrintln(no)

else

fmtPrintln(yes)

DropdownlistLetssaywerequireanitemfromourdropdownlistbutinsteadwegetavaluefabricatedbyhackersHowdowepreventthisfromhappening

Supposewehavethefollowingltselectgt

ltselectname=fruitgt

ltoptionvalue=applegtappleltoptiongt

ltoptionvalue=peargtpearltoptiongt

ltoptionvalue=bananagtbananaltoptiongt

ltselectgt

Wecanusethefollowingstrategytosanitizeourinput

slice=[]stringapplepearbanana

for_v=rangeslice

ifv==rFormGet(fruit)

returntrue

returnfalse

AllthefunctionsIveshownaboveareinmyopensourceprojectforoperatingonslicesandmapshttpsgithubcomastaxiebeeku

Radiobuttons

Validationofinputs

99

Ifwewanttoknowwhethertheuserismaleorfemalewemayusearadiobuttonreturning1formaleand2forfemaleHoweversomelittlekidwhojustreadhisfirstbookonHTTPdecidestosendtoyoua3WillyourprogramthrowanexceptionAsyoucanseeweneedtousethesamemethodaswedidforourdropdownlisttomakesurethatonlyexpectedvaluesarereturnedbyourradiobutton

ltinputtype=radioname=gendervalue=1gtMale

ltinputtype=radioname=gendervalue=2gtFemale

Andweusethefollowingcodetovalidatetheinput

slice=[]int12

for_v=rangeslice

ifv==rFormGet(gender)

returntrue

returnfalse

CheckboxesSupposetherearesomecheckboxesforuserinterestsandthatyoudontwantextraneousvalueshereeitherYoucanvalidatetheseasefollows

ltinputtype=checkboxname=interestvalue=footballgtFootball

ltinputtype=checkboxname=interestvalue=basketballgtBasketball

ltinputtype=checkboxname=interestvalue=tennisgtTennis

Inthiscasethesanitizationisalittlebitdifferenttovalidatingthebuttonandcheckboxinputssinceherewegetaslicefromthecheckboxes

slice=[]stringfootballbasketballtennis

a=Slice_diff(rForm[interest]slice)

ifa==nil

returntrue

returnfalse

DateandtimeSupposeyouwantuserstoinputvaliddatesortimesGohasthetimepackageforconvertingyearmonthanddaytotheircorrespondingtimesAfterthatitseasytocheckit

t=timeDate(2009timeNovember1023000timeUTC)

fmtPrintf(GolaunchedatsntLocal())

Afteryouhavethetimeyoucanusethetimepackageformoreoperationsdependingonyourneeds

InthissectionwevediscussedsomecommonmethodsofvalidatingformdataontheserversideIhopethatyounowunderstandmoreaboutdatavalidationinGoespeciallyhowtouseregularexpressionstoyouradvantage

LinksDirectory

Validationofinputs

100

PrevioussectionProcessforminputsNextsectionCrosssitescripting

Validationofinputs

101

43CrosssitescriptingTodayswebsiteshavemuchmoredynamiccontentinordertoimproveuserexperiencewhichmeansthatwemustprovidedynamicinformationdependingoneveryindividualsbehaviorUnfortunatelydynamicwebsitesaresusceptibletomaliciousattacksknownasCrosssitescripting(knownasXSS)StaticwebsitesarenotsusceptibletoCrosssitescripting

AttackersofteninjectmaliciousscriptslikeJavaScriptVBScriptActiveXorFlashintothosewebsitesthathaveloopholesOncetheyhavesuccessfullyinjectedtheirscriptsuserinformationcanbestolenandyourwebsitecanbefloodedwithspamTheattackerscanalsochangeusersettingstowhatevertheywant

Ifyouwishtopreventthiskindofattackyoushouldcombinethefollowingtwoapproaches

ValidationofalldatafromuserswhichwetalkedaboutintheprevioussectionCarefullyhandledatathatwillbesenttoclientsinordertopreventanyinjectedscriptsfromrunningonbrowsers

SohowcanwedothesetwothingsinGoFortunatelythehtmltemplatepackagehassomeusefulfunctionstoescapedataasfollows

funcHTMLEscape(wioWriterb[]byte)escapesbtowfuncHTMLEscapeString(sstring)stringreturnsastringafterescapingfromsfuncHTMLEscaper(argsinterface)stringreturnsastringafterescapingfrommultiplearguments

Letschangetheexampleinsection41

fmtPrintln(usernametemplateHTMLEscapeString(rFormGet(username)))printatserverside

fmtPrintln(passwordtemplateHTMLEscapeString(rFormGet(password)))

templateHTMLEscape(w[]byte(rFormGet(username)))respondedtoclients

Ifsomeonetriestoinputtheusernameasltscriptgtalert()ltscriptgtwewillseethefollowingcontentinthebrowser

Figure43JavaScriptafterescaped

FunctionsinthehtmltemplatepackagehelpyoutoescapeallHTMLtagsWhatifyoujustwanttoprintltscriptgtalert()ltscriptgttobrowsersYoushouldusetexttemplateinstead

importtexttemplate

terr=templateNew(foo)Parse(`defineTHelloend`)

err=tExecuteTemplate(outTltscriptgtalert(youhavebeenpwned)ltscriptgt)

Output

Helloltscriptgtalert(youhavebeenpwned)ltscriptgt

OryoucanusethetemplateHTMLtypeVariablecontentwillnotbeescapedifitstypeistemplateHTML

importhtmltemplate

terr=templateNew(foo)Parse(`defineTHelloend`)

err=tExecuteTemplate(outTtemplateHTML(ltscriptgtalert(youhavebeenpwned)ltscriptgt))

Output

Helloltscriptgtalert(youhavebeenpwned)ltscriptgt

Crosssitescripting

102

Onemoreexampleofescaping

importhtmltemplate

terr=templateNew(foo)Parse(`defineTHelloend`)

err=tExecuteTemplate(outTltscriptgtalert(youhavebeenpwned)ltscriptgt)

Output

Helloampltscriptampgtalert(amp39youhavebeenpwnedamp39)ampltscriptampgt

LinksDirectoryPrevioussectionVerificationofinputsNextsectionDuplicatesubmissions

Crosssitescripting

103

44DuplicatesubmissionsIdontknowifyouveeverseensomeblogsorBBSthathavemorethanonepostthatareexactlythesamebutIcantellyouthatitsbecauseuserssubmittedduplicatepostformsTherearemanythingsthatcancauseduplicatesubmissionssometimesusersjustdoubleclickthesubmitbuttonortheywanttomodifysomecontentafterpostingandpressthebackbuttonInsomecasesitisbytheintentionalactionsofmalicioususersItseasytoseehowduplicatesubmissionscanleadtomanyproblemsThuswehavetouseeffectivemeanstopreventit

ThesolutionistoaddahiddenfieldwithauniquetokentoyourformandtoalwayscheckthistokenbeforeprocessingtheincomingdataAlsoifyouareusingAjaxtosubmitaformuseJavaScripttodisablethesubmitbuttononcetheformhasbeensubmitted

Letsimprovetheexamplefromsection42

ltinputtype=checkboxname=interestvalue=footballgtFootball

ltinputtype=checkboxname=interestvalue=basketballgtBasketball

ltinputtype=checkboxname=interestvalue=tennisgtTennis

Usernameltinputtype=textname=usernamegt

Passwordltinputtype=passwordname=passwordgt

ltinputtype=hiddenname=tokenvalue=gt

ltinputtype=submitvalue=Logingt

WeuseanMD5hash(timestamp)togeneratethetokenandaddedittobothahiddenfieldontheclientsideformandasessioncookieontheserverside(Chapter6)Wecanthenusethistokentocheckwhetherornotthisformwassubmitted

funclogin(whttpResponseWriterrhttpRequest)

fmtPrintln(methodrMethod)getrequestmethod

ifrMethod==GET

crutime=timeNow()Unix()

h=md5New()

ioWriteString(hstrconvFormatInt(crutime10))

token=fmtSprintf(xhSum(nil))

t_=templateParseFiles(logingtpl)

tExecute(wtoken)

else

loginrequest

rParseForm()

token=rFormGet(token)

iftoken=

checktokenvalidity

else

giveerrorifnotoken

fmtPrintln(usernamelengthlen(rForm[username][0]))

fmtPrintln(usernametemplateHTMLEscapeString(rFormGet(username)))printinserverside

fmtPrintln(passwordtemplateHTMLEscapeString(rFormGet(password)))

templateHTMLEscape(w[]byte(rFormGet(username)))respondtoclient

Figure44Thecontentinbrowserafteraddingatoken

YoucanrefreshthispageandyouwillseeadifferenttokeneverytimeThisensuresthateveryformisunique

FornowyoucanpreventmanyduplicatesubmissionattacksbyaddingtokenstoyourformsbutitcannotpreventalldeceptiveattacksofthistypeThereismuchmoreworkthatneedstobedone

Duplicatesubmissions

104

LinksDirectoryPrevioussectionCrosssitescriptingNextsectionFileupload

Duplicatesubmissions

105

45FileuploadSupposeyouhaveawebsitelikeInstagramandyouwantuserstouploadtheirbeautifulphotosHowwouldyouimplementthatfunctionality

YouhavetoaddpropertyenctypetotheformthatyouwanttouseforuploadingphotosTherearethreepossiblevaluesforthisproperty

applicationx-www-form-urlencodedTranscodeallcharactersbeforeuploading(default)

multipartform-dataNotranscodingYoumustusethisvaluewhenyourformhasfileuploadcontrols

textplainConvertspacesto+butnotranscodingforspecialcharacters

ThereforetheHTMLcontentofafileuploadformshouldlooklikethis

lthtmlgt

ltheadgt

lttitlegtUploadfilelttitlegt

ltheadgt

ltbodygt

ltformenctype=multipartform-dataaction=http1270019090uploadmethod=postgt

ltinputtype=filename=uploadfilegt

ltinputtype=hiddenname=tokenvalue=gt

ltinputtype=submitvalue=uploadgt

ltformgt

ltbodygt

lthtmlgt

Weneedtoaddafunctionontheserversidetohandlethisform

httpHandleFunc(uploadupload)

uploadlogic

funcupload(whttpResponseWriterrhttpRequest)

fmtPrintln(methodrMethod)

ifrMethod==GET

crutime=timeNow()Unix()

h=md5New()

ioWriteString(hstrconvFormatInt(crutime10))

token=fmtSprintf(xhSum(nil))

t_=templateParseFiles(uploadgtpl)

tExecute(wtoken)

else

rParseMultipartForm(32ltlt20)

filehandlererr=rFormFile(uploadfile)

iferr=nil

fmtPrintln(err)

return

deferfileClose()

fmtFprintf(wvhandlerHeader)

ferr=osOpenFile(test+handlerFilenameosO_WRONLY|osO_CREATE0666)

iferr=nil

fmtPrintln(err)

return

deferfClose()

ioCopy(ffile)

Fileupload

106

AsyoucanseeweneedtocallrParseMultipartFormforuploadingfilesThefunctionParseMultipartFormtakesthemaxMemoryargumentAfteryoucallParseMultipartFormthefilewillbesavedintheservermemorywithmaxMemorysizeIfthefilesizeislargerthanmaxMemorytherestofthedatawillbesavedinasystemtemporaryfileYoucanuserFormFiletogetthefilehandleanduseioCopytosavetoyourfilesystem

YoudontneedtocallrParseFormwhenyouaccessothernon-filefieldsintheformbecauseGowillcallitwhenitsnecessaryAlsocallingParseMultipartFormonceisenough-multiplecallsmakenodifference

Weusethreestepsforuploadingfilesasfollows

1 Addenctype=multipartform-datatoyourform2 CallrParseMultipartFormontheserversidetosavethefileeithertomemoryortoatemporaryfile3 CallrFormFiletogetthefilehandleandsavetothefilesystem

ThefilehandleristhemultipartFileHeaderItusesthefollowingstruct

typeFileHeaderstruct

Filenamestring

HeadertextprotoMIMEHeader

containsfilteredorunexportedfields

Figure45Printinformationonserverafterreceivingfile

ClientsuploadfilesIshowedanexampleofusingaformtoauploadafileWecanimpersonateaclientformtouploadfilesinGoaswell

Fileupload

107

packagemain

import(

bytes

fmt

io

ioioutil

mimemultipart

nethttp

os

)

funcpostFile(filenamestringtargetUrlstring)error

bodyBuf=ampbytesBuffer

bodyWriter=multipartNewWriter(bodyBuf)

thisstepisveryimportant

fileWritererr=bodyWriterCreateFormFile(uploadfilefilename)

iferr=nil

fmtPrintln(errorwritingtobuffer)

returnerr

openfilehandle

fherr=osOpen(filename)

iferr=nil

fmtPrintln(erroropeningfile)

returnerr

deferfhClose()

iocopy

_err=ioCopy(fileWriterfh)

iferr=nil

returnerr

contentType=bodyWriterFormDataContentType()

bodyWriterClose()

resperr=httpPost(targetUrlcontentTypebodyBuf)

iferr=nil

returnerr

deferrespBodyClose()

resp_bodyerr=ioutilReadAll(respBody)

iferr=nil

returnerr

fmtPrintln(respStatus)

fmtPrintln(string(resp_body))

returnnil

sampleusage

funcmain()

target_url=httplocalhost9090upload

filename=astaxiepdf

postFile(filenametarget_url)

TheaboveexampleshowsyouhowtouseaclienttouploadfilesItusesmultipartWritetowritefilesintocacheandsendsthemtotheserverthroughthePOSTmethod

IfyouhaveotherfieldsthatneedtowriteintodatalikeusernamecallmultipartWriteFieldasneeded

Links

Fileupload

108

DirectoryPrevioussectionDuplicatesubmissionsNextsectionSummary

Fileupload

109

46SummaryInthischapterwemainlylearnedhowtoprocessformdatainGothroughseveralexampleslikelogginginusersanduploadingfilesWealsoemphasizedthatvalidatinguserdataisextremelyimportantforwebsitesecurityandweusedonesectiontotalkabouthowtofilterdatawithregularexpressions

Ihopethatyounowknowmoreaboutthecommunicationprocessbetweenclientandserver

LinksDirectoryPrevioussectionFileuploadNextchapterDatabase

Summary

110

5DatabaseForwebdevelopersthedatabaseisatthecoreofwebdevelopmentYoucansavealmostanythingintoadatabaseandqueryorupdatedatainsideitlikeuserinformationproductsornewsarticles

GodoesntprovideanydatabasedriversbutitdoeshaveadriverinterfacedefinedinthedatabasesqlpackagePeoplecandevelopdatabasedriversbasedonthatinterfaceInsection51wearegoingtotalkaboutdatabasedriverinterfacedesigninGoInsections52to54IwillintroducesomeSQLdatabasedriverstoyouInsection55IwillpresenttheORM thatIhavedevelopedwhichisbasedonthedatabasesqlinterfacestandardItiscompatiblewithmostdriversthathaveimplementedthedatabasesqlinterfaceanditmakesiteasytoaccessdatabasesidiomaticallyinGo

NoSQLhasbeenahottopicinrecentyearsMorewebsitesaredecidingtouseNoSQLdatabasesastheirmaindatabaseinsteadofjustforthepurposeofcachingIwillintroduceyoutotwoNoSQLdatabaseswhichareMongoDBandRedisinsection56

LinksDirectoryPreviousChapterChapter4SummaryNextsectiondatabasesqlinterface

Database

111

51databasesqlinterfaceGodoesntprovideanyofficialdatabasedriversunlikeotherlanguageslikePHPwhichdoHoweveritdoeshavesomedatabasedriverinterfacestandardsfordeveloperstodevelopdatabasedriverswithTheadvantageisthatifyourcodeisdevelopedaccordingtotheseinterfacestandardsyouwillnotneedtochangeanycodeifyourdatabasechangesLetsseewhatthesedatabaseinterfacestandardsare

sqlRegisterThisfunctionisinthedatabasesqlpackageforregisteringdatabasedriverswhenyouusethird-partydatabasedriversAlloftheseshouldcalltheRegister(namestringdriverdriverDriver)functionininit()inordertoregisterthemselves

Letstakealookatthecorrespondingmymysqlandsqlite3drivercode

httpsgithubcommattngo-sqlite3driver

funcinit()

sqlRegister(sqlite3ampSQLiteDriver)

httpsgithubcommikespookmymysqldriver

Driverautomaticallyregisteredindatabasesql

vard=Driverprototcpraddr1270013306

funcinit()

Register(SETNAMESutf8)

sqlRegister(mymysqlampd)

Weseethatallthird-partydatabasedriversimplementthisfunctiontoregisterthemselvesandGousesamaptosaveuserdriversinsideofdatabasesql

vardrivers=make(map[string]driverDriver)

drivers[name]=driver

Thereforethisregistrationfunctioncanregisterasmanydriversasyoumayrequireeachwithdifferentnames

Wealwaysseethefollowingcodewhenweusethird-partydrivers

import(

databasesql

_githubcommattngo-sqlite3

)

Heretheunderscore(alsoknownasablank)_canbequiteconfusingformanybeginnersbutthisisagreatfeatureinGoWealreadyknowthatthisunderscoreidentifierisusedfordiscardingvaluesfromfunctionreturnsandalsothatyoumustuseallpackagesthatyouveimportedinyourcodeinGoSowhentheblankisusedwithimportitmeansthatyouneedtoexecutetheinit()functionofthatpackagewithoutdirectlyusingitwhichisaperfectfitfortheuse-caseofregisteringdatabasedrivers

driverDriverDriverisaninterfacecontaininganOpen(namestring)methodthatreturnsaConninterface

databasesqlinterface

112

typeDriverinterface

Open(namestring)(Connerror)

Thisisaone-timeConnwhichmeansitcanonlybeusedoncepergoroutineThefollowingcodewillcauseerrorstooccur

gogoroutineA(Conn)query

gogoroutineB(Conn)insert

BecauseGohasnoideawhichgoroutinedoeswhichoperationthequeryoperationmaygettheresultoftheinsertoperationandvice-versa

Allthird-partydriversshouldhavethisfunctiontoparsethenameofConnandreturnthecorrectresults

driverConnThisisadatabaseconnectioninterfacewithsomemethodsandasivesaidabovethesameConncanonlybeusedoncepergoroutine

typeConninterface

Prepare(querystring)(Stmterror)

Close()error

Begin()(Txerror)

PreparereturnsthepreparestatusofcorrespondingSQLcommandsforqueryinganddeletingetcCloseclosesthecurrentconnectionandcleansresourcesMostthird-partydriversimplementsomekindofconnectionpoolsoyoudontneedtocacheconnectionswhichcancauseunexpectederrorsBeginreturnsaTxthatrepresentsatransactionhandleYoucanuseitforqueryingupdatingrollingbacktransactionsetc

driverStmtThisisareadystatusthatcorrespondswithConnsoitcanonlybeusedoncepergoroutine(asisthecasewithConn)

typeStmtinterface

Close()error

NumInput()int

Exec(args[]Value)(Resulterror)

Query(args[]Value)(Rowserror)

CloseclosesthecurrentconnectionbutstillreturnsrowdataifitisexecutingaqueryoperationNumInputreturnsthenumberofobligateargumentsDatabasedriversshouldchecktheircallersargumentswhentheresultisgreaterthan0anditreturns-1whendatabasedriversdontknowanyobligateargumentExecexecutestheupdateinsertSQLcommandspreparedinPreparereturnsResultQueryexecutestheselectSQLcommandpreparedinPreparereturnsrowdata

driverTx

databasesqlinterface

113

Generallytransactionhandlesonlyhavesubmitorrollbackmethodsanddatabasedriversonlyneedtoimplementthesetwomethods

typeTxinterface

Commit()error

Rollback()error

driverExecerThisisanoptionalinterface

typeExecerinterface

Exec(querystringargs[]Value)(Resulterror)

IfthedriverdoesntimplementthisinterfacewhenyoucallDBExecitwillautomaticallycallPreparethenreturnStmtAfterthatitexecutestheExecmethodofStmtthenclosesStmt

driverResultThisistheinterfaceforresultsofupdateinsertoperations

typeResultinterface

LastInsertId()(int64error)

RowsAffected()(int64error)

LastInsertIdreturnsauto-incrementIdnumberafteradatabaseinsertoperationRowsAffectedreturnsrowsthatwereaffectedbyqueryoperations

driverRowsThisistheinterfacefortheresultofaqueryoperation

typeRowsinterface

Columns()[]string

Close()error

Next(dest[]Value)error

ColumnsreturnsfieldinformationofdatabasetablesTheslicehasaone-to-onecorrespondencewithSQLqueryfieldsonlyanddoesnotreturnallfieldsofthatdatabasetableCloseclosesRowsiteratorNextreturnsnextdataandassignstodestconvertingallstringsintobytearraysandgetsioEOFerrorifnomoredataisavailable

driverRowsAffectedThisisanaliasofint64butitimplementstheResultinterface

databasesqlinterface

114

typeRowsAffectedint64

func(RowsAffected)LastInsertId()(int64error)

func(vRowsAffected)RowsAffected()(int64error)

driverValueThisisanemptyinterfacethatcancontainanykindofdata

typeValueinterface

TheValuemustbesomethingthatdriverscanoperateonornilsoitshouldbeoneofthefollowingtypes

int64

float64

bool

[]byte

string[]ExceptRowsNextwhichcannotreturnstring

timeTime

driverValueConverterThisdefinesaninterfaceforconvertingnormalvaluestodriverValue

typeValueConverterinterface

ConvertValue(vinterface)(Valueerror)

Thisinterfaceiscommonlyusedindatabasedriversandhasmanyusefulfeatures

ConvertsdriverValuetoacorrespondingdatabasefieldtypeforexampleconvertsint64touint16ConvertsdatabasequeryresultstodriverValueConvertsdriverValuetoauserdefinedvalueinthescanfunction

driverValuerThisdefinesaninterfaceforreturningdriverValue

typeValuerinterface

Value()(Valueerror)

ManytypesimplementthisinterfaceforconversionbetweendriverValueanditself

AtthispointyoushouldknowabitaboutdevelopingdatabasedriversinGoOnceyoucanimplementinterfacesforoperationslikeadddeleteupdateetcthereareonlyafewproblemsleftrelatedtocommunicatingwithspecificdatabases

databasesqldatabasesqldefinesevenmorehigh-levelmethodsontopofdatabasesqldriverformoreconvenientdatabaseoperationsanditsuggeststhatyouimplementaconnectionpool

databasesqlinterface

115

typeDBstruct

driverdriverDriver

dsnstring

musyncMutexprotectsfreeConnandclosed

freeConn[]driverConn

closedbool

AsyoucanseetheOpenfunctionreturnsaDBthathasafreeConnandthisisasimpleconnectionpoolItsimplementationisverysimpleanduglyItusesdeferdbputConn(cierr)intheDbpreparefunctiontoputaconnectionintotheconnectionpoolEverytimeyoucalltheConnfunctionitchecksthelengthoffreeConnIfitsgreaterthan0thatmeansthereisareusableconnectionanditdirectlyreturnstoyouOtherwiseitcreatesanewconnectionandreturns

LinksDirectoryPrevioussectionDatabaseNextsectionMySQL

databasesqlinterface

116

52MySQLTheLAMPstackhasbeenverypopularontheinternetinrecentyearsandtheMinLAMPstandforMySQLMySQLisfamousbecauseitsopensourceandeasytouseAssuchithasbecomethede-factodatabaseintheback-endsofmanywebsites

MySQLdriversThereareacoupleofdriversthatsupportMySQLinGoSomeofthemimplementthedatabasesqlinterfaceandothersusetheirowninterfacestandards

httpsgithubcomgo-sql-drivermysqlsupportsdatabasesqlwritteninpureGohttpsgithubcomziutekmymysqlsupportsdatabasesqlanduserdefinedinterfaceswritteninpureGo

Illusethefirstdriverinthefollowingexamples(Iusethisoneinmypersonalprojectstoo)andIalsorecommendthatyouuseitforthefollowingreasons

ItsanewdatabasedriverandsupportsmorefeaturesItfullysupportsdatabasesqlinterfacestandardsSupportskeep-alivelongconnectionswiththread-safety

SamplesInthefollowingsectionsIllusethesamedatabasetablestructurefordifferentdatabasesthencreateSQLasfollows

CREATETABLE`userinfo`(

`uid`INT(10)NOTNULLAUTO_INCREMENT

`username`VARCHAR(64)NULLDEFAULTNULL

`departname`VARCHAR(64)NULLDEFAULTNULL

`created`DATENULLDEFAULTNULL

PRIMARYKEY(`uid`)

)

Thefollowingexampleshowshowtooperateonadatabasebasedonthedatabasesqlinterfacestandards

packagemain

import(

_githubcomgo-sql-drivermysql

databasesql

fmt

)

funcmain()

dberr=sqlOpen(mysqlastaxieastaxietestcharset=utf8)

checkErr(err)

insert

stmterr=dbPrepare(INSERTuserinfoSETusername=departname=created=)

checkErr(err)

reserr=stmtExec(astaxie研发部门2012-12-09)

checkErr(err)

iderr=resLastInsertId()

checkErr(err)

fmtPrintln(id)

update

HowtouseMySQL

117

stmterr=dbPrepare(updateuserinfosetusername=whereuid=)

checkErr(err)

reserr=stmtExec(astaxieupdateid)

checkErr(err)

affecterr=resRowsAffected()

checkErr(err)

fmtPrintln(affect)

query

rowserr=dbQuery(SELECTFROMuserinfo)

checkErr(err)

forrowsNext()

varuidint

varusernamestring

vardepartmentstring

varcreatedstring

err=rowsScan(ampuidampusernameampdepartmentampcreated)

checkErr(err)

fmtPrintln(uid)

fmtPrintln(username)

fmtPrintln(department)

fmtPrintln(created)

delete

stmterr=dbPrepare(deletefromuserinfowhereuid=)

checkErr(err)

reserr=stmtExec(id)

checkErr(err)

affecterr=resRowsAffected()

checkErr(err)

fmtPrintln(affect)

dbClose()

funccheckErr(errerror)

iferr=nil

panic(err)

Letmeexplainafewoftheimportantfunctionshere

sqlOpen()opensaregistereddatabasedriverTheGo-MySQL-DriverregisteredthemysqldriverhereThesecondargumentistheDSN(DataSourceName)thatdefinesinformationpertainingtothedatabaseconnectionItsupportsfollowingformats

userunix(pathtosocket)dbnamecharset=utf8

userpasswordtcp(localhost5555)dbnamecharset=utf8

userpassworddbname

userpasswordtcp([deadbeefcafe]80)dbname

dbPrepare()returnsaSQLoperationthatisgoingtobeexecutedItalsoreturnstheexecutionstatusafterexecutingSQL

dbQuery()executesSQLandreturnsaRowsresultstmtExec()executesSQLthathasbeenpreparedandstoredinStmt

Notethatweusetheformat=topassargumentsThisisnecessaryforpreventingSQLinjectionattacks

HowtouseMySQL

118

LinksDirectoryPrevioussectiondatabasesqlinterfaceNextsectionSQLite

HowtouseMySQL

119

53SQLiteSQLiteisanopensourceembeddedrelationaldatabaseIthasaself-containedzero-configurationandtransaction-supporteddatabaseengineItscharacteristicsarehighlyportableeasytousecompactefficientandreliableInmostofcasesyouonlyneedabinaryfileofSQLitetocreateconnectandoperateadatabaseIfyouarelookingforanembeddeddatabasesolutionSQLiteisworthconsideringYoucansaySQLiteistheopensourceversionofAccess

SQLitedriversTherearemanydatabasedriversforSQLiteinGobutmanyofthemdonotsupportthedatabasesqlinterfacestandards

httpsgithubcommattngo-sqlite3supportsdatabasesqlbasedoncgohttpsgithubcomfeyeleanorgosqlite3doesntsupportdatabasesqlbasedoncgohttpsgithubcomphfgo-sqlite3doesntsupportdatabasesqlbasedoncgo

ThefirstdriveristheonlyonethatsupportsthedatabasesqlinterfacestandardinitsSQLitedriversoIusethisinmyprojects-itwillmakeiteasytomigratemycodeinthefutureifIneedto

SamplesWecreatethefollowingSQL

CREATETABLE`userinfo`(

`uid`INTEGERPRIMARYKEYAUTOINCREMENT

`username`VARCHAR(64)NULL

`departname`VARCHAR(64)NULL

`created`DATENULL

)

Anexample

packagemain

import(

databasesql

fmt

time

_githubcommattngo-sqlite3

)

funcmain()

dberr=sqlOpen(sqlite3foodb)

checkErr(err)

insert

stmterr=dbPrepare(INSERTINTOuserinfo(usernamedepartnamecreated)values())

checkErr(err)

reserr=stmtExec(astaxie研发部门2012-12-09)

checkErr(err)

iderr=resLastInsertId()

checkErr(err)

fmtPrintln(id)

update

stmterr=dbPrepare(updateuserinfosetusername=whereuid=)

checkErr(err)

HowtouseSQLite

120

reserr=stmtExec(astaxieupdateid)

checkErr(err)

affecterr=resRowsAffected()

checkErr(err)

fmtPrintln(affect)

query

rowserr=dbQuery(SELECTFROMuserinfo)

checkErr(err)

varuidint

varusernamestring

vardepartmentstring

varcreatedtimeTime

forrowsNext()

err=rowsScan(ampuidampusernameampdepartmentampcreated)

checkErr(err)

fmtPrintln(uid)

fmtPrintln(username)

fmtPrintln(department)

fmtPrintln(created)

rowsClose()goodhabittoclose

delete

stmterr=dbPrepare(deletefromuserinfowhereuid=)

checkErr(err)

reserr=stmtExec(id)

checkErr(err)

affecterr=resRowsAffected()

checkErr(err)

fmtPrintln(affect)

dbClose()

funccheckErr(errerror)

iferr=nil

panic(err)

YoumayhavenoticedthatthecodeisalmostthesameasintheprevioussectionandthatweonlychangedthenameoftheregistereddriverandcalledsqlOpentoconnecttoSQLiteinadifferentway

Notethatsometimesyoucantusetheforstatementbecauseyoudonthavemorethanonerowthenyoucanusetheifstatement

ifrowsNext()

err=rowsScan(ampuidampusernameampdepartmentampcreated)

checkErr(err)

fmtPrintln(uid)

fmtPrintln(username)

fmtPrintln(department)

fmtPrintln(created)

AlsoyouhavetodoarowsNext()withoutusingthatyoucantfetchdataintheScanfunction

Transactions

HowtouseSQLite

121

TheaboveexampleshowshowyoufetchdatafromthedatabasebutwhenyouwanttowriteawebapplicationthenitwillnotonlybenecessarytofetchdatafromthedbbutitwillalsoberequiredtowritedataintoitForthatpurposeyoushouldusetransactionsbecauseforvariousreasonssuchashavingmultiplegoroutineswhichaccessthedatabasethedatabasemightgetlockedThisisundesirableinyourwebapplicationandtheuseoftransactionsiseffectiveinensuringyourdatabaseactivitieseitherpassorfailcompletelydependingoncircumstancesItisclearthatusingtransactionscanpreventalotofthingsfromgoingwrongwiththewebapp

trashSQLerr=databasePrepare(updatetasksetis_deleted=Ylast_modified_at=datetime()whereid=)

iferr=nil

fmtPrintln(err)

txerr=databaseBegin()

iferr=nil

fmtPrintln(err)

_err=txStmt(trashSQL)Exec(id)

iferr=nil

fmtPrintln(doingrollback)

txRollback()

else

txCommit()

Asitisclearfromtheaboveblockofcodeyoufirstprepareastatementafterwhichyouexecuteitdependingontheoutputofthatexecutionthenyoueitherrollitbackorcommitit

AsafinalnoteonthissectionthereisausefulSQLitemanagementtoolavailablehttpsqlitebrowserorg

LinksDirectoryPrevioussectionMySQLNextsectionPostgreSQL

HowtouseSQLite

122

54PostgreSQLPostgreSQLisanobject-relationaldatabasemanagementsystemavailableformanyplatformsincludingLinuxFreeBSDSolarisMicrosoftWindowsandMacOSXItisreleasedunderanMIT-stylelicenseandisthusfreeandopensourcesoftwareItslargerthanMySQLbecauseitsdesignedforenterpriseusageasanalternativetoOraclePostgresqlisagoodchoiceforenterprisetypeprojects

PostgreSQLdriversTherearemanydatabasedriversavailableforPostgreSQLHerearethreeexamplesofthem

httpsgithubcomlibpqsupportsdatabasesqlwritteninpureGohttpsgithubcomjbarhamgopgsqldriversupportsdatabasesqlwritteninpureGohttpsgithubcomlxngo-pgsqlsupportsdatabasesqlwritteninpureGo

Iwillusethefirstoneintheexamplesthatfollow

SamplesWecreatethefollowingSQL

CREATETABLEuserinfo

(

uidserialNOTNULL

usernamecharactervarying(100)NOTNULL

departnamecharactervarying(500)NOTNULL

Createddate

CONSTRAINTuserinfo_pkeyPRIMARYKEY(uid)

)

WITH(OIDS=FALSE)

Anexample

packagemain

import(

databasesql

fmt

_githubcomlibpq

time

)

const(

DB_USER=postgres

DB_PASSWORD=postgres

DB_NAME=test

)

funcmain()

dbinfo=fmtSprintf(user=spassword=sdbname=ssslmode=disable

DB_USERDB_PASSWORDDB_NAME)

dberr=sqlOpen(postgresdbinfo)

checkErr(err)

deferdbClose()

fmtPrintln(Insertingvalues)

varlastInsertIdint

err=dbQueryRow(INSERTINTOuserinfo(usernamedepartnamecreated)VALUES($1$2$3)returninguidastax

ie研发部门2012-12-09)Scan(amplastInsertId)

HowtousePostgreSQL

123

checkErr(err)

fmtPrintln(lastinsertedid=lastInsertId)

fmtPrintln(Updating)

stmterr=dbPrepare(updateuserinfosetusername=$1whereuid=$2)

checkErr(err)

reserr=stmtExec(astaxieupdatelastInsertId)

checkErr(err)

affecterr=resRowsAffected()

checkErr(err)

fmtPrintln(affectrowschanged)

fmtPrintln(Querying)

rowserr=dbQuery(SELECTFROMuserinfo)

checkErr(err)

forrowsNext()

varuidint

varusernamestring

vardepartmentstring

varcreatedtimeTime

err=rowsScan(ampuidampusernameampdepartmentampcreated)

checkErr(err)

fmtPrintln(uid|username|department|created)

fmtPrintf(3v|8v|6v|6vnuidusernamedepartmentcreated)

fmtPrintln(Deleting)

stmterr=dbPrepare(deletefromuserinfowhereuid=$1)

checkErr(err)

reserr=stmtExec(lastInsertId)

checkErr(err)

affecterr=resRowsAffected()

checkErr(err)

fmtPrintln(affectrowschanged)

funccheckErr(errerror)

iferr=nil

panic(err)

NotethatPostgreSQLusesthe$1$2formatinsteadofthethatMySQLusesandithasadifferentDSNformatinsqlOpenAnotherthingisthatthePostgreSQLdriverdoesnotsupportsqlResultLastInsertId()Soinsteadofthis

stmterr=dbPrepare(INSERTINTOuserinfo(usernamedepartnamecreated)VALUES($1$2$3))

reserr=stmtExec(astaxie研发部门2012-12-09)

fmtPrintln(resLastInsertId())

usedbQueryRow()andScan()togetthevalueforthelastinsertedid

err=dbQueryRow(INSERTINTOTABLE_NAMEvalues($1)returninguidVALUE1)Scan(amplastInsertId)

fmtPrintln(lastInsertId)

LinksDirectoryPrevioussectionSQLite

HowtousePostgreSQL

124

NextsectionDevelopORMbasedonbeedb

HowtousePostgreSQL

125

55DevelopORMbasedonbeedb(Projectbeedbisnolongermaintainedbutthecodesstillthere)

beedbisanORM(object-relationalmapper)developedinGobymeItusesidiomaticGotooperateondatabasesimplementingstruct-to-databasemappingandactsasalightweightGoORMframeworkThepurposeofdevelopingthisORMisnotonlytohelppeoplelearnhowtowriteanORMbutalsotofindagoodbalancebetweenfunctionalityandperformancewhenitcomestodatapersistence

beedbisanopensourceprojectthatsupportsbasicORMfunctionalitybutdoesntsupportassociationqueries

BecausebeedbsupportsdatabasesqlinterfacestandardsanydriverthatimplementsthisinterfacecanbeusedwithbeedbIvetestedthefollowingdrivers

Mysqlgithubgo-mysql-drivermysql

PostgreSQLgithubcomlibpq

SQLitegithubcommattngo-sqlite3

Mysqlgithubcomziutekmymysqlgodrv

MSADODBgithubcommattngo-adodb

Oraclegithubcommattngo-oci8

ODBCbitbucketorgmiquellamgodbc

InstallationYoucanusegogettoinstallbeedblocally

gogetgithubcomastaxiebeedb

InitializationFirstyouhavetoimportallthenecessarypackages

import(

databasesql

githubcomastaxiebeedb

_githubcomziutekmymysqlgodrv

)

Thenyouneedtoopenadatabaseconnectionandcreateabeedbobject(MySQLinthisexample)

dberr=sqlOpen(mymysqltestxiemengjun123456)

iferr=nil

panic(err)

orm=beedbNew(db)

beedbNew()actuallyhastwoargumentsThefirstisthedatabaseobjectandthesecondisforindicatingwhichdatabaseengineyoureusingIfyoureusingMySQLSQLiteyoucanjustskipthesecondargument

OtherwisethisargumentmustbesuppliedForinstanceinthecaseofSQLServer

HowtousebeedbORM

126

orm=beedbNew(dbmssql)

PostgreSQL

orm=beedbNew(dbpg)

beedbsupportsdebuggingUsethefollowingcodetoenableit

beedbOnDebug=true

NextwehaveastructfortheUserinfodatabasetablethatweusedinprevioussections

typeUserinfostruct

Uidint`PK`iftheprimarykeyisnotidyouneedtoaddtag`PK`foryourcustomizedprimarykey

Usernamestring

Departnamestring

CreatedtimeTime

Beawarethatbeedbauto-convertscamelcasenamestolowersnakecaseForexampleifwehaveUserInfoasthestructnamebeedbwillconvertittouser_infointhedatabaseThesameruleappliestostructfieldnames

InsertdataThefollowingexampleshowsyouhowtousebeedbtosaveastructinsteadofusingrawSQLcommandsWeusethebeedbSavemethodtoapplythechange

varsaveoneUserinfo

saveoneUsername=TestAddUser

saveoneDepartname=TestAddDepartname

saveoneCreated=timeNow()

ormSave(ampsaveone)

YoucanchecksaveoneUidaftertherecordisinserteditsvalueisaself-incrementedIDwhichtheSavemethodtakescareofforyou

beedbprovidesanotherwayofinsertingdatathisisviaGosmaptype

add=make(map[string]interface)

add[username]=astaxie

add[departname]=clouddevelop

add[created]=2012-12-02

ormSetTable(userinfo)Insert(add)

Insertmultipledata

addslice=make([]map[string]interface10)

add=make(map[string]interface)

add2=make(map[string]interface)

add[username]=astaxie

add[departname]=clouddevelop

add[created]=2012-12-02

add2[username]=astaxie2

add2[departname]=clouddevelop2

add2[created]=2012-12-02

addslice=append(addsliceaddadd2)

ormSetTable(userinfo)InsertBatch(addslice)

HowtousebeedbORM

127

ThemethodshownaboveissimilartoachainedquerywhichyoushouldbefamiliarwithifyouveeverusedjqueryItreturnstheoriginalORMobjectaftercallsthencontinuesdoingotherjobs

ThemethodSetTabletellstheORMwewanttoinsertourdataintotheuserinfotable

UpdatedataLetscontinueworkingwiththeaboveexampletoseehowtoupdatedataNowthatwehavetheprimarykeyofsaveone(Uid)beedbexecutesanupdateoperationinsteadofinsertinganewrecord

saveoneUsername=UpdateUsername

saveoneDepartname=UpdateDepartname

saveoneCreated=timeNow()

ormSave(ampsaveone)update

Likebeforeyoucanalsousemapforupdatingdata

t=make(map[string]interface)

t[username]=astaxie

ormSetTable(userinfo)SetPK(uid)Where(2)Update(t)

Letmeexplainsomeofthemethodsusedabove

SetPK()tellstheORMthatuidistheprimarykeyrecordsintheuserinfotableWhere()setsconditionsandsupportsmultipleargumentsIfthefirstargumentisanintegeritsashortformforWhere(ltprimarykeygt=ltvaluegt)Update()methodacceptsamapandupdatesthedatabase

QuerydataThebeedbqueryinterfaceisveryflexibleLetsseesomeexamples

Example1querybyprimarykey

varuserUserinfo

Whereacceptstwoargumentssupportsintegers

ormWhere(uid=27)Find(ampuser)

Example2

varuser2Userinfo

ormWhere(3)Find(ampuser2)shortformthatomitsprimarykey

Example3otherqueryconditions

varuser3Userinfo

Wheretwoargumentsareacceptedwithsupportforchartype

ormWhere(name=john)Find(ampuser3)

Example4morecomplexconditions

varuser4Userinfo

Wherethreeargumentsareaccepted

ormWhere(name=andageltjohn88)Find(ampuser4)

Examplestogetmultiplerecords

HowtousebeedbORM

128

Example1gets10recordswithidgt3thatstartswithposition20

varallusers[]Userinfo

err=ormWhere(idgt3)Limit(1020)FindAll(ampallusers)

Example2omitsthesecondargumentoflimitsoitstartswith0andgets10records

vartenusers[]Userinfo

err=ormWhere(idgt3)Limit(10)FindAll(amptenusers)

Example3getsallrecords

vareveryone[]Userinfo

err=ormOrderBy(uiddescusernameasc)FindAll(ampeveryone)

AsyoucanseetheLimitmethodisforlimitingthenumberofresults

Limit()supportstwoargumentsthenumberofresultsandthestartingposition0isthedefaultvalueofthestartingpositionOrderBy()isfororderingresultsTheargumentistheordercondition

AlltheexamplesherearesimplymappingrecordstostructsYoucanalsojustputthedataintoamapasfollows

a_=ormSetTable(userinfo)SetPK(uid)Where(2)Select(uidusername)FindMap()

Select()tellsbeedbhowmanyfieldsyouwanttogetfromthedatabasetableIfunspecifiedallfieldsarereturnedbydefaultFindMap()returnsthe[]map[string][]bytetypesoyouneedtoconverttoothertypesyourself

Deletedatabeedbprovidesrichmethodstodeletedata

Example1deleteasinglerecord

saveoneistheoneinaboveexample

ormDelete(ampsaveone)

Example2deletemultiplerecords

alluseristheslicewhichgetsmultiplerecords

ormDeleteAll(ampalluser)

Example3deleterecordsbySQL

ormSetTable(userinfo)Where(uidgt3)DeleteRow()

AssociationqueriesbeedbdoesntsupportjoiningbetweenstructsHoweversincesomeapplicationsneedthisfeaturehereisanimplementation

a_=ormSetTable(userinfo)Join(LEFTuserdetailuserinfouid=userdetailuid)

Where(userinfouid=1)Select(userinfouiduserinfousernameuserdetailprofile)FindMap()

HowtousebeedbORM

129

WeseeanewmethodcalledJoin()thathasthreearguments

ThefirstargumentTypeofJoinINNERLEFTOUTERCROSSetcThesecondargumentthetableyouwanttojoinwithThethirdargumentjoincondition

GroupByandHavingbeedbalsohasanimplementationofgroupbyandhaving

a_=ormSetTable(userinfo)GroupBy(username)Having(username=astaxie)FindMap()

GroupBy()indicatesthefieldthatisforgroupbyHaving()indicatesconditionsofhaving

FutureIhavereceivedalotoffeedbackonbeedbfrommanypeopleallaroundtheworldandImthinkingaboutreconfiguringthefollowingaspects

ImplementaninterfacedesignsimilartodatabasesqldriverinordertofacilitateCRUDoperationsImplementrelationaldatabaseassociationslikeonetooneonetomanyandmanytomanyHeresasample

typeProfilestruct

Nicknamestring

Mobilestring

typeUserinfostruct

Uidint

PK_Usernamestring

Departnamestring

CreatedtimeTime

ProfileHasOne

Auto-createtablesandindexesImplementaconnectionpoolusinggoroutines

LinksDirectoryPrevioussectionPostgreSQLNextsectionNoSQLdatabase

HowtousebeedbORM

130

56NoSQLdatabaseANoSQLdatabaseprovidesamechanismforthestorageandretrievalofdatathatuseslooserconsistencymodelsthantypicalrelationaldatabasesinordertoachievehorizontalscalingandhigheravailabilitySomeauthorsrefertothemasNotonlySQLtoemphasizethatsomeNoSQLsystemsdoallowSQL-likequerylanguagestobeused

AstheClanguageofthe21stcenturyGohasgoodsupportforNoSQLdatabasesincludingthepopularredismongoDBCassandraandMembaseNoSQLdatabases

redisredisisakey-valuestoragesystemlikeMemcachedthatsupportsthestringlistsetandzset(orderedset)valuetypes

TherearesomeGodatabasedriversforredis

httpsgithubcomgaryburdredigohttpsgithubcomgo-redisredishttpsgithubcomhoisieredishttpsgithubcomalphazeroGo-Redishttpsgithubcomsimonz05godis

Letsseehowtousethedriverthatredigotooperateonadatabase

packagemain

import(

fmt

githubcomgaryburdredigoredis

os

ossignal

syscall

time

)

var(

PoolredisPool

)

funcinit()

redisHost=6379

Pool=newPool(redisHost)

close()

funcnewPool(serverstring)redisPool

returnampredisPool

MaxIdle3

IdleTimeout240timeSecond

Dialfunc()(redisConnerror)

cerr=redisDial(tcpserver)

iferr=nil

returnnilerr

returncerr

TestOnBorrowfunc(credisConnttimeTime)error

_err=cDo(PING)

returnerr

NOSQL

131

funcclose()

c=make(chanosSignal1)

signalNotify(cosInterrupt)

signalNotify(csyscallSIGTERM)

signalNotify(csyscallSIGKILL)

gofunc()

lt-c

PoolClose()

osExit(0)

()

funcGet(keystring)([]byteerror)

conn=PoolGet()

deferconnClose()

vardata[]byte

dataerr=redisBytes(connDo(GETkey))

iferr=nil

returndatafmtErrorf(errorgetkeysvkeyerr)

returndataerr

funcmain()

testerr=Get(test)

fmtPrintln(testerr)

IforkedthelastofthesepackagesfixedsomebugsanduseditinmyshortURLservice(2millionPVeveryday)

httpsgithubcomastaxiegoredis

LetsseehowtousethedriverthatIforkedtooperateonadatabase

packagemain

import(

githubcomastaxiegoredis

fmt

)

funcmain()

varclientgoredisClient

SetthedefaultportinRedis

clientAddr=1270016379

stringmanipulation

clientSet(a[]byte(hello))

val_=clientGet(a)

fmtPrintln(string(val))

clientDel(a)

listoperation

vals=[]stringabcde

for_v=rangevals

clientRpush(l[]byte(v))

dbvals_=clientLrange(l04)

foriv=rangedbvals

println(istring(v))

clientDel(l)

NOSQL

132

WecanseethatitisquiteeasytooperateredisinGoandithashighperformanceItsclientcommandsarealmostthesameasredisbuilt-incommands

mongoDBmongoDB(fromhumongous)isanopensourcedocument-orienteddatabasesystemdevelopedandsupportedby10genItispartoftheNoSQLfamilyofdatabasesystemsInsteadofstoringdataintablesasisdoneinaclassicalrelationaldatabaseMongoDBstoresstructureddataasJSON-likedocumentswithdynamicschemas(MongoDBcallstheformatBSON)makingtheintegrationofdataincertaintypesofapplicationseasierandfaster

Figure51MongoDBcomparedtoMysql

ThebestdriverformongoDBiscalledmgoanditispossiblethatitwillbeincludedinthestandardlibraryinthefuture

Installmgo

gogetgopkginmgov2

Hereistheexample

packagemain

import(

fmt

gopkginmgov2

gopkginmgov2bson

log

)

typePersonstruct

Namestring

Phonestring

funcmain()

sessionerr=mgoDial(server1examplecomserver2examplecom)

iferr=nil

panic(err)

defersessionClose()

OptionalSwitchthesessiontoamonotonicbehavior

sessionSetMode(mgoMonotonictrue)

c=sessionDB(test)C(people)

err=cInsert(ampPersonAle+555381169639

ampPersonCla+555384028510)

iferr=nil

logFatal(err)

result=Person

err=cFind(bsonMnameAle)One(ampresult)

iferr=nil

logFatal(err)

fmtPrintln(PhoneresultPhone)

NOSQL

133

WecanseethattherearenobigdifferenceswhenitcomestooperatingonmgoorbeedbdatabasestheyarebothbasedonstructsThisistheGowayofdoingthings

LinksDirectoryPrevioussectionDevelopORMbasedonbeedbNextsectionSummary

NOSQL

134

57SummaryInthischapteryoufirstlearnedaboutthedesignofthedatabasesqlinterfaceandmanythird-partydatabasedriversforvariousdatabasetypesThenIintroducedbeedbanORMforrelationaldatabasestoyouIalsoshowedyousomesampledatabaseoperationsIntheendItalkedaboutafewNoSQLdatabasesWesawthatGoprovidesverygoodsupportforthoseNoSQLdatabases

AfterreadingthischapterIhopethatyouhaveabetterunderstandingofhowtooperatedatabasesinGoThisisthemostimportantpartofwebdevelopmentsoIwantyoutocompletelyunderstandthedesignconceptsofthedatabasesqlinterface

LinksDirectoryPrevioussectionNoSQLdatabaseNextsectionDatastorageandsession

Summary

135

6DatastorageandsessionsAnimportanttopicinwebdevelopmentisprovidingagooduserexperiencebutthefactthatHTTPisastatelessprotocolseemscontrarytothisspiritHowcanwecontrolthewholeprocessofviewingwebsitesforusersTheclassicsolutionsareusingcookiesandsessionswherecookiesserveastheclientsidemechanismandsessionsaresavedontheserversidewithauniqueidentifierforeverysingleuserNotethatsessionscanbepassedinURLsorcookiesoreveninyourdatabase(whichismuchmoresecurebutmayhamperyourapplicationperformance)

Insection61wearegoingtotalkaboutdifferencesbetweencookiesandsessionsInsection62youlllearnhowtousesessionsinGowithanimplementationofasessionmanagerInsection63wewilltalkaboutsessionhijackingandhowtopreventitwhenyouknowthatsessionscanbesavedanywhereThesessionmanagerwewillimplementinsection63willsavesessionsinmemorybutifweneedtoexpandourapplicationtoallowforsessionsharingitsalwaysbettertosavethesesessionsdirectlyintoourdatabaseWelltalkmoreaboutthisinsection64

LinksDirectoryPreviousChapterChapter5SummaryNextsectionSessionandcookies

Datastorageandsession

136

61SessionandcookiesSessionsandcookiesaretwoverycommonwebconceptsandarealsoveryeasytomisunderstandHowevertheyareextremelyimportantfortheauthorizationofpagesaswellasforgatheringpagestatisticsLetstakealookatthesetwousecases

SupposeyouwanttocrawlapagethatrestrictspublicaccesslikeatwitterusershomepageforinstanceOfcourseyoucanopenyourbrowserandtypeinyourusernameandpasswordtologinandaccessthatinformationbutso-calledwebcrawlingmeansthatweuseaprogramtoautomatethisprocesswithoutanyhumaninterventionThereforewehavetofindoutwhatisreallygoingonbehindthesceneswhenweuseabrowsertologin

WhenwefirstreceivealoginpageandtypeinausernameandpasswordafterwepresstheloginbuttonthebrowsersendsaPOSTrequesttotheremoteserverTheBrowserredirectstotheuserhomepageaftertheserververifiesthelogininformationandreturnsanHTTPresponseThequestionhereishowdoestheserverknowthatwehaveaccessprivilegesforthedesiredwebpageBecauseHTTPisstatelesstheserverhasnowayofknowingwhetherornotwepassedtheverificationinlaststepTheeasiestandperhapsthemostnaivesolutionistoappendtheusernameandpasswordtotheURLThisworksbutputstoomuchpressureontheserver(theservermustvalidateeveryrequestagainstthedatabase)andcanbedetrimentaltotheuserexperienceAnalternativewayofachievingthisgoalistosavetheusersidentityeitherontheserversideorclientsideusingcookiesandsessions

Cookiesinshortstorehistoricalinformation(includinguserlogininformation)ontheclientscomputerTheclientsbrowsersendsthesecookieseverytimetheuservisitsthesamewebsiteautomaticallycompletingtheloginstepfortheuser

Figure61cookieprinciple

SessionsontheotherhandstorehistoricalinformationontheserversideTheserverusesasessionidtoidentifydifferentsessionsandthesessionidthatisgeneratedbytheservershouldalwaysberandomanduniqueYoucanusecookiesorURLargumentstogettheclientsidentity

Figure62sessionprinciple

CookiesCookiesaremaintainedbybrowsersTheycanbemodifiedduringcommunicationbetweenwebserversandbrowsersWebapplicationscanaccesscookieinformationwhenusersvisitthecorrespondingwebsitesWithinmostbrowsersettingsthereisonesettingpertainingtocookieprivacyYoushouldbeabletoseesomethingsimilartothefollowingwhenyouopenit

Figure63cookieinbrowsers

Cookieshaveanexpirytimeandtherearetwotypesofcookiesdistinguishedbytheirlifecylessessioncookiesandpersistentcookies

IfyourapplicationdoesntsetacookieexpirytimethebrowserwillnotsaveitintothelocalfilesystemafterthebrowserisclosedThesecookiesarecalledsessioncookiesandthistypeofcookieisusuallysavedinmemoryinsteadoftothelocalfilesystem

Ifyourapplicationdoessetanexpirytime(forexamplesetMaxAge(606024))thebrowserwillsavethiscookietothelocalfilesystemanditwillnotbedeleteduntilreachingtheallottedexpirytimeCookiesthataresavedtothelocalfilesystemcanbesharedbydifferentbrowserprocesses-forexamplebytwoIEwindowsdifferentbrowsersusedifferentprocessesfordealingwithcookiesthataresavedinmemory  

Sessionandcookies

137

SetcookiesinGoGousestheSetCookiefunctioninthenethttppackagetosetcookies

httpSetCookie(wResponseWritercookieCookie)

wistheresponseoftherequestandcookieisastructLetsseewhatitlookslike

typeCookiestruct

Namestring

Valuestring

Pathstring

Domainstring

ExpirestimeTime

RawExpiresstring

MaxAge=0meansnoMax-Ageattributespecified

MaxAgelt0meansdeletecookienowequivalentlyMax-Age0

MaxAgegt0meansMax-Ageattributepresentandgiveninseconds

MaxAgeint

Securebool

HttpOnlybool

Rawstring

Unparsed[]stringRawtextofunparsedattribute-valuepairs

Hereisanexampleofsettingacookie

expiration=timeNow()Add(36524timeHour)

cookie=httpCookieNameusernameValueastaxieExpiresexpiration

httpSetCookie(wampcookie)

FetchcookiesinGoTheaboveexampleshowshowtosetacookieNowletsseehowtogetacookiethathasbeenset

cookie_=rCookie(username)

fmtFprint(wcookie)

Hereisanotherwaytogetacookie

for_cookie=rangerCookies()

fmtFprint(wcookieName)

Asyoucanseeitsveryconvenienttogetcookiesfromrequests

SessionsAsessionisaseriesofactionsormessagesForexampleyoucanthinkoftheactionsyoubetweenpickingupyourtelephonetohanginguptobeatypeofsessionWhenitcomestonetworkprotocolssessionshavemoretodowithconnectionsbetweenbrowsersandservers

Sessionshelptostoretheconnectionstatusbetweenserverandclientandthiscansometimesbeintheformofadatastoragestruct

Sessionandcookies

138

Sessionsareaserver-sidemechanismandusuallyemployhashtables(orsomethingsimilar)tosaveincominginformation

WhenanapplicationneedstoassignanewsessiontoaclienttheservershouldcheckifthereareanyexistingsessionsforthesameclientwithauniquesessionidIfthesessionidalreadyexiststheserverwilljustreturnthesamesessiontotheclientOntheotherhandifasessioniddoesntexistfortheclienttheservercreatesabrandnewsession(thisusuallyhappenswhentheserverhasdeletedthecorrespondingsessionidbuttheuserhasappendedtheoldsessionmanually)

Thesessionitselfisnotcomplexbutitsimplementationanddeploymentaresoyoucannotuseonewaytorulethemall

SummaryInconclusionthepurposeofsessionsandcookiesarethesameTheyarebothforovercomingthestatelessnessofHTTPbuttheyusedifferentmethodsSessionsusecookiestosavesessionidsontheclientsideandsaveallotherinformationontheserversideCookiessaveallclientinformationontheclientsideYoumayhavenoticedthatcookieshavesomesecurityproblemsForexampleusernamesandpasswordscanpotentiallybecrackedandcollectedbymaliciousthirdpartywebsites

Herearetwocommonexploits

1 appAsettinganunexpectedcookieforappB2 XSSattackappAusestheJavaScriptdocumentcookietoaccessthecookiesofappB

AfterfinishingthissectionyoushouldknowsomeofthebasicconceptsofcookiesandsessionsYoushouldbeabletounderstandthedifferencesbetweenthemsothatyouwontkillyourselfwhenbugsinevitablyemergeWelldiscusssessionsinmoredetailinthefollowingsections

LinksDirectoryPrevioussectionDatastorageandsessionNextsectionHowtousesessioninGo

Sessionandcookies

139

62HowtousesessionsinGoInsection61welearnedthatsessionsareonesolutionforverifyingusersandthatfornowtheGostandardlibrarydoesnothavebaked-insupportforsessionsorsessionhandlingSoweregoingtoimplementourownversionofasessionmanagerinGo

CreatingsessionsThebasicprinciplebehindsessionsisthataservermaintainsinformationforeverysingleclientandclientsrelyonuniquesessionidstoaccessthisinformationWhenusersvisitthewebapplicationtheserverwillcreateanewsessionwiththefollowingthreestepsasneeded

CreateauniquesessionidOpenupadatastoragespacenormallywesavesessionsinmemorybutyouwillloseallsessiondataifthesystemisaccidentallyinterruptedThiscanbeaveryseriousissueifwebapplicationdealswithsensitivedatalikeinelectroniccommerceforinstanceInordertosolvethisproblemyoucaninsteadsaveyoursessiondatainadatabaseorfilesystemThismakesdatapersistencemorereliableandeasytosharewithotherapplicationsalthoughthetradeoffisthatmoreserver-sideIOisneededtoreadandwritethesesessionsSendtheuniquesessionidtotheclient

ThekeystephereistosendtheuniquesessionidtotheclientInthecontextofastandardHTTPresponseyoucaneitherusetheresponselineheaderorbodytoaccomplishthisthereforewehavetwowaystosendsessionidstoclientsbycookiesorURLrewrites

CookiestheservercaneasilyuseSet-cookieinsideofaresponseheadertosendasessionidtoaclientandaclientcanthenusethiscookieforfuturerequestsweoftensettheexpirytimeforcookiescontainingsessioninformationto0whichmeansthecookiewillbesavedinmemoryandonlydeletedafterusershaveclosetheirbrowsersURLrewriteappendthesessionidasargumentsintheURLforallpagesThiswayseemsmessybutitsthebestchoiceifclientshavedisabledcookiesintheirbrowsers

UseGotomanagesessionsWevetalkedaboutconstructingsessionsandyoushouldnowhaveageneraloverviewofitbuthowcanweusesessionsondynamicpagesLetstakeacloserlookatthelifecycleofasessionsowecancontinueimplementingourGosessionmanager

Sessionmanagementdesign

Hereisalistofsomeofthekeyconsiderationsinsessionmanagementdesign

GlobalsessionmanagerKeepsessioniduniqueHaveonesessionforeveryuserSessionstorageinmemoryfileordatabaseDealwithexpiredsessions

NextwellexamineacompleteexampleofaGosessionmanagerandtherationalebehindsomeofitsdesigndecisions

Sessionmanager

Defineaglobalsessionmanager

HowtousesessioninGo

140

typeManagerstruct

cookieNamestringprivatecookiename

locksyncMutexprotectssession

providerProvider

maxlifetimeint64

funcNewManager(provideNamecookieNamestringmaxlifetimeint64)(Managererror)

providerok=provides[provideName]

ifok

returnnilfmtErrorf(sessionunknownprovideq(forgottenimport)provideName)

returnampManagerproviderprovidercookieNamecookieNamemaxlifetimemaxlifetimenil

Createaglobalsessionmanagerinthemain()function

varglobalSessionssessionManager

Theninitializethesessionmanager

funcinit()

globalSessions=NewManager(memorygosessionid3600)

WeknowthatwecansavesessionsinmanywaysincludinginmemorythefilesystemordirectlyintothedatabaseWeneedtodefineaProviderinterfaceinordertorepresenttheunderlyingstructureofoursessionmanager

typeProviderinterface

SessionInit(sidstring)(Sessionerror)

SessionRead(sidstring)(Sessionerror)

SessionDestroy(sidstring)error

SessionGC(maxLifeTimeint64)

SessionInitimplementstheinitializationofasessionandreturnsanewsessionifitsucceedsSessionReadreturnsasessionrepresentedbythecorrespondingsidCreatesanewsessionandreturnsitifitdoesnotalreadyexistSessionDestroygivenansiddeletesthecorrespondingsessionSessionGCdeletesexpiredsessionvariablesaccordingtomaxLifeTime

SowhatmethodsshouldoursessioninterfacehaveIfyouhaveanyexperienceinwebdevelopmentyoushouldknowthatthereareonlyfouroperationsforsessionssetvaluegetvaluedeletevalueandgetcurrentsessionidSooursessioninterfaceshouldhavefourmethodstoperformtheseoperations

typeSessioninterface

Set(keyvalueinterface)errorsetsessionvalue

Get(keyinterface)interfacegetsessionvalue

Delete(keyinterface)errordeletesessionvalue

SessionID()stringbackcurrentsessionID

ThisdesigntakesitsrootsfromthedatabasesqldriverwhichdefinestheinterfacefirstthenregistersspecificstructureswhenwewanttouseitThefollowingcodeistheinternalimplementationofasessionregisterfunction

HowtousesessioninGo

141

varprovides=make(map[string]Provider)

Registermakesasessionprovideravailablebytheprovidedname

IfaRegisteriscalledtwicewiththesamenameorifthedriverisnil

itpanics

funcRegister(namestringproviderProvider)

ifprovider==nil

panic(sessionRegisterproviderisnil)

if_dup=provides[name]dup

panic(sessionRegistercalledtwiceforprovider+name)

provides[name]=provider

UniquesessionidsSessionidsareforidentifyingusersofwebapplicationssotheymustbeuniqueThefollowingcodeshowshowtoachievethisgoal

func(managerManager)sessionId()string

b=make([]byte32)

if_err=ioReadFull(randReaderb)err=nil

return

returnbase64URLEncodingEncodeToString(b)

CreatingasessionWeneedtoallocateorgetanexistingsessioninordertovalidateuseroperationsTheSessionStartfunctionisforcheckingtheexistenceofanysessionsrelatedtothecurrentuserandcreatinganewsessionifnoneisfound

func(managerManager)SessionStart(whttpResponseWriterrhttpRequest)(sessionSession)

managerlockLock()

defermanagerlockUnlock()

cookieerr=rCookie(managercookieName)

iferr=nil||cookieValue==

sid=managersessionId()

session_=managerproviderSessionInit(sid)

cookie=httpCookieNamemanagercookieNameValueurlQueryEscape(sid)PathHttpOnlytrueM

axAgeint(managermaxlifetime)

httpSetCookie(wampcookie)

else

sid_=urlQueryUnescape(cookieValue)

session_=managerproviderSessionRead(sid)

return

Hereisanexamplethatusessessionsforaloginoperation

funclogin(whttpResponseWriterrhttpRequest)

sess=globalSessionsSessionStart(wr)

rParseForm()

ifrMethod==GET

t_=templateParseFiles(logingtpl)

wHeader()Set(Content-Typetexthtml)

tExecute(wsessGet(username))

else

sessSet(usernamerForm[username])

httpRedirect(wr302)

HowtousesessioninGo

142

Operationvaluesetgetanddelete

TheSessionStartfunctionreturnsavariablethatimplementsasessioninterfaceHowdoweuseit

YousawsessionGet(uid)intheaboveexampleforabasicoperationNowletsexamineamoredetailedexample

funccount(whttpResponseWriterrhttpRequest)

sess=globalSessionsSessionStart(wr)

createtime=sessGet(createtime)

ifcreatetime==nil

sessSet(createtimetimeNow()Unix())

elseif(createtime(int64)+360)lt(timeNow()Unix())

globalSessionsSessionDestroy(wr)

sess=globalSessionsSessionStart(wr)

ct=sessGet(countnum)

ifct==nil

sessSet(countnum1)

else

sessSet(countnum(ct(int)+1))

t_=templateParseFiles(countgtpl)

wHeader()Set(Content-Typetexthtml)

tExecute(wsessGet(countnum))

AsyoucanseeoperatingonsessionssimplyinvolvesusingthekeyvaluepatternintheSetGetandDeleteoperations

BecausesessionshavetheconceptofanexpirytimewedefinetheGCtoupdatethesessionslatestmodifytimeThiswaytheGCwillnotdeletesessionsthathaveexpiredbutarestillbeingused

ResetsessionsWeknowthatwebapplicationshavealogoutoperationWhenuserslogoutweneedtodeletethecorrespondingsessionWevealreadyusedtheresetoperationinaboveexample-nowletstakealookatthefunctionbody

Destroysessionid

func(managerManager)SessionDestroy(whttpResponseWriterrhttpRequest)

cookieerr=rCookie(managercookieName)

iferr=nil||cookieValue==

return

else

managerlockLock()

defermanagerlockUnlock()

managerproviderSessionDestroy(cookieValue)

expiration=timeNow()

cookie=httpCookieNamemanagercookieNamePathHttpOnlytrueExpiresexpirationMaxAge-1

httpSetCookie(wampcookie)

Deletesessions

LetsseehowtoletthesessionmanagerdeleteasessionWeneedtostarttheGCinthemain()function

HowtousesessioninGo

143

funcinit()

goglobalSessionsGC()

func(managerManager)GC()

managerlockLock()

defermanagerlockUnlock()

managerproviderSessionGC(managermaxlifetime)

timeAfterFunc(timeDuration(managermaxlifetime)func()managerGC())

WeseethattheGCmakesfulluseofthetimerfunctioninthetimepackageItautomaticallycallsGCwhenthesessiontimesoutensuringthatallsessionsareusableduringmaxLifeTimeAsimilarsolutioncanbeusedtocountonlineusers

SummarySofarweimplementedasessionmanagertomanageglobalsessionsinthewebapplicationanddefinedtheProviderinterfaceasthestorageimplementationofSessionInthenextsectionwearegoingtotalkabouthowtoimplementProviderforadditionalsessionstoragestructureswhichyouwillbeabletoreferenceinthefuture

LinksDirectoryPrevioussectionSessionandcookiesNextsectionSessionstorage

HowtousesessioninGo

144

63SessionstorageWeintroducedasimplesessionmanagersworkingprinciplesintheprevioussectionandamongotherthingswedefinedasessionstorageinterfaceInthissectionImgoingtoshowyouanexampleofamemorybasedsessionstorageenginethatimplementsthisinterfaceYoucantailorthistootherformsofsessionstorageaswell

packagememory

import(

containerlist

githubcomastaxiesession

sync

time

)

varpder=ampProviderlistlistNew()

typeSessionStorestruct

sidstringuniquesessionid

timeAccessedtimeTimelastaccesstime

valuemap[interface]interfacesessionvaluestoredinside

func(stSessionStore)Set(keyvalueinterface)error

stvalue[key]=value

pderSessionUpdate(stsid)

returnnil

func(stSessionStore)Get(keyinterface)interface

pderSessionUpdate(stsid)

ifvok=stvalue[key]ok

returnv

else

returnnil

returnnil

func(stSessionStore)Delete(keyinterface)error

delete(stvaluekey)

pderSessionUpdate(stsid)

returnnil

func(stSessionStore)SessionID()string

returnstsid

typeProviderstruct

locksyncMutexlock

sessionsmap[string]listElementsaveinmemory

listlistListgc

func(pderProvider)SessionInit(sidstring)(sessionSessionerror)

pderlockLock()

deferpderlockUnlock()

v=make(map[interface]interface0)

newsess=ampSessionStoresidsidtimeAccessedtimeNow()valuev

element=pderlistPushBack(newsess)

pdersessions[sid]=element

returnnewsessnil

func(pderProvider)SessionRead(sidstring)(sessionSessionerror)

ifelementok=pdersessions[sid]ok

Sessionstorage

145

returnelementValue(SessionStore)nil

else

sesserr=pderSessionInit(sid)

returnsesserr

returnnilnil

func(pderProvider)SessionDestroy(sidstring)error

ifelementok=pdersessions[sid]ok

delete(pdersessionssid)

pderlistRemove(element)

returnnil

returnnil

func(pderProvider)SessionGC(maxlifetimeint64)

pderlockLock()

deferpderlockUnlock()

for

element=pderlistBack()

ifelement==nil

break

if(elementValue(SessionStore)timeAccessedUnix()+maxlifetime)lttimeNow()Unix()

pderlistRemove(element)

delete(pdersessionselementValue(SessionStore)sid)

else

break

func(pderProvider)SessionUpdate(sidstring)error

pderlockLock()

deferpderlockUnlock()

ifelementok=pdersessions[sid]ok

elementValue(SessionStore)timeAccessed=timeNow()

pderlistMoveToFront(element)

returnnil

returnnil

funcinit()

pdersessions=make(map[string]listElement0)

sessionRegister(memorypder)

TheaboveexampleimplementsamemorybasedsessionstoragemechanismItusesitsinit()functiontoregisterthisstorageenginetothesessionmanagerSohowdoweregisterthisenginefromourmainprogram

import(

githubcomastaxiesession

_githubcomastaxiesessionprovidersmemory

)

Weusetheblankimportmechanism(whichwillinvokethepackagesinit()functionautomatically)toregisterthisenginetoasessionmanagerWethenusethefollowingcodetoinitializethesessionmanager

Sessionstorage

146

varglobalSessionssessionManager

initializeininit()function

funcinit()

globalSessions_=sessionNewManager(memorygosessionid3600)

goglobalSessionsGC()

LinksDirectoryPrevioussectionHowtousesessionsinGoNextsectionPreventsessionhijacking

Sessionstorage

147

64PreventingsessionhijackingSessionhijackingisacommonyetserioussecuritythreatClientsusesessionidsforvalidationandotherpurposeswhencommunicatingwithserversUnfortunatelymaliciousthirdpartiescansometimestrackthesecommunicationsandfigureouttheclientsessionid

Inthissectionwearegoingtoshowyouhowtohijackasessionforeducationalpurposes

ThesessionhijackingprocessThefollowingcodeisacounterforthecountvariable

funccount(whttpResponseWriterrhttpRequest)

sess=globalSessionsSessionStart(wr)

ct=sessGet(countnum)

ifct==nil

sessSet(countnum1)

else

sessSet(countnum(ct(int)+1))

t_=templateParseFiles(countgtpl)

wHeader()Set(Content-Typetexthtml)

tExecute(wsessGet(countnum))

Thecontentofcountgtplisasfollows

HiNowcount

Wecanseethefollowingcontentinthebrowser

Figure64countinbrowser

Keeprefreshinguntilthenumberbecomes6thenopenthebrowserscookiemanager(Iusechromehere)Youshouldbeabletoseethefollowinginformation

Figure65cookiessavedinabrowser

Thisstepisveryimportantopenanotherbrowser(Iusefirefoxhere)copytheURLtothenewbrowseropenacookiesimulatortocreateanewcookieandinputexactlythesamevalueasthecookiewesawinourfirstbrowser

Figure66Simulateacookie

Refreshthepageandyoullseethefollowing

Figure67hijackingthesessionhassucceeded

HereweseethatwecanhijacksessionsbetweendifferentbrowsersandactionsperformedinonebrowsercanaffectthestateofapageinanotherbrowserBecauseHTTPisstatelessthereisnowayofknowingthatthesessionidfromfirefoxissimulatedandchromeisalsonotabletoknowthatitssessionidhasbeenhijacked

Preventhijackofsession

148

preventsessionhijacking

cookieonlyandtoken

ThroughthissimpleexampleofhijackingasessionyoucanseethatitsverydangerousbecauseitallowsattackerstodowhatevertheywantSohowcanwepreventsessionhijacking

ThefirststepistoonlysetsessionidsincookiesinsteadofinURLrewritesAlsoweshouldsetthehttponlycookiepropertytotrueThisrestrictsclient-sidescriptsfromgainingaccesstothesessionidUsingthesetechniquescookiescannotbeaccessedbyXSSanditwontbeaseasyaswedemonstratedtogetasessionidfromacookiemanager

ThesecondstepistoaddatokentoeveryrequestSimilartothemannerinwhichwedealtwithrepeatingformsubmissionsinprevioussectionsweaddahiddenfieldthatcontainsatokenWhenarequestissenttotheserverwecanverifythistokentoprovethattherequestisunique

h=md5New()

salt=astaxie^7amp8888

ioWriteString(hsalt+timeNow()String())

token=fmtSprintf(xhSum(nil))

ifrForm[token]=token

asktologin

sessSet(tokentoken)

SessionidtimeoutAnothersolutionistoaddacreatetimeforeverysessionandtoreplaceexpiredsessionidswithnewonesThiscanpreventsessionhijackingundercertaincircumstancessuchaswhenthehijackisattemptedtoolate

createtime=sessGet(createtime)

ifcreatetime==nil

sessSet(createtimetimeNow()Unix())

elseif(createtime(int64)+60)lt(timeNow()Unix())

globalSessionsSessionDestroy(wr)

sess=globalSessionsSessionStart(wr)

Wesetavaluetosavethecreatetimeandcheckifitsexpired(Iset60secondshere)Thisstepcanoftenthwartsessionhijackingattempts

BycombiningthetwosolutionssetoutaboveyouwillbeabletopreventmostsessionhijackingattemptsfromsucceedingOntheonehandsessionidsthatarefrequentlyresetwillresultinanattackeralwaysgettingexpiredanduselesssessionidsontheotherhandbysettingthehttponlypropertyoncookiesandensuringthatsessionidscanonlybepassedviacookiesallURLbasedattacksaremitigatedFinallywesetMaxAge=0onourcookieswhichmeansthatthesessionidswillnotbesavedinthebrowserhistory

LinksDirectoryPrevioussectionSessionstorageNextsectionSummary

Preventhijackofsession

149

65SummaryInthischapterwelearnedaboutthedefinitionandpurposeofsessionsandcookiesandtherelationshipbetweenthetwoSinceGodoesntsupportsessionsinitsstandardlibrarywealsodesignedourownsessionmanagerWewentthrougheverythingfromcreatingclientsessionstodeletingthemWethendefinedaninterfacecalledProviderwhichsupportsallsessionstoragestructuresInsection63weimplementedamemorybasedsessionmanagertopersistclientdataacrosssessionsInsection64IdemonstratedonewayofhijackingasessionThenwelookedathowtopreventyourownsessionsfrombeinghijackedIhopethatyounowunderstandmostoftheworkingprinciplesbehindsessionssothatyoureabletosafelyusetheminyourapplications

LinksDirectoryPrevioussectionPreventsessionhijackingNextchapterTextfiles

Summary

150

7TextfilesHandlingtextfilesisabigpartofwebdevelopmentWeoftenneedtoproduceorhandlereceivedtextcontentincludingstringsnumbersJSONXMLetcAsahighperformancelanguageGohasgoodsupportforthisinitsstandardlibraryYoullfindthatthesesupportinglibrariesarejustawesomeandwillallowyoutoeasilydealwithanytextcontentyoumayencounterThischaptercontains4sectionsandwillgiveyouafullintroductiontotextprocessinginGo

XMLisaninteractivelanguagethatiscommonlyusedinmanyAPIsmanywebserverswritteninJavauseXMLastheirstandardinteractionlanguageWellmoretalkaboutXMLinsection71Insection72welltakealookatJSONwhichhasbeenverypopularinrecentyearsandismuchmoreconvenientthanXMLInsection73wearegoingtotalkaboutregularexpressionswhich(forthemajorityofpeople)lookslikealanguageusedbyaliensInsection74youwillseehowtheMVCpatternisusedtodevelopapplicationsinGoandalsohowtouseGostemplatepackagefortemplatingyourviewsInsection75wellintroduceyoutofileandfolderoperationsFinallywewillexplainsomeGostringoperationsinsection76

LinksDirectoryPreviousChapterChapter6SummaryNextsectionXML

Textfiles

151

71XMLXMLisacommonlyuseddatacommunicationformatinwebservicesTodayitsassumingamoreandmoreimportantroleinwebdevelopmentInthissectionweregoingtointroducehowtoworkwithXMLthroughGosstandardlibrary

IwillnotmakeanyattemptstoteachXMLssyntaxorconventionsForthatpleasereadmoredocumentationaboutXMLitselfWewillonlyfocusonhowtoencodeanddecodeXMLfilesinGo

SupposeyouworkinITandyouhavetodealwiththefollowingXMLconfigurationfile

ltxmlversion=10encoding=utf-8gt

ltserversversion=1gt

ltservergt

ltserverNamegtShanghai_VPNltserverNamegt

ltserverIPgt127001ltserverIPgt

ltservergt

ltservergt

ltserverNamegtBeijing_VPNltserverNamegt

ltserverIPgt127002ltserverIPgt

ltservergt

ltserversgt

TheaboveXMLdocumentcontainstwokindsofinformationaboutyourservertheservernameandIPWewillusethisdocumentinourfollowingexamples

ParseXMLHowdoweparsethisXMLdocumentWecanusetheUnmarshalfunctioninGosxmlpackagetodothis

funcUnmarshal(data[]bytevinterface)error

thedataparameterreceivesadatastreamfromanXMLsourceandvisthestructureyouwanttooutputtheparsedXMLtoItisaninterfacewhichmeansyoucanconvertXMLtoanystructureyoudesireHerewellonlytalkabouthowtoconvertfromXMLtothestructtypesincetheysharesimilartreestructures

Samplecode

XML

152

packagemain

import(

encodingxml

fmt

ioioutil

os

)

typeRecurlyserversstruct

XMLNamexmlName`xmlservers`

Versionstring`xmlversionattr`

Svs[]server`xmlserver`

Descriptionstring`xmlinnerxml`

typeserverstruct

XMLNamexmlName`xmlserver`

ServerNamestring`xmlserverName`

ServerIPstring`xmlserverIP`

funcmain()

fileerr=osOpen(serversxml)Forreadaccess

iferr=nil

fmtPrintf(errorverr)

return

deferfileClose()

dataerr=ioutilReadAll(file)

iferr=nil

fmtPrintf(errorverr)

return

v=Recurlyservers

err=xmlUnmarshal(dataampv)

iferr=nil

fmtPrintf(errorverr)

return

fmtPrintln(v)

XMLisactuallyatreedatastructureandwecandefineaverysimilarstructureusingstructsinGothenusexmlUnmarshaltoconvertfromXMLtoourstructobjectThesamplecodewillprintthefollowingcontent

servers1[serverShanghai_VPN127001serverBeijing_VPN127002]

ltservergt

ltserverNamegtShanghai_VPNltserverNamegt

ltserverIPgt127001ltserverIPgt

ltservergt

ltservergt

ltserverNamegtBeijing_VPNltserverNamegt

ltserverIPgt127002ltserverIPgt

ltservergt

WeusexmlUnmarshaltoparsetheXMLdocumenttothecorrespondingstructobjectYoushouldseethatwehavesomethinglikexmlserverNameinourstructThisisafeatureofstructscalledstructtagsforhelpingwithreflectionLetsseethedefinitionofUnmarshalagain

funcUnmarshal(data[]bytevinterface)error

XML

153

ThefirstargumentisanXMLdatastreamThesecondargumentisstoragetypeandsupportsthestructsliceandstringtypesGosXMLpackageusesreflectionfordatamappingsoallfieldsinvshouldbeexportedHoweverthiscausesaproblemhowdoesitknowwhichXMLfieldcorrespondstothemappedstructfieldTheansweristhattheXMLparserparsesdatainacertainorderThelibrarywilltrytofindthematchingstructtagfirstIfamatchcannotbefoundthenitsearchesthroughthestructfieldnamesBeawarethatalltagsfieldnamesandXMLelementsarecasesensitivesoyouhavetomakesurethatthereisaone-to-onecorrespondenceforthemappingtosucceed

GosreflectionmechanismallowsyoutousethistaginformationtoreflectXMLdatatoastructobjectIfyouwanttoknowmoreaboutreflectioninGopleasereadthepackagedocumentationonstructtagsandreflection

HerearesomeruleswhenusingthexmlpackagetoparseXMLdocumentstostructs

Ifthefieldtypeisastringor[]bytewiththetaginnerxmlUnmarshalwillassignrawXMLdatatoitlikeDescriptionintheaboveexample

Shanghai_VPN127001Beijing_VPN127002

IfafieldiscalledXMLNameanditstypeisxmlNamethenitgetstheelementnamelikeserversinaboveexample

IfafieldstagcontainsthecorrespondingelementnamethenitgetstheelementnameaswelllikeservernameandserveripintheaboveexampleIfafieldstagcontainsattrthenitgetsthecorrespondingelementsattributelikeversioninaboveexampleIfafieldstagcontainssomethinglikeagtbgtcitgetsthevalueoftheelementcofnodebofnodeaIfafieldstagcontains=thenitgetsnothingIfafieldstagcontainsanythenitgetsallchildelementswhichdonotfittheotherrulesIftheXMLelementshaveoneormorecommentsallofthesecommentswillbeaddedtothefirstfieldthathasthetagthatcontainscommentsThisfieldtypecanbeastringor[]byteIfthiskindoffielddoesnotexistallcommentsarediscarded

TheserulestellyouhowtodefinetagsinstructsOnceyouunderstandtheserulesmappingXMLtostructswillbeaseasyasthesamplecodeaboveBecausetagsandXMLelementshaveaone-to-onecorrespondencewecanalsouseslicestorepresentmultipleelementsonthesamelevel

Notethatallfieldsinstructsshouldbeexported(capitalized)inordertoparsedatacorrectly

ProduceXMLWhatifwewanttoproduceanXMLdocumentinsteadofparsingoneHowdowedothisinGoUnsurprisinglythexmlpackageprovidestwofunctionswhichareMarshalandMarshalIndentwherethesecondfunctionautomaticallyindentsthemarshalledXMLdocumentTheirdefinitionasfollows

funcMarshal(vinterface)([]byteerror)

funcMarshalIndent(vinterfaceprefixindentstring)([]byteerror)

ThefirstargumentinbothofthesefunctionsisforstoringamarshalledXMLdatastream

Letslookatanexampletoseehowthisworks

XML

154

packagemain

import(

encodingxml

fmt

os

)

typeServersstruct

XMLNamexmlName`xmlservers`

Versionstring`xmlversionattr`

Svs[]server`xmlserver`

typeserverstruct

ServerNamestring`xmlserverName`

ServerIPstring`xmlserverIP`

funcmain()

v=ampServersVersion1

vSvs=append(vSvsserverShanghai_VPN127001)

vSvs=append(vSvsserverBeijing_VPN127002)

outputerr=xmlMarshalIndent(v)

iferr=nil

fmtPrintf(errorvnerr)

osStdoutWrite([]byte(xmlHeader))

osStdoutWrite(output)

Theaboveexampleprintsthefollowinginformation

ltxmlversion=10encoding=UTF-8gt

ltserversversion=1gt

ltservergt

ltserverNamegtShanghai_VPNltserverNamegt

ltserverIPgt127001ltserverIPgt

ltservergt

ltservergt

ltserverNamegtBeijing_VPNltserverNamegt

ltserverIPgt127002ltserverIPgt

ltservergt

ltserversgt

AswevepreviouslydefinedthereasonwehaveosStdoutWrite([]byte(xmlHeader))isbecausebothxmlMarshalIndentandxmlMarshaldonotoutputXMLheadersontheirownsowehavetoexplicitlyprinttheminordertoproduceXMLdocumentscorrectly

HerewecanseethatMarshalalsoreceivesavparameteroftypeinterfaceSowhataretheruleswhenmarshallingtoanXMLdocument

IfvisanarrayorsliceitprintsallelementslikeavalueIfvisapointeritprintsthecontentthatvispointingtoprintingnothingwhenvisnilIfvisainterfaceitdealwiththeinterfaceaswellIfvisoneoftheothertypesitprintsthevalueofthattype

SohowdoesxmlMarshaldecidetheelementsnameItfollowstheensuingrules

IfvisastructitdefinesthenameinthetagofXMLNameThefieldnameisXMLNameandthetypeisxmlNameFieldtaginstructFieldnameinstructTypenameofmarshal

XML

155

ThenweneedtofigureouthowtosettagsinordertoproducethefinalXMLdocument

XMLNamewillnotbeprintedFieldsthathavetagscontaining-willnotbeprintedIfatagcontainsnameattritusesnameastheattributenameandthefieldvalueasthevaluelikeversionintheaboveexampleIfatagcontainsattritusesthefieldsnameastheattributenameandthefieldvalueasitsvalueIfatagcontainschardataitprintscharacterdatainsteadofelementIfatagcontainsinnerxmlitprintstherawvalueIfatagcontainscommentitprintsitasacommentwithoutescapingsoyoucannothave--initsvalueIfatagcontainsomitemptyitomitsthisfieldifitsvalueiszero-valueincludingfalse0nilpointerornilinterfacezerolengthofarrayslicemapandstringIfatagcontainsagtbgtcitprintsthreeelementswhereacontainsbandbcontainsclikeinthefollowingcode `xmlFirstNamestringxmlnamegtfirstLastNamestringxmlnamegtlast`

Asta

Xieltnamegt```YoumayhavenoticedthatstructtagsareveryusefulfordealingwithXMLandthesamegoesfortheotherdataformatswellbediscussinginthefollowingsectionsIfyoustillfindthatyouhaveproblemswithworkingwithstructtagsyoushouldprobablyreadmoredocumentationaboutthembeforedivingintothenextsection

LinksDirectoryPrevioussectionTextfilesNextsectionJSON

XML

156

72JSONJSON(JavaScriptObjectNotation)isalightweightdataexchangelanguagewhichisbasedontextdescriptionItsadvantagesincludebeingself-descriptiveeasytounderstandetcEventhoughitisasubsetofJavaScriptJSONusesadifferenttextformattheresultbeingthatitcanbeconsideredasanindependentlanguageJSONbearssimilaritytoC-familylanguages

ThebiggestdifferencebetweenJSONandXMListhatXMLisacompletemarkuplanguagewhereasJSONisnotJSONissmallerandfasterthanXMLthereforeitsmucheasierandquickertoparseinbrowserswhichisoneofthereasonswhymanyopenplatformschoosetouseJSONastheirdataexchangeinterfacelanguage

SinceJSONisbecomingmoreandmoreimportantinwebdevelopmentletstakealookatthelevelofsupportGohasforJSONYoullfindthatGosstandardlibraryhasverygoodsupportforencodinganddecodingJSON

HereweuseJSONtorepresenttheexampleintheprevioussection

servers[serverNameShanghai_VPNserverIP127001serverNameBeijing_VPNserverIP127002]

TherestofthissectionwillusethisJSONdatatointroduceJSONconceptsinGo

ParseJSON

Parsetostruct

SupposewehavetheJSONintheaboveexampleHowcanweparsethisdataandmapittoastructinGoGoprovidesthefollowingfunctionforjustthispurpose

funcUnmarshal(data[]bytevinterface)error

Wecanusethisfunctionlikeso

packagemain

import(

encodingjson

fmt

)

typeServerstruct

ServerNamestring

ServerIPstring

typeServerslicestruct

Servers[]Server

funcmain()

varsServerslice

str=`servers[serverNameShanghai_VPNserverIP127001serverNameBeijing_VPNserverIP

127002]`

jsonUnmarshal([]byte(str)amps)

fmtPrintln(s)

JSON

157

IntheaboveexamplewedefinedacorrespondingstructsinGoforourJSONusingsliceforanarrayofJSONobjectsandfieldnameasourJSONkeysButhowdoesGoknowwhichJSONobjectcorrespondstowhichspecificstructfiledSupposewehaveakeycalledFooinJSONHowdowefinditscorrespondingfield

FirstGotriestofindthe(capitalised)exportedfieldwhosetagcontainsFooIfnomatchcanbefoundlookforthefieldwhosenameisFooIftherearestillnotmatcheslookforsomethinglikeFOOorFoOignoringcasesensitivity

YoumayhavenoticedthatallfieldsthataregoingtobeassignedshouldbeexportedandGoonlyassignsfieldsthatcanbefoundignoringallothersThiscanbeusefulifyouneedtodealwithlargechunksofJSONdatabutyouonlyaspecificsubsetofitthedatayoudontneedcaneasilybediscarded

ParsetointerfaceWhenweknowwhatkindofJSONtoexpectinadvancewecanparseittoaspecificstructButwhatifwedontknow

WeknowthataninterfacecanbeanythinginGosoitisthebestcontainertosaveourJSONofunknownformatTheJSONpackageusesmap[string]interfaceand[]interfacetosaveallkindsofJSONobjectsandarraysHereisalistofJSONmappingrelations

boolrepresentsJSONbooleansfloat64representsJSONnumbersstringrepresentsJSONstringsnilrepresentsJSONnull

SupposewehavethefollowingJSONdata

b=[]byte(`NameWednesdayAge6Parents[GomezMorticia]`)

NowweparsethisJSONtoaninterface

varfinterface

err=jsonUnmarshal(bampf)

Thefstoresamapwherekeysarestringsandvaluesareinterfaces

f=map[string]interface

NameWednesday

Age6

Parents[]interface

Gomez

Morticia

SohowdoweaccessthisdataTypeassertion

m=f(map[string]interface)

Afterassertedyoucanusethefollowingcodetoaccessdata

JSON

158

forkv=rangem

switchvv=v(type)

casestring

fmtPrintln(kisstringvv)

caseint

fmtPrintln(kisintvv)

casefloat64

fmtPrintln(kisfloat64vv)

case[]interface

fmtPrintln(kisanarray)

foriu=rangevv

fmtPrintln(iu)

default

fmtPrintln(kisofatypeIdontknowhowtohandle)

AsyoucanseewecannowparseJSONofanunknownformatthroughinterfaceandtypeassertion

TheaboveexampleistheofficialsolutionbuttypeassertingisnotalwaysconvenientSoIrecommendanopensourceprojectcalledsimplejsoncreatedandmaintainedbybitlyHereisanexampleofhowtousethisprojecttodealwithJSONofanunknownformat

jserr=NewJson([]byte(`

test

array[123]

int10

float5150

bignum9223372036854775807

stringsimplejson

booltrue

`))

arr_=jsGet(test)Get(array)Array()

i_=jsGet(test)Get(int)Int()

ms=jsGet(test)Get(string)MustString()

ItsnothardtoseehowconvenientthisisCheckouttherepositorytoseemoreinformationhttpsgithubcombitlygo-simplejson

ProducingJSONInmanysituationsweneedtoproduceJSONdataandrespondtoclientsInGotheJSONpackagehasafunctioncalledMarshaltodojustthat

funcMarshal(vinterface)([]byteerror)

SupposeweneedtoproduceaserverinformationlistWehavefollowingsample

JSON

159

packagemain

import(

encodingjson

fmt

)

typeServerstruct

ServerNamestring

ServerIPstring

typeServerslicestruct

Servers[]Server

funcmain()

varsServerslice

sServers=append(sServersServerServerNameShanghai_VPNServerIP127001)

sServers=append(sServersServerServerNameBeijing_VPNServerIP127002)

berr=jsonMarshal(s)

iferr=nil

fmtPrintln(jsonerrerr)

fmtPrintln(string(b))

Output

Servers[ServerNameShanghai_VPNServerIP127001ServerNameBeijing_VPNServerIP127002]

AsyouknowallfieldnamesarecapitalizedbutifyouwantyourJSONkeynamestostartwithalowercaseletteryoushouldusestructtagsOtherwiseGowillnotproducedataforinternalfields

typeServerstruct

ServerNamestring`jsonserverName`

ServerIPstring`jsonserverIP`

typeServerslicestruct

Servers[]Server`jsonservers`

AfterthismodificationwecanproducethesameJSONdataasbefore

HerearesomepointsyouneedtokeepinmindwhentryingtoproduceJSON

Fieldtagscontaining-willnotbeoutputtedIfatagcontainsacustomizednameGousesthisinsteadofthefieldnamelikeserverNameintheaboveexampleIfatagcontainsomitemptythisfieldwillnotbeoutputtedifitiszero-valueIfthefieldtypeisboolstringintint64etcanditstagcontainsstringGoconvertsthisfieldtoitscorrespondingJSONtype

Example

JSON

160

typeServerstruct

IDwillnotbeoutputed

IDint`json-`

ServerName2willbeconvertedtoJSONtype

ServerNamestring`jsonserverName`

ServerName2string`jsonserverName2string`

IfServerIPisemptyitwillnotbeoutputted

ServerIPstring`jsonserverIPomitempty`

s=Server

ID3

ServerName`Go10`

ServerName2`Go10`

ServerIP``

b_=jsonMarshal(s)

osStdoutWrite(b)

Output

serverNameGo10serverName2Go10

TheMarshalfunctiononlyreturnsdatawhenithassucceededsoherearesomepointsweneedtokeepinmind

JSONonlysupportsstringsaskeyssoifyouwanttoencodeamapitstypehastobemap[string]TwhereTisthetypeinGoTypeslikechannelcomplextypesandfunctionsarenotcapableofbeingencodedtoJSONDonottrytoencodecyclicdataitleadstoaninfiniterecursionIfthefieldisapointerGooutputsthedatathatitpointstoorelseoutputsnullifitpointstonil

InthissectionweintroducedhowtodecodeandencodeJSONdatainGoWealsolookedatonethird-partyprojectcalledsimplejsonwhichisusefulforparsingJSONorunknownformatTheseareallusefulconceptsfordevelopingwebapplicationsinGo

LinksDirectoryPrevioussectionXMLNextsectionRegexp

JSON

161

73RegexpRegularExpressions(Regexp)isacomplicatedbutpowerfultoolforpatternmatchingandtextmanipulationAlthoughitdoesnotperformaswellaspuretextmatchingitsmoreflexibleBasedonitssyntaxyoucanfilteralmostanykindoftextfromyoursourcecontentIfyouneedtocollectdatainwebdevelopmentitsnotdifficulttouseRegexptoretrievemeaningfuldata

GohastheregexppackagewhichprovidesofficialsupportforregexpIfyouvealreadyusedregexpinotherprogramminglanguagesyoushouldbefamiliarwithitNotethatGoimplementedRE2standardexceptforCFormoredetailsfollowthislinkhttpcodegooglecompre2wikiSyntax

Gosstringspackagecanactuallydomanyjobslikesearching(ContainsIndex)replacing(Replace)parsing(SplitJoin)etcanditsfasterthanRegexpHoweverthesearealltrivialoperationsIfyouwanttosearchacaseinsensitivestringRegexpshouldbeyourbestchoiceSoifthestringspackageissufficientforyourneedsjustuseitsinceitseasytouseandreadifyouneedtoperformmoreadvancedoperationsuseRegexp

IfyourecallformvalidationfromprevioussectionsweusedRegexptoverifythevalidityofuserinputinformationBeawarethatallcharactersareUTF-8LetslearnmoreabouttheGoregexppackage

MatchTheregexppackagehas3functionstomatchifitmatchesapatternthenitreturnstruereturningfalseotherwise

funcMatch(patternstringb[]byte)(matchedboolerrorerror)

funcMatchReader(patternstringrioRuneReader)(matchedboolerrorerror)

funcMatchString(patternstringsstring)(matchedboolerrorerror)

All3functionscheckifpatternmatchestheinputsourcereturningtrueifitmatchesHoweverifyourRegexhassyntaxerrorsitwillreturnanerrorThe3inputsourcesofthesefunctionsaresliceofbyteRuneReaderandstring

HereisanexampleofhowtoverifyanIPaddress

funcIsIP(ipstring)(bbool)

ifm_=regexpMatchString(^[0-9]13[0-9]13[0-9]13[0-9]13$ip)m

returnfalse

returntrue

AsyoucanseeusingpatternintheregexppackageisnotthatdifferentHeresonemoreexampleonverifyingwhetheruserinputisvalid

funcmain()

iflen(osArgs)==1

fmtPrintln(Usageregexp[string])

osExit(1)

elseifm_=regexpMatchString(^[0-9]+$osArgs[1])m

fmtPrintln(Number)

else

fmtPrintln(Notnumber)

IntheaboveexamplesweuseMatch(Reader|String)tocheckifcontentisvalidbuttheyarealleasytouse

Regexp

162

FilterMatchmodecanverifycontentbutitcannotcutfilterorcollectdatafromitIfyouwanttodothatyouhavetousethecomplexmodeofRegexp

LetssayweneedtowriteacrawlerHereisanexampleforwhenyoumustuseRegexptofilterandcutdata

packagemain

import(

fmt

ioioutil

nethttp

regexp

strings

)

funcmain()

resperr=httpGet(httpwwwbaiducom)

iferr=nil

fmtPrintln(httpgeterror)

deferrespBodyClose()

bodyerr=ioutilReadAll(respBody)

iferr=nil

fmtPrintln(httpreaderror)

return

src=string(body)

ConvertHTMLtagstolowercase

re_=regexpCompile(lt[Ss]+gt)

src=reReplaceAllStringFunc(srcstringsToLower)

RemoveSTYLE

re_=regexpCompile(ltstyle[Ss]+ltstylegt)

src=reReplaceAllString(src)

RemoveSCRIPT

re_=regexpCompile(ltscript[Ss]+ltscriptgt)

src=reReplaceAllString(src)

RemoveallHTMLcodeinanglebracketsandreplacewithnewline

re_=regexpCompile(lt[Ss]+gt)

src=reReplaceAllString(srcn)

Removecontinuousnewline

re_=regexpCompile(s2)

src=reReplaceAllString(srcn)

fmtPrintln(stringsTrimSpace(src))

InthisexampleweuseCompileasthefirststepforcomplexmodeItverifiesthatyourRegexsyntaxiscorrectthenreturnsaRegexpforparsingcontentinotheroperations

HerearesomefunctionstoparseyourRegexpsyntax

funcCompile(exprstring)(Regexperror)

funcCompilePOSIX(exprstring)(Regexperror)

funcMustCompile(strstring)Regexp

funcMustCompilePOSIX(strstring)Regexp

Regexp

163

ThedifferencebetweenComplePOSIXandCompileisthattheformerhastousePOSIXsyntaxwhichisleftmostlongestsearchandthelatterisonlyleftmostsearchForinstanceforRegexp[a-z]24andcontentaa09aaa88aaaaCompilePOSIXreturnsaaaabutCompilereturnsaaMustprefixmeanspanicwhentheRegexpsyntaxisnotcorrectreturningerrorotherwise

NowthatweknowhowtocreateanewRegexpletsseehowthemethodsprovidedbythisstructcanhelpustooperateoncontent

func(reRegexp)Find(b[]byte)[]byte

func(reRegexp)FindAll(b[]bytenint)[][]byte

func(reRegexp)FindAllIndex(b[]bytenint)[][]int

func(reRegexp)FindAllString(sstringnint)[]string

func(reRegexp)FindAllStringIndex(sstringnint)[][]int

func(reRegexp)FindAllStringSubmatch(sstringnint)[][]string

func(reRegexp)FindAllStringSubmatchIndex(sstringnint)[][]int

func(reRegexp)FindAllSubmatch(b[]bytenint)[][][]byte

func(reRegexp)FindAllSubmatchIndex(b[]bytenint)[][]int

func(reRegexp)FindIndex(b[]byte)(loc[]int)

func(reRegexp)FindReaderIndex(rioRuneReader)(loc[]int)

func(reRegexp)FindReaderSubmatchIndex(rioRuneReader)[]int

func(reRegexp)FindString(sstring)string

func(reRegexp)FindStringIndex(sstring)(loc[]int)

func(reRegexp)FindStringSubmatch(sstring)[]string

func(reRegexp)FindStringSubmatchIndex(sstring)[]int

func(reRegexp)FindSubmatch(b[]byte)[][]byte

func(reRegexp)FindSubmatchIndex(b[]byte)[]int

These18methodsincludeidenticalfunctionsfordifferentinputsources(byteslicestringandioRuneReader)sowecanreallysimplifythislistbyignoringinputsourcesasfollows

func(reRegexp)Find(b[]byte)[]byte

func(reRegexp)FindAll(b[]bytenint)[][]byte

func(reRegexp)FindAllIndex(b[]bytenint)[][]int

func(reRegexp)FindAllSubmatch(b[]bytenint)[][][]byte

func(reRegexp)FindAllSubmatchIndex(b[]bytenint)[][]int

func(reRegexp)FindIndex(b[]byte)(loc[]int)

func(reRegexp)FindSubmatch(b[]byte)[][]byte

func(reRegexp)FindSubmatchIndex(b[]byte)[]int

Codesample

Regexp

164

packagemain

import(

fmt

regexp

)

funcmain()

a=IamlearningGolanguage

re_=regexpCompile([a-z]24)

Findthefirstmatch

one=reFind([]byte(a))

fmtPrintln(Findstring(one))

Findallmatchesandsavetoaslicenlessthan0meansreturnallmatchesindicateslengthofsliceifit

sgreaterthan0

all=reFindAll([]byte(a)-1)

fmtPrintln(FindAllall)

Findindexoffirstmatchstartandendposition

index=reFindIndex([]byte(a))

fmtPrintln(FindIndexindex)

Findindexofallmatchesthendoessamejobasabove

allindex=reFindAllIndex([]byte(a)-1)

fmtPrintln(FindAllIndexallindex)

re2_=regexpCompile(am()lang())

Findfirstsubmatchandreturnarraythefirstelementcontainsallelementsthesecondelementcontainsthe

resultoffirst()thethirdelementcontainstheresultofsecond()

Output

thefirstelementamlearningGolanguage

thesecondelementlearningGonoticespaceswillbeoutputedaswell

thethirdelementuage

submatch=re2FindSubmatch([]byte(a))

fmtPrintln(FindSubmatchsubmatch)

for_v=rangesubmatch

fmtPrintln(string(v))

SameasFindIndex()

submatchindex=re2FindSubmatchIndex([]byte(a))

fmtPrintln(submatchindex)

FindAllSubmatchfindallsubmatches

submatchall=re2FindAllSubmatch([]byte(a)-1)

fmtPrintln(submatchall)

FindAllSubmatchIndexfindindexofallsubmatches

submatchallindex=re2FindAllSubmatchIndex([]byte(a)-1)

fmtPrintln(submatchallindex)

AswevepreviouslymentionedRegexpalsohas3methodsformatchingTheydotheexactsamethingastheexportedfunctionsInfactthoseexportedfunctionsactuallycallthesemethodsunderthehood

func(reRegexp)Match(b[]byte)bool

func(reRegexp)MatchReader(rioRuneReader)bool

func(reRegexp)MatchString(sstring)bool

NextletsseehowtoreplacestringsusingRegexp

Regexp

165

func(reRegexp)ReplaceAll(srcrepl[]byte)[]byte

func(reRegexp)ReplaceAllFunc(src[]bytereplfunc([]byte)[]byte)[]byte

func(reRegexp)ReplaceAllLiteral(srcrepl[]byte)[]byte

func(reRegexp)ReplaceAllLiteralString(srcreplstring)string

func(reRegexp)ReplaceAllString(srcreplstring)string

func(reRegexp)ReplaceAllStringFunc(srcstringreplfunc(string)string)string

Theseareusedinthecrawlingexamplesowewillnotexplainanyfurtherhere

LetstakealookatthedefinitionofExpand

func(reRegexp)Expand(dst[]bytetemplate[]bytesrc[]bytematch[]int)[]byte

func(reRegexp)ExpandString(dst[]bytetemplatestringsrcstringmatch[]int)[]byte

SohowdoweuseExpand

funcmain()

src=[]byte(`

callhelloalice

hellobob

callhelloeve

`)

pat=regexpMustCompile(`(m)(call)s+(Pltcmdgtw+)s+(Pltarggt+)s$`)

res=[]byte

for_s=rangepatFindAllSubmatchIndex(src-1)

res=patExpand(res[]byte($cmd($arg)n)srcs)

fmtPrintln(string(res))

AtthispointyouvelearntthewholeregexppackageinGoIhopethatyoucanunderstandmorebystudyingexamplesofkeymethodssothatyoucandosomethinginterestingonyourown

LinksDirectoryPrevioussectionJSONNextsectionTemplates

Regexp

166

74Templates

WhatisatemplateHopefullyyoureawareoftheMVC(ModelViewController)designmodelwheremodelsprocessdataviewsshowtheresultsandfinallycontrollershandleuserrequestsForviewsmanydynamiclanguagesgeneratedatabywritingcodeinstaticHTMLfilesForinstanceJSPisimplementedbyinsertinglt==gtPHPbyinsertingltphpgtetc

Thefollowingdemonstratesthetemplatemechanism

Figure71Templatemechanism

MostofthecontentthatwebapplicationsrespondtoclientswithisstaticandthedynamicpartsareusuallyverysmallForexampleifyouneedtodisplayalistuserswhohavevisitedapageonlytheusernamewouldbedynamicThestyleofthelistremainsthesameAsyoucanseetemplatesareusefulforreusingstaticcontent

TemplatinginGoInGowehavethetemplatepackagetohelphandletemplatesWecanusefunctionslikeParseParseFileandExecutetoloadtemplatesfromplaintextorfilesthenevaluatethedynamicpartsasshowninfigure71

Example

funchandler(whttpResponseWriterrhttpRequest)

t=templateNew(sometemplate)Createatemplate

t_=tParseFiles(tmplwelcomehtmlnil)Parsetemplatefile

user=GetUser()Getcurrentuserinfomration

tExecute(wuser)merge

AsyoucanseeitsveryeasytouseloadandrenderdataintemplatesinGojustasinotherprogramminglanguages

Forthesakeofconveniencewewillusethefollowingrulesinourexamples

UseParsetoreplaceParseFilesbecauseParsecantestcontentdirectlyfromstringssowedontneedanyextrafilesUsemainforeveryexampleanddonotusehandlerUseosStdouttoreplacehttpResponseWritersinceosStdoutalsoimplementstheioWriterinterface

InsertingdataintoatemplateWevejustshownyouhowtoparseandrendertemplatesLetstakeitonestepfurtherandrenderdatatoourtemplatesEverytemplateisanobjectinGosohowdoweinsertfieldstotemplates

Fields

InGoEveryfieldthatyouintendtoberenderedwithinatemplateshouldbeputinsideofisshorthandforthecurrentobjectwhichissimilartoitsJavaorC++counterpartIfyouwanttoaccessthefieldsofthecurrentobjectyoushoulduseFieldNameNoticethatonlyexportedfieldscanbeaccessedintemplatesHereisanexample

Templates

167

packagemain

import(

htmltemplate

os

)

typePersonstruct

UserNamestring

funcmain()

t=templateNew(fieldnameexample)

t_=tParse(helloUserName)

p=PersonUserNameAstaxie

tExecute(osStdoutp)

TheaboveexampleoutputshelloAstaxiecorrectlybutifwemodifyourstructalittlebitthefollowingerroremerges

typePersonstruct

UserNamestring

emailstringFieldisnotexported

t_=tParse(helloUserNameemail)

ThispartofthecodewillnotbecompiledbecausewetrytoaccessafieldthathasnotbeenexportedHoweverifwetrytouseafieldthatdoesnotexistGosimplyoutputsanemptystringinsteadofanerror

IfyouprintinatemplateGooutputsaformattedstringofthisobjectcallingfmtunderthecovers

Nestedfields

WeknowhowtooutputafieldnowWhatifthefieldisanobjectanditalsohasitsownfieldsHowdoweprintthemallinoneloopWecanusewithhelliphellipendandrangehellipendforexactlythatpurpose

rangejustlikerangeinGowithletsyouwritethesameobjectnameonceanduseasshorthandforit(SimilartowithinVB)

Moreexamples

Templates

168

packagemain

import(

htmltemplate

os

)

typeFriendstruct

Fnamestring

typePersonstruct

UserNamestring

Emails[]string

Friends[]Friend

funcmain()

f1=FriendFnameminuxma

f2=FriendFnamexushiwei

t=templateNew(fieldnameexample)

t_=tParse(`helloUserName

rangeEmails

anemail

end

withFriends

range

myfriendnameisFname

end

end

`)

p=PersonUserNameAstaxie

Emails[]stringastaxiebeegomeastaxiegmailcom

Friends[]Friendampf1ampf2

tExecute(osStdoutp)

ConditionsIfyouneedtocheckforconditionsintemplatesyoucanusetheif-elsesyntaxjustlikeyoudoinregularGoprogramsIfthepipelineisemptythedefaultvalueofifisfalseThefollowingexampleshowshowtouseif-elseintemplates

packagemain

import(

os

texttemplate

)

funcmain()

tEmpty=templateNew(templatetest)

tEmpty=templateMust(tEmptyParse(Emptypipelineifdemoif``willnotbeoutputtedendn))

tEmptyExecute(osStdoutnil)

tWithValue=templateNew(templatetest)

tWithValue=templateMust(tWithValueParse(Notemptypipelineifdemoif`anything`willbeoutputtede

ndn))

tWithValueExecute(osStdoutnil)

tIfElse=templateNew(templatetest)

tIfElse=templateMust(tIfElseParse(if-elsedemoif`anything`ifpartelseelsepartendn))

tIfElseExecute(osStdoutnil)

Asyoucanseeitseasytouseif-elseintemplates

Templates

169

AttentionYouCANNOTuseconditionalexpressionsinifforinstanceMail==astaxiegmailcomOnlybooleanvaluesareacceptable

pipelines

Unixusersshouldbefamiliarwiththepipeoperatorlikels|grepbeegoThiscommandfiltersfilesandonlyshowsthosethatcontainthewordbeegoOnethingthatIlikeaboutGotemplatesisthattheysupportpipesAnythingincanbethedataofpipelinesThee-mailweusedabovecanrenderourapplicationvulnerabletoXSSattacksHowcanweaddressthisissueusingpipes

|html

Wecanusethismethodtoescapethee-mailbodytoHTMLItsquitesimilartowritingaUnixcommandanditisconvenientforuseintemplatefunctions

TemplatevariablesSometimesweneedtouselocalvariablesintemplatesWecanusethemwiththewithrangeandifkeywordsandtheirscopeisbetweenthesekeywordsandendHeresanexampleofdeclaringaglobalvariable

$variable=pipeline

Moreexamples

with$x=output|printfq$xend

with$x=outputprintfq$xend

with$x=output$x|printfqend

Templatefunctions

GousesthefmtpackagetoformatoutputintemplatesbutsometimesweneedtodosomethingelseForexampleconsiderthefollowingscenarioletssaywewanttoreplacewithatinoure-mailaddresslikeastaxieatbeegomeAtthispointwehavetowriteacustomizedfunction

EverytemplatefunctionhasauniquenameandisassociatedwithonefunctioninyourGoprogramasfollows

typeFuncMapmap[string]interface

SupposewehaveanemailDealtemplatefunctionassociatedwithitsEmailDealWithcounterpartfunctioninourGoprogramWecanusethefollowingcodetoregisterthisfunction

t=tFuncs(templateFuncMapemailDealEmailDealWith)

EmailDealWithdefinition

funcEmailDealWith(argshellipinterface)string

Example

Templates

170

packagemain

import(

fmt

htmltemplate

os

strings

)

typeFriendstruct

Fnamestring

typePersonstruct

UserNamestring

Emails[]string

Friends[]Friend

funcEmailDealWith(argsinterface)string

ok=false

varsstring

iflen(args)==1

sok=args[0](string)

ifok

s=fmtSprint(args)

findthesymbol

substrs=stringsSplit(s)

iflen(substrs)=2

returns

replacethebyat

return(substrs[0]+at+substrs[1])

funcmain()

f1=FriendFnameminuxma

f2=FriendFnamexushiwei

t=templateNew(fieldnameexample)

t=tFuncs(templateFuncMapemailDealEmailDealWith)

t_=tParse(`helloUserName

rangeEmails

anemails|emailDeal

end

withFriends

range

myfriendnameisFname

end

end

`)

p=PersonUserNameAstaxie

Emails[]stringastaxiebeegomeastaxiegmailcom

Friends[]Friendampf1ampf2

tExecute(osStdoutp)

Hereisalistofbuilt-intemplatefunctions

Templates

171

varbuiltins=FuncMap

andand

callcall

htmlHTMLEscaper

indexindex

jsJSEscaper

lenlength

notnot

oror

printfmtSprint

printffmtSprintf

printlnfmtSprintln

urlqueryURLQueryEscaper

MustThetemplatepackagehasafunctioncalledMustwhichisforvalidatingtemplateslikethematchingofbracescommentsandvariablesLetstakealookatanexampleofMust

packagemain

import(

fmt

texttemplate

)

funcmain()

tOk=templateNew(first)

templateMust(tOkParse(somestatictextandacomment))

fmtPrintln(ThefirstoneparsedOK)

templateMust(templateNew(second)Parse(somestatictextName))

fmtPrintln(ThesecondoneparsedOK)

fmtPrintln(Thenextoneoughttofail)

tErr=templateNew(checkparseerrorwithMust)

templateMust(tErrParse(somestatictextName))

Output

ThefirstoneparsedOK

ThesecondoneparsedOK

Thenextoneoughttofail

panictemplatecheckparseerrorwithMust1unexpectedincommand

NestedtemplatesJustlikeinmostwebapplicationscertainpartsoftemplatescanbereusedacrossothertemplatesliketheheadersandfootersofablogWecandeclareheadercontentandfooterassub-templatesanddeclaretheminGousingthefollowingsyntax

definesub-templatecontentend

Thesub-templateiscalledusingthefollowingsyntax

templatesub-template

Templates

172

Heresacompleteexamplesupposingthatwehavethefollowingthreefilesheadertmplcontenttmplandfootertmplinthefoldertemplateswewillreadthefolderandstorethefilenamesinastringarraywhichwewillthenusetoparsefiles

Maintemplate

raw

headertmpl

defineheader

lthtmlgt

ltheadgt

lttitlegtSomethingherelttitlegt

ltheadgt

ltbodygt

end

contenttmpl

definecontent

templateheader

lth1gtNestedherelth1gt

ltulgt

ltligtNestedusagltligt

ltligtCalltemplateltligt

ltulgt

templatefooter

end

footertmpl

definefooter

ltbodygt

lthtmlgt

end

Whenusingsubtemplatingmakesurethatyouhaveparsedeachsubtemplatefile

otherwisethecompilerwouldntunderstandwhattosubstitutewhenitreadsthetemplateheader

endraw

Code

Templates

173

packagemain

import(

fmt

os

ioioutil

texttemplate

)

vartemplatestemplateTemplate

funcmain()

varallFiles[]string

fileserr=ioutilReadDir(templates)

iferr=nil

fmtPrintln(err)

for_file=rangefiles

filename=fileName()

ifstringsHasSuffix(filenametmpl)

allFiles=append(allFilestemplates+filename)

templateserr=templateParseFiles(allFiles)parsesalltmplfilesinthetemplatesfolder

s1=templatesLookup(headertmpl)

s1ExecuteTemplate(osStdoutheadernil)

fmtPrintln()

s2=templatesLookup(contenttmpl)

s2ExecuteTemplate(osStdoutcontentnil)

fmtPrintln()

s3=templatesLookup(footertmpl)

s3ExecuteTemplate(osStdoutfooternil)

fmtPrintln()

s3Execute(osStdoutnil)

HerewecanseethattemplateParseFilesparsesallnestedtemplatesintocacheandthateverytemplatedefinedbydefineareindependentofeachotherTheyarepersistedinsomethinglikeamapwherethetemplatenamesarekeysandthevaluesarethetemplatebodiesWecanthenuseExecuteTemplatetoexecutethecorrespondingsub-templatessothattheheaderandfooterareindependentandcontentcontainsthembothNotethatifwetrytoexecutes1Executenothingwillbeoutputtedbecausethereisnodefaultsub-templateavailable

Whenyoudontwanttousedefinethenyoucanjustcreateatextfilewiththenameofthesubtemplateforinstance_headtmplisasubtemplatewhichyoulluseacrossyourprojectthencreatethisfileinthetemplatesfolderandusethenormalsyntaxLookupcacheisbasicallycreatedsothatyoudontreadthefileeverytimeyouservearequestbecauseifyoudothenyouarewastingalotofresourcesforreadingafilewhichwontchangeunlessthecodebaseisbeingrewrittenitdoesntmakesensetoparsethetemplatefilesduringeachHTTPGETrequestsothetechniqueisusedwhereweparsethefilesonceandthendoaLookup()onthecachetoexecutethetemplatewhenweneedittodisplaydata

Templatesinonesetknoweachotherbutyoumustparsethemforeverysingleset

Sometimesyouwanttocontextualizetemplatesforinstanceyouhavea_headhtmlyoumighthaveaheaderwhosvalueyouhavetopopulatebasedonwhichdatayouareloadingforinstanceforatodolistmanageryoucanhavethreecategoriespendingcompleteddeletedforthissupposeyouhaveanifstatementlikethis

lttitlegtifeqNavigationpendingTasks

elseifeqNavigationcompletedCompleted

elseifeqNavigationdeletedDeleted

elseifeqNavigationeditEdit

end

lttitlegt

Templates

174

NoteGotemplatesfollowthePolishnotationwhileperformingthecomparisonwhereyougivetheoperatorfirstandthecomparisonvalueandthevaluetobecomparedwithTheelseifpartisprettystraightforward

Typicallyweusearangeoperatortoloopthroughthecontextvariablewhichwepasstothetemplatewhileexecutionlikethis

presentinviewspackage

context=dbGetTasks(pending)truewhenyouwantnondeletednotes

homeTemplateExecute(wcontext)

Wegetthecontextobjectfromthedatabaseasastructobjectthedefinitionisasbelow

Taskisthestructusedtoidentifytasks

typeTaskstruct

Idint

Titlestring

Contentstring

Createdstring

Contextisthestructpassedtotemplates

typeContextstruct

Tasks[]Task

Navigationstring

Searchstring

Messagestring

presentindatabasepackage

vartask[]typesTask

varcontexttypesContext

context=typesContextTaskstaskNavigationstatus

Thislineisinthedatabasepackagewherethecontextisreturnedbacktotheview

WeusethetaskarrayandtheNavigationinourtemplateswesawhowweusetheNavigationinthetemplatewellseehowwellusetheactualtaskarrayinourtemplate

HereintheifTaskswefirstcheckiftheTasksfieldofourcontextobjectwhichwepassedtothetemplatewhileexecutingisemptyornotIfitisnotemptythenwewillrangethroughthatarraytopopulatethetitleandcontentofTaskThebelowexampleisveryimportantwhenitcomestoloopingthroughanarrayinatemplatewestartwiththeRangeoperatorthenwecangiveanymemberofthatstructasNamemyTaskstructurehasaTitleandaContent(pleasenotethecapitalTandCtheyareexportednamesandtheyneedtobecapitalisedunlessyouwanttomakethemprivate)

rangeTasks

Title

Content

end

ThisblockofcodewillprinteachtitleandcontentoftheTaskarrayBelowisafullexamplefromgithubcomthewhitetulipTaskshomehtmltemplate

Templates

175

ltdivclass=timelinegt

ifTasksrangeTasks

ltdivclass=notegt

ltpclass=noteHeadinggtTitleltpgt

lthrgt

ltpclass=noteContentgtContentltpgt

ltulgt

ltspangt

ltdivgt

endelse

ltdivclass=notegt

ltpclass=noteHeadinggtNoTaskshereltpgt

ltpclass=notefootergt

Createnewtaskltbuttonclass=floating-action-icon-addgthereltbuttongtltpgt

ltdivgt

end

SummaryInthissectionyoulearnedhowtocombinedynamicdatawithtemplatesusingtechniquesincludingprintingdatainloopstemplatefunctionsandnestedtemplatesBylearningabouttemplateswecanconcludediscussingtheV(View)partoftheMVCarchitectureInthefollowingchapterswewillcovertheM(Model)andC(Controller)aspectsofMVC

LinksDirectoryPrevioussectionRegexpNextsectionFiles

Templates

176

75FilesFilesareessentialobjectsoneverysinglecomputerdeviceItwontcomeasanysurprisetoyouthatwebapplicationsalsomakeheavyuseofthemInthissectionweregoingtolearnhowtooperateonfilesinGo

DirectoriesInGomostofthefileoperationfunctionsarelocatedintheospackageHerearesomedirectoryfunctions

funcMkdir(namestringpermFileMode)error

Createadirectorywithnamepermisthedirectorypermissionsie0777

funcMkdirAll(pathstringpermFileMode)error

Createmultipledirectoriesaccordingtopathlikeastaxietest1test2

funcRemove(namestring)error

RemovesdirectorywithnameReturnserrorifitsnotadirectoryornotempty

funcRemoveAll(pathstring)error

RemovesmultipledirectoriesaccordingtopathDirectorieswillnotbedeletedifpathisasinglepath

Codesample

packagemain

import(

fmt

os

)

funcmain()

osMkdir(astaxie0777)

osMkdirAll(astaxietest1test20777)

err=osRemove(astaxie)

iferr=nil

fmtPrintln(err)

osRemoveAll(astaxie)

Files

Createandopenfiles

Therearetwofunctionsforcreatingfiles

funcCreate(namestring)(fileFileerrError)

Createafilewithnameandreturnaread-writablefileobjectwithpermission0666

funcNewFile(fduintptrnamestring)File

Createafileandreturnafileobject

Therearealsotwofunctionstoopenfiles

funcOpen(namestring)(fileFileerrError)

Files

177

Opensafilecallednamewithread-onlyaccesscallingOpenFileunderthecovers

funcOpenFile(namestringflagintpermuint32)(fileFileerrError)

Opensafilecallednameflagisopenmodelikeread-onlyread-writeetcpermarethefilepermissions

WritefilesFunctionsforwritingfiles

func(fileFile)Write(b[]byte)(ninterrError)

Writebytetypecontenttoafile

func(fileFile)WriteAt(b[]byteoffint64)(ninterrError)

Writebytetypecontenttoaspecificpositionofafile

func(fileFile)WriteString(sstring)(retinterrError)

Writeastringtoafile

Codesample

packagemain

import(

fmt

os

)

funcmain()

userFile=astaxietxt

fouterr=osCreate(userFile)

iferr=nil

fmtPrintln(userFileerr)

return

deferfoutClose()

fori=0ilt10i++

foutWriteString(Justatestrn)

foutWrite([]byte(Justatestrn))

ReadfilesFunctionsforreadingfiles

func(fileFile)Read(b[]byte)(ninterrError)

Readdatatob

func(fileFile)ReadAt(b[]byteoffint64)(ninterrError)

Readdatafrompositionofftob

Codesample

Files

178

packagemain

import(

fmt

os

)

funcmain()

userFile=asatxietxt

flerr=osOpen(userFile)

iferr=nil

fmtPrintln(userFileerr)

return

deferflClose()

buf=make([]byte1024)

for

n_=flRead(buf)

if0==n

break

osStdoutWrite(buf[n])

DeletefilesGousesthesamefunctionforremovingfilesanddirectories

funcRemove(namestring)Error

Removeafileordirectorycalledname(anameendingwithsignifiesthatitsadirectory)

LinksDirectoryPrevioussectionTemplatesNextsectionStrings

Files

179

76StringsOnthewebalmosteverythingwesee(includinguserinputsdatabaseaccessetc)isrepresentedbystringsTheyareaveryimportantpartofwebdevelopmentInmanycaseswealsoneedtosplitjoinconvertandotherwisemanipulatestringsInthissectionwearegoingtointroducethestringsandstrconvpackagesfromtheGostandardlibrary

stringsThefollowingfunctionsarefromthestringspackageSeetheofficialdocumentationformoredetails

funcContains(ssubstrstring)bool

Checkifstringscontainsstringsubstrreturnsabooleanvalue```GofmtPrintln(stringsContains(seafoodfoo))fmtPrintln(stringsContains(seafoodbar))fmtPrintln(stringsContains(seafood))fmtPrintln(stringsContains())

Outputtruefalsetruetrue

-funcJoin(a[]stringsepstring)string

Combinestringsfromslicewithseparator`sep`

```Go

s=[]stringfoobarbaz

fmtPrintln(stringsJoin(s))

Outputfoobarbaz

funcIndex(ssepstring)int

Findindexofsepinstringsreturns-1ifitsnotfound

fmtPrintln(stringsIndex(chickenken))

fmtPrintln(stringsIndex(chickendmr))

Output4

-1

funcRepeat(sstringcountint)string

Repeatstringscounttimes

fmtPrintln(ba+stringsRepeat(na2))

Outputbanana

funcReplace(soldnewstringnint)string

ReplacestringoldwithstringnewinstringsnisthenumberofreplacementsIfnislessthan0replaceallinstances

fmtPrintln(stringsReplace(oinkoinkoinkkky2))

fmtPrintln(stringsReplace(oinkoinkoinkoinkmoo-1))

Outputoinkyoinkyoink

moomoomoo

funcSplit(ssepstring)[]string

Splitstringswithseparatorsepintoaslice

Strings

180

fmtPrintf(qnstringsSplit(abc))

fmtPrintf(qnstringsSplit(amanaplanacanalpanamaa))

fmtPrintf(qnstringsSplit(xyz))

fmtPrintf(qnstringsSplit(BernardoOHiggins))

Output[abc]

[manplancanalpanama]

[xyz]

[]

funcTrim(sstringcutsetstring)string

Removecutsetofstringsifitsleftmostorrightmost

fmtPrintf([q]stringsTrim(Achtung))

Output[Achtung]

funcFields(sstring)[]string

Removespaceitemsandsplitstringwithspaceintoaslice

fmtPrintf(FieldsareqstringsFields(foobarbaz))

OutputFieldsare[foobarbaz]

strconvThefollowingfunctionsarefromthestrconvpackageAsusualpleaseseeofficialdocumentationformoredetails

Appendseriesconvertdatatostringandappendtocurrentbyteslice```Gopackagemain

import(fmtstrconv)

funcmain()str=make([]byte0100)str=strconvAppendInt(str456710)str=strconvAppendBool(strfalse)str=strconvAppendQuote(strabcdefg)str=strconvAppendQuoteRune(str单)fmtPrintln(string(str))

-Formatseriesconvertotherdatatypesintostring

```Go

packagemain

import(

fmt

strconv

)

funcmain()

a=strconvFormatBool(false)

b=strconvFormatFloat(12323g1264)

c=strconvFormatInt(123410)

d=strconvFormatUint(1234510)

e=strconvItoa(1023)

fmtPrintln(abcde)

Parseseriesconvertstringstoothertypes```Gopackagemain

import(fmtstrconv)

funcmain()aerr=strconvParseBool(false)iferr=nilfmtPrintln(err)berr=strconvParseFloat(1232364)iferr=nilfmtPrintln(err)cerr=strconvParseInt(12341064)iferr=nilfmtPrintln(err)derr=strconvParseUint(123451064)iferr=nilfmtPrintln(err)eerr=strconvItoa(1023)iferr=nilfmtPrintln(err)fmtPrintln(abcde)```

Strings

181

LinksDirectoryPrevioussectionFilesNextsectionSummary

Strings

182

77SummaryInthischapterweintroducedsometextprocessingtoolslikeXMLJSONRegexpandwealsotalkedabouttemplatesXMLandJSONaredataexchangetoolsYoucanrepresentalmostanykindofinformationusingthesetwoformatsRegexpisapowerfultoolforsearchingreplacingandcuttingtextcontentWithtemplatesyoucaneasilycombinedynamicdatawithstaticfilesThesetoolsareallusefulwhendevelopingwebapplicationsIhopethatyounowhaveabetterunderstandingofprocessinganddisplayingcontentusingGo

LinksDirectoryPrevioussectionStringsNextchapterWebservices

Summary

183

8WebservicesWebservicesallowyouuseformatslikeXMLorJSONtoexchangeinformationthroughHTTPForexampleifyouwanttoknowtheweatherinShanghaitomorrowthecurrentsharepriceofAppleorproductinformationonAmazonyoucanwriteapieceofcodetofetchthatinformationfromopenplatformsInGothisprocesscanbecomparabletocallingalocalfunctionandgettingitsreturnvalue

ThekeypointisthatwebservicesareplatformindependentThisallowsyoutodeployyourapplicationsonLinuxandinteractwithASPNETapplicationsinWindowsforexamplejustlikeyouwouldnthaveaprobleminteractingwithJSPonFreeBSDeither

TheRESTarchitectureandSOAPprotocolarethemostpopularstylesinwhichwebservicescanbeimplementedthesedays

RESTrequestsareprettystraightforwardbecauseitsbasedonHTTPEveryRESTrequestisactuallyanHTTPrequestandservershandlerequestsusingdifferentmethodsBecausemanydevelopersarefamiliarwithHTTPalreadyRESTshouldfeellikeitsalreadyintheirbackpocketsWearegoingtoshowyouhowtoimplementRESTinGoinsection83SOAPisastandardforcross-networkinformationtransmissionandremotecomputerfunctioncallslaunchedbyW3CTheproblemwithSOAPisthatitsspecificationisverylongandcomplicatedanditsstillgettinglongerGobelievesthatthingsshouldbesimplesowerenotgoingtotalkaboutSOAPFortunatelyGoprovidessupportforRPC(RemoteProcedureCalls)whichhasgoodperformanceandiseasytodevelopwithsowewillintroducehowtoimplementRPCinGoinsection84

GoistheClanguageofthe21stcenturyaspiringtobesimpleyetperformantWiththesequalitiesinmindwellintroduceyoutosocketprogramminginGoinsection81Nowadaysmanyreal-timeserversusesocketstoovercomethelowperformanceofHTTPAlongwiththerapiddevelopmentofHTML5websocketsarenowusedbymanywebbasedgamecompaniesandwewilltalkaboutthismoreinsection82

LinksDirectoryPreviousChapterChapter7SummaryNextsectionSockets

Webservices

184

81SocketsSomenetworkapplicationdeveloperssaythatthelowerapplicationlayersareallaboutsocketprogrammingThismaynotbetrueforallcasesbutmanymodernwebapplicationsdoindeedusesocketstotheiradvantageHaveyoueverwonderedhowbrowserscommunicatewithwebserverswhenyouaresurfingtheinternetOrHowMSNconnectsyouandyourfriendstogetherinachatroomrelayingeachmessageinreal-timeManyservicesliketheseusesocketstotransferdataAsyoucanseesocketsoccupyanimportantpositioninnetworkprogrammingtodayandweregoingtolearnaboutusingsocketsinGointhissection

WhatisasocketSocketsoriginatefromUnixandgiventhebasiceverythingisafilephilosophyofUnixeverythingcanbeoperatedonwithopen-gtwriteread-gtcloseSocketsareoneimplementationofthisphilosophySocketshaveafunctioncallforopeningasocketjustlikeyouwouldopenafileThisreturnsanintdescriptorofthesocketwhichcanthenbeusedforoperationslikecreatingconnectionstransferringdataetc

Twotypesofsocketsthatarecommonlyusedarestreamsockets(SOCK_STREAM)anddatagramsockets(SOCK_DGRAM)Streamsocketsareconnection-orientedlikeTCPwhiledatagramsocketsdonotestablishconnectionslikeUDP

SocketcommunicationBeforeweunderstandhowsocketscommunicatewithoneanotherweneedtofigureouthowtomakesurethateverysocketisuniqueotherwiseestablishingareliablecommunicationchannelisalreadyoutofthequestionWecangiveeveryprocessauniquePIDwhichservesourpurposelocallyhoweverthatsnotabletoworkoveranetworkFortunatelyTCPIPhelpsussolvethisproblemTheIPaddressesofthenetworklayerareuniqueinanetworkofhostsandprotocol+portisalsouniqueamonghostapplicationsSowecanusetheseprinciplestomakesocketswhichareunique

Figure81networkprotocollayers

ApplicationsthatarebasedonTCPIPallusesocketAPIsintheircodeinonewayoranotherGiventhatnetworkedapplicationsarebecomingmoreandmoreprevalentinthemoderndayitsnowondersomedevelopersaresayingthateverythingisaboutsockets

SocketbasicknowledgeWeknowthatsocketshavetwotypeswhichareTCPsocketsandUDPsocketsTCPandUDPareprotocolsandasmentionedwealsoneedanIPaddressandportnumbertohaveauniquesocket

IPv4TheglobalinternetusesTCPIPasitsprotocolwhereIPisthenetworklayerandacorepartofTCPIPIPv4signifiesthatitsversionis4infrastructuredevelopmenttodatehasspannedover30years

ThenumberofbitsinanIPv4addressis32whichmeansthat2^32devicesareabletouniquelyconnecttotheinternetDuetotherapiddevelopoftheinternetIPaddressesarealreadyrunningoutofstockinrecentyears

Addressformat127001172122121111

IPv6

Sockets

185

IPv6isthenextversionornextgenerationoftheinternetItsbeingdevelopedforsolvingmanyoftheproblemsinherentwithIPv4DevicesusingIPv6haveanaddressthats128bitslongsowellneverneedtoworryaboutashortageofuniqueaddressesToputthisintoperspectiveyoucouldhavemorethan1000IPaddressesforeverysquaremeteronearthwithIPv6Otherproblemslikepeertopeerconnectionservicequality(QoS)securitymultiplebroadcastetcarealsobeimproved

Addressformat2002c0e882e7000c0e882e7

IPtypesinGo

ThenetpackageinGoprovidesmanytypesfunctionsandmethodsfornetworkprogrammingThedefinitionofIPasfollows

typeIP[]byte

FunctionParseIP(sstring)IPistoconverttheIPv4orIPv6formattoanIP

packagemain

import(

net

os

fmt

)

funcmain()

iflen(osArgs)=2

fmtFprintf(osStderrUsagesip-addrnosArgs[0])

osExit(1)

name=osArgs[1]

addr=netParseIP(name)

ifaddr==nil

fmtPrintln(Invalidaddress)

else

fmtPrintln(TheaddressisaddrString())

osExit(0)

ItreturnsthecorrespondingIPformatforagivenIPaddress

TCPsocketWhatcanwedowhenweknowhowtovisitawebservicethroughanetworkportAsaclientwecansendarequesttoanappointednetworkportandgetsitsresponseasaserverweneedtobindaservicetoanappointednetworkportwaitforclientsrequestsandsupplyaresponse

InGosnetpackagetheresatypecalledTCPConnthatfacilitatesthiskindofclientsserversinteractionThistypehastwokeyfunctions

func(cTCPConn)Write(b[]byte)(ninterrosError)

func(cTCPConn)Read(b[]byte)(ninterrosError)

TCPConncanbeusedbyeitherclientorserverforreadingandwritingdata

WealsoneedaTCPAddrtorepresentTCPaddressinformation

Sockets

186

typeTCPAddrstruct

IPIP

Portint

WeusetheResolveTCPAddrfunctiontogetaTCPAddrinGo

funcResolveTCPAddr(netaddrstring)(TCPAddrosError)

Argumentsofnetcanbeoneoftcp4tcp6ortcpwhicheachsignifyIPv4-onlyIPv6-onlyandeitherIPv4orIPv6respectivelyaddrcanbeadomainnameorIPaddresslikewwwgooglecom80or12700122

TCPclientGoclientsusetheDialTCPfunctioninthenetpackagetocreateaTCPconnectionwhichreturnsaTCPConnobjectafteraconnectionisestablishedtheserverhasthesametypeofconnectionobjectforthecurrentconnectionandclientandservercanbeginexchangingdatawithoneanotherIngeneralclientssendrequeststoserversthroughaTCPConnandreceiveinformationfromtheserverresponseserversreadandparseclientrequeststhenreturnfeedbackThisconnectionwillremainvaliduntileithertheclientorserverclosesitThefunctionforcreatingaconnectionisasfollows

funcDialTCP(netstringladdrraddrTCPAddr)(cTCPConnerrosError)

Argumentsofnetcanbeoneoftcp4tcp6ortcpwhicheachsignifyIPv4-onlyIPv6-onlyandeitherIPv4orIPv6respectivelyladdrrepresentsthelocaladdresssetittonilinmostcasesraddrrepresentstheremoteaddress

LetswriteasimpleexampletosimulateaclientrequestingaconnectiontoaserverbasedonanHTTPrequestWeneedasimpleHTTPrequestheader

HEADHTTP10rnrn

Serverresponseinformationformatmaylooklikethefollowing

HTTP10200OK

ETag-9985996

Last-ModifiedThu25Mar2010175110GMT

Content-Length18074

Connectionclose

DateSat28Aug2010004348GMT

Serverlighttpd1423

Clientcode

Sockets

187

packagemain

import(

fmt

ioioutil

net

os

)

funcmain()

iflen(osArgs)=2

fmtFprintf(osStderrUsageshostportosArgs[0])

osExit(1)

service=osArgs[1]

tcpAddrerr=netResolveTCPAddr(tcp4service)

checkError(err)

connerr=netDialTCP(tcpniltcpAddr)

checkError(err)

_err=connWrite([]byte(HEADHTTP10rnrn))

checkError(err)

resulterr=ioutilReadAll(conn)

checkError(err)

fmtPrintln(string(result))

osExit(0)

funccheckError(errerror)

iferr=nil

fmtFprintf(osStderrFatalerrorserrError())

osExit(1)

IntheaboveexampleweuseuserinputastheserviceargumentofnetResolveTCPAddrtogetatcpAddrPassingtcpAddrtotheDialTCPfunctionwecreateaTCPconnectionconnWecanthenuseconntosendrequestinformationtotheserverFinallyweuseioutilReadAlltoreadallthecontentfromconnwhichcontainstheserverresponse

TCPserver

WehaveaTCPclientnowWecanalsousethenetpackagetowriteaTCPserverOntheserversideweneedtobindourservicetoaspecificinactiveportandlistenforanyincomingclientrequests

funcListenTCP(netstringladdrTCPAddr)(lTCPListenererrosError)

func(lTCPListener)Accept()(cConnerrosError)

TheargumentsrequiredhereareidenticaltothoserequiredbytheDialTCPfunctionweusedearlierLetsimplementatimesyncingserviceusingport7777

Sockets

188

packagemain

import(

fmt

net

os

time

)

funcmain()

service=7777

tcpAddrerr=netResolveTCPAddr(tcp4service)

checkError(err)

listenererr=netListenTCP(tcptcpAddr)

checkError(err)

for

connerr=listenerAccept()

iferr=nil

continue

daytime=timeNow()String()

connWrite([]byte(daytime))dontcareaboutreturnvalue

connClose()werefinishedwiththisclient

funccheckError(errerror)

iferr=nil

fmtFprintf(osStderrFatalerrorserrError())

osExit(1)

AftertheserviceisstarteditwaitsforclientrequestsWhenitreceivesaclientrequestitAcceptsitandreturnsaresponsetotheclientcontaininginformationaboutthecurrenttimeItsworthnotingthatwhenerrorsoccurintheforlooptheservicecontinuesrunninginsteadofexitingInsteadofcrashingtheserverwillrecordtheerrortoaservererrorlog

TheabovecodeisstillnotgoodenoughhoweverWedidntmakeuseofgoroutineswhichwouldhaveallowedustoacceptsimultaneousrequestsLetsdothisnow

Sockets

189

packagemain

import(

fmt

net

os

time

)

funcmain()

service=1200

tcpAddrerr=netResolveTCPAddr(tcp4service)

checkError(err)

listenererr=netListenTCP(tcptcpAddr)

checkError(err)

for

connerr=listenerAccept()

iferr=nil

continue

gohandleClient(conn)

funchandleClient(connnetConn)

deferconnClose()

daytime=timeNow()String()

connWrite([]byte(daytime))dontcareaboutreturnvalue

werefinishedwiththisclient

funccheckError(errerror)

iferr=nil

fmtFprintf(osStderrFatalerrorserrError())

osExit(1)

ByseparatingoutourbusinessprocessfromthehandleClientfunctionandbyusingthegokeywordwevealreadyimplementedconcurrencyinourserviceThisisagooddemonstrationofthepowerandsimplicityofgoroutines

SomeofyoumaybethinkingthefollowingthisserverdoesnotdoanythingmeaningfulWhatifweneededtosendmultiplerequestsfordifferenttimeformatsoverasingleconnectionHowwouldwedothat

Sockets

190

packagemain

import(

fmt

net

os

time

strconv

)

funcmain()

service=1200

tcpAddrerr=netResolveTCPAddr(tcp4service)

checkError(err)

listenererr=netListenTCP(tcptcpAddr)

checkError(err)

for

connerr=listenerAccept()

iferr=nil

continue

gohandleClient(conn)

funchandleClient(connnetConn)

connSetReadDeadline(timeNow()Add(2timeMinute))set2minutestimeout

request=make([]byte128)setmaximumrequestlengthto128Btopreventfloodbasedattacks

deferconnClose()closeconnectionbeforeexit

for

read_lenerr=connRead(request)

iferr=nil

fmtPrintln(err)

break

ifread_len==0

breakconnectionalreadyclosedbyclient

elseifstring(request[read_len])==timestamp

daytime=strconvFormatInt(timeNow()Unix()10)

connWrite([]byte(daytime))

else

daytime=timeNow()String()

connWrite([]byte(daytime))

funccheckError(errerror)

iferr=nil

fmtFprintf(osStderrFatalerrorserrError())

osExit(1)

InthisexampleweuseconnRead()toconstantlyreadclientrequestsWecannotclosetheconnectionbecauseclientsmayissuemorethanonerequestDuetothetimeoutwesetusingconnSetReadDeadline()theconnectionclosesautomaticallyafterourallottedtimeperiodWhentheexpirytimehaselapsedourprogrambreaksfromtheforloopNoticethatrequestneedstobecreatedwithamaxsizelimitationinordertopreventfloodattacks

ControllingTCPconnections

ControllingTCPfunctions

funcDialTimeout(netaddrstringtimeouttimeDuration)(Connerror)

Sockets

191

SettingthetimeoutofconnectionsThesearesuitableforuseonbothclientsandservers

func(cTCPConn)SetReadDeadline(ttimeTime)error

func(cTCPConn)SetWriteDeadline(ttimeTime)error

Settingthewritereadtimeoutofoneconnection

func(cTCPConn)SetKeepAlive(keepalivebool)osError

ItsworthtakingsometimetothinkabouthowlongyouwantyourconnectiontimeoutstobeLongconnectionscanreducetheamountofoverheadinvolvedincreatingconnectionsandaregoodforapplicationsthatneedtoexchangedatafrequently

FormoredetailedinformationjustlookuptheofficialdocumentationforGosnetpackage

UDPsocketsTheonlydifferencebetweenaUDPsocketandaTCPsocketistheprocessingmethodfordealingwithmultiplerequestsonserversideThisarisesfromthefactthatUDPdoesnothaveafunctionlikeAcceptAlloftheotherfunctionshaveUDPcounterpartsjustreplaceTCPwithUDPinthefunctionsmentionedabove

funcResolveUDPAddr(netaddrstring)(UDPAddrosError)

funcDialUDP(netstringladdrraddrUDPAddr)(cUDPConnerrosError)

funcListenUDP(netstringladdrUDPAddr)(cUDPConnerrosError)

func(cUDPConn)ReadFromUDP(b[]byte)(nintaddrUDPAddrerrosError

func(cUDPConn)WriteToUDP(b[]byteaddrUDPAddr)(ninterrosError)

UDPclientcodesample

packagemain

import(

fmt

net

os

)

funcmain()

iflen(osArgs)=2

fmtFprintf(osStderrUsageshostportosArgs[0])

osExit(1)

service=osArgs[1]

udpAddrerr=netResolveUDPAddr(udp4service)

checkError(err)

connerr=netDialUDP(udpniludpAddr)

checkError(err)

_err=connWrite([]byte(anything))

checkError(err)

varbuf[512]byte

nerr=connRead(buf[0])

checkError(err)

fmtPrintln(string(buf[0n]))

osExit(0)

funccheckError(errerror)

iferr=nil

fmtFprintf(osStderrFatalerrorerrError())

osExit(1)

Sockets

192

UDPservercodesample

packagemain

import(

fmt

net

os

time

)

funcmain()

service=1200

udpAddrerr=netResolveUDPAddr(udp4service)

checkError(err)

connerr=netListenUDP(udpudpAddr)

checkError(err)

for

handleClient(conn)

funchandleClient(connnetUDPConn)

varbuf[512]byte

_addrerr=connReadFromUDP(buf[0])

iferr=nil

return

daytime=timeNow()String()

connWriteToUDP([]byte(daytime)addr)

funccheckError(errerror)

iferr=nil

fmtFprintf(osStderrFatalerrorerrError())

osExit(1)

SummaryThroughdescribingandcodingsomesimpleprogramsusingTCPandUDPsocketswecanseethatGoprovidesexcellentsupportforsocketprogrammingandthattheyarefunandeasytouseGoalsoprovidesmanyfunctionsforbuildinghighperformancesocketapplications

LinksDirectoryPrevioussectionWebservicesNextsectionWebSocket

Sockets

193

82WebSocketsWebSocketsareanimportantfeatureofHTML5Itimplementsbrowserbasedremotesocketswhichallowsbrowserstohavefull-duplexcommunicationswithserversMainstreambrowserslikeFirefoxGoogleChromeandSafariprovidesupportforthisWebSockets

PeopleoftenusedrollpollingforinstantmessagingservicesbeforeWebSocketswerebornwhichallowclientstosendHTTPrequestsperiodicallyTheserverthenreturnsthelatestdatatoclientsThedownsidetothismethodisthatitrequiresclientstokeepsendingmanyrequeststotheserverwhichcanconsumealargeamountofbandwidth

WebSocketsuseaspecialkindofheaderthatreducesthenumberofhandshakesrequiredbetweenbrowserandservertoonlyoneforestablishingaconnectionThisconnectionwillremainactivethroughoutitslifetimeandyoucanuseJavaScripttowriteorreaddatafromthisconnectionasinthecaseofaconventionalTCPsocketsItsolvesmanyoftheheadacheinvolvedwithreal-timewebdevelopmentandhasthefollowingadvantagesovertraditionalHTTP

OnlyoneTCPconnectionforasinglewebclientWebSocketserverscanpushdatatowebclientsLightweightheadertoreducedatatransmissionoverhead

WebSocketURLsbeginwithwsorwss(SSL)ThefollowingfigureshowsthecommunicationprocessofWebSocketsAparticularHTTPheaderissenttotheserveraspartofthehandshakingprotocolandtheconnectionisestablishedThenserversorclientsareabletosendorreceivedatathroughJavaScriptviaWebSocketThissocketcanthenbeusedbyaneventhandlertoreceivedataasynchronously

Figure82WebSocketprinciple

WebSocketprinciplesTheWebSocketprotocolisactuallyquitesimpleAftersuccessfullycompletingtheinitialhandshakeaconnectionisestablishedSubsequentdatacommunicationswillallbeginwithx00andendwithxFFThisprefixandsuffixwillbevisibletoclientsbecausetheWebSocketwillbreakoffbothendyieldingtherawdataautomatically

WebSocketconnectionsarerequestedbybrowsersandrespondedtobyserversafterwhichtheconnectionisestablishedThisprocessisoftencalledhandshaking

Considerthefollowingrequestsandresponses

Figure83WebSocketrequestandresponse

Sec-WebSocket-keyisgeneratedrandomlyasyoumayhavealreadyguessedanditsbase64encodedServersneedtoappendthiskeytoafixedstringafteracceptingarequest

258EAFA5-E914-47DA-95CA-C5AB0DC85B11

Supposewehavef7cb4ezEAl6C3wRaU6JORA==thenwehave

f7cb4ezEAl6C3wRaU6JORA==258EAFA5-E914-47DA-95CA-C5AB0DC85B11

Usesha1tocomputethebinaryvalueandusebase64toencodeitWewillthenwehave

rE91AJhfC+6JdVcVXOGJEADEJdQ=

WebSocket

194

UsethisasthevalueoftheSec-WebSocket-Acceptresponseheader

WebSocketinGoTheGostandardlibrarydoesnotsupportWebSocketsHoweverthewebsocketpackagewhichisasub-packageofgonetdoesandisofficiallymaintainedandsupported

Usegogettoinstallthispackage

gogetgolangorgxnetwebsocket

WebSocketshavebothclientandserversidesLetsseeasimpleexamplewhereauserinputssomeinformationontheclientsideandsendsittotheserverthroughaWebSocketfollowedbytheserverpushinginformationbacktotheclient

Clientcode

lthtmlgt

ltheadgtltheadgt

ltbodygt

ltscripttype=textjavascriptgt

varsock=null

varwsuri=ws1270011234

windowonload=function()

consolelog(onload)

sock=newWebSocket(wsuri)

sockonopen=function()

consolelog(connectedto+wsuri)

sockonclose=function(e)

consolelog(connectionclosed(+ecode+))

sockonmessage=function(e)

consolelog(messagereceived+edata)

functionsend()

varmsg=documentgetElementById(message)value

socksend(msg)

ltscriptgt

lth1gtWebSocketEchoTestlth1gt

ltformgt

ltpgt

Messageltinputid=messagetype=textvalue=Helloworldgt

ltpgt

ltformgt

ltbuttononclick=send()gtSendMessageltbuttongt

ltbodygt

lthtmlgt

AsyoucanseeitsveryeasytousetheclientsideJavaScriptfunctionstoestablishaconnectionTheonopeneventgetstriggeredaftersuccessfullycompletingtheaforementionedhandshakingprocessIttellstheclientthattheconnectionhasbeencreatedsuccessfullyClientsattemptingtoopenaconnectiontypicallybindtofourevents

1)onopentriggeredafterconnectionhasbeenestablished2)onmessagetriggeredafterreceivingamessage3)onerrortriggeredafteranerrorhasoccurred

WebSocket

195

4)onclosetriggeredaftertheconnectionhasclosed

Servercode

packagemain

import(

golangorgxnetwebsocket

fmt

log

nethttp

)

funcEcho(wswebsocketConn)

varerrerror

for

varreplystring

iferr=websocketMessageReceive(wsampreply)err=nil

fmtPrintln(Cantreceive)

break

fmtPrintln(Receivedbackfromclient+reply)

msg=Received+reply

fmtPrintln(Sendingtoclient+msg)

iferr=websocketMessageSend(wsmsg)err=nil

fmtPrintln(Cantsend)

break

funcmain()

httpHandle(websocketHandler(Echo))

iferr=httpListenAndServe(1234nil)err=nil

logFatal(ListenAndServeerr)

WhenaclientSendsuserinputinformationtheserverReceivesitandusesSendonceagaintoreturnaresponse

Figure84WebSocketserverreceivedinformation

ThroughtheexampleabovewecanseethattheclientandserversideimplementationofWebSocketsisveryconvenientWecanusethenetpackagedirectlyinGoWiththerapiddevelopmentofHTML5IthinkthatWebSocketswilltakeonamuchmoreimportantroleinmoderndaywebdevelopmentweshouldallbeatleastalittlebitfamiliarwiththem

LinksDirectoryPrevioussectionSocketsNextsectionREST

WebSocket

196

83RESTRESTisthemostpopularsoftwarearchitectureontheinternettodaybecauseitisfoundedonwelldefinedstrictstandardsanditseasytounderstandandexpandMoreandmorewebsitesarebasingtheirdesignsontopofRESTInthissectionwearegoingtohaveacloselookatimplementingtheRESTarchitectureinGoand(hopefully)learnhowtoleverageittoourbenefit

WhatisRESTThefirstdeclarationoftheconceptofREST(REpresentationalStateTransfer)wasintheyear2000inRoyThomasFieldingsdoctoraldissertationwhoalsojusthappenstobetheco-founderoftheHTTPprotocolItspecifiesthearchitecturesconstraintsandprinciplesandanythingimplementedwiththisarchitecturecanbecalledaRESTfulsystem

BeforeweunderstandwhatRESTisweneedtocoverthefollowingconcepts

Resources

RESTisthePresentationLayerStateTransferwherethepresentationlayerisactuallytheresourcepresentatio

nlayer

SowhatareresourcesPicturesdocumentsorvideosetcareallexamplesofresourcesandcanbelocatedby

URI

Representation

ResourcesarespecificinformationentitiesthatcanbeshowninavarietyofwayswithinthepresentationlayerForinstanceaTXTdocumentcanberepresentedasHTMLJSONXMLetcanimagecanberepresentedasjpgpngetc

URIsareusedtoidentifyresourcesbuthowdowedetermineitsspecificmanifestationsYouarereferredtotheAcceptandContent-TypeinanHTTPrequestheaderthesetwofieldsdescribethepresentationlayer

StateTransfer

AninteractiveprocessisinitiatedbetweenclientandservereachtimeyouvisitanypageofawebsiteDuringthisprocesscertaindatarelatedtothecurrentpagestateneedtobesavedHoweveryoullrecallthatHTTPisastatelessprotocolItsobviousthatweneedtosavethisclientstateonourserversideItfollowsthatifaclientmodifiessomedataandwantstopersistthechangestheremustbeawaytoinformtheserversideaboutthenewstate

MostofthetimeclientsinformserversofstatechangesusingHTTPTheyhavefouroperationswithwhichtodothis

-GETisusedtoobtainresources-POSTsisusedtocreateorupdateresources-PUTupdatesresources-DELETEdeletesresources

Tosummarizetheabove

(1)EveryURIrepresentsaresource(2)Thereisarepresentationlayerfortransferringresourcesbetweenclientsandservers(3)ClientsusefourHTTPmethodstoimplementPresentationLayerStateTransferallowingthemtooperateonremoteresources

ThemostimportantprincipleofwebapplicationsthatimplementRESTisthattheinteractionbetweenclientsandserversarestatelesseveryrequestshouldencapsulatealloftherequiredinformationServersshouldbeabletorestartatanytimewithouttheclientsbeingnotifiedInadditionrequestscanberespondedbyanyserverofthesameservicewhichisidealforcloudcomputingLastlybecauseitsstatelessclientscancachedataforimprovingperformance

REST

197

AnotherimportantprincipleofRESTissystemdelaminationwhichmeansthatcomponentsinonelayerhavenowayofinteractingdirectlywithcomponentsinotherlayersThiscanlimitsystemcomplexityandencourageindependenceintheunderlyingcomponents

Figure85RESTarchitecture

WhenRESTfulconstraintsarejudiciouslyabidedbywebapplicationscanbescaledtoaccommodatemassivenumbersofclientsUsingtheRESTarchitecturecanalsohelpreducedelaysbetweenclientsandserverssimplifysystemarchitectureandimprovethevisibilityofsub-systemendpoints

Figure86RESTsexpansibility

RESTfulimplementationGodoesnthavedirectsupportforRESTbutsinceRESTfulwebapplicationsareallHTTP-basedwecanusethenethttppackagetoimplementitonourownOfcoursewewillfirstneedtomakesomemodificationsbeforeweareabletofullyimplementREST

RESTusesdifferentmethodstohandleresourcesdependingontheinteractionthatsrequiredwiththatresourceManyexistingapplicationsclaimtobeRESTfulbuttheydonotactuallyimplementRESTImgoingtocategorizetheseapplicationsintoseverallevelsdependsonwhichHTTPmethodstheyimplement

Figure87RESTslevel

ThepictureaboveshowsthreelevelsthatarecurrentlyimplementedinRESTYoumaynotchoosetofollowalltherulesandconstraintsofRESTwhendevelopingyourownapplicationsbecausesometimesitsrulesarenotagoodfitforallsituationsRESTfulwebapplicationsuseeverysingleHTTPmethodincludingDELETEandPUTbutinmanycasesHTTPclientscanonlysendGETandPOSTrequests

HTMLstandardallowsclientssendGETandPOSTrequeststhroughlinksandformsItsnotpossibletosendPUTorDELETErequestswithoutAJAXsupportSomefirewallsinterceptPUTandDELETErequestsandclientshavetousePOSTinordertoimplementthemFullyRESTfulservicesareinchargeoffindingtheoriginalHTTPmethodsandrestoringthem

WecansimulatePUTandDELETErequestsbyaddingahidden_methodfieldinourPOSTrequestshowevertheserequestsmustbeconvertedontheserversidebeforetheyareprocessedMypersonalapplicationsusethisworkflowtoimplementRESTinterfacesStandardRESTfulinterfacesareeasilyimplementedinGoasthefollowingexampledemonstrates

REST

198

packagemain

import(

fmt

githubcomjulienschmidthttprouter

log

nethttp

)

funcIndex(whttpResponseWriterrhttpRequest_httprouterParams)

fmtFprint(wWelcomen)

funcHello(whttpResponseWriterrhttpRequestpshttprouterParams)

fmtFprintf(whellosnpsByName(name))

funcgetuser(whttpResponseWriterrhttpRequestpshttprouterParams)

uid=psByName(uid)

fmtFprintf(wyouaregetusersuid)

funcmodifyuser(whttpResponseWriterrhttpRequestpshttprouterParams)

uid=psByName(uid)

fmtFprintf(wyouaremodifyusersuid)

funcdeleteuser(whttpResponseWriterrhttpRequestpshttprouterParams)

uid=psByName(uid)

fmtFprintf(wyouaredeleteusersuid)

funcadduser(whttpResponseWriterrhttpRequestpshttprouterParams)

uid=rFormValue(uid)

uid=psByName(uid)

fmtFprintf(wyouareaddusersuid)

funcmain()

router=httprouterNew()

routerGET(Index)

routerGET(hellonameHello)

routerGET(useruidgetuser)

routerPOST(adduseruidadduser)

routerDELETE(deluseruiddeleteuser)

routerPUT(moduseruidmodifyuser)

logFatal(httpListenAndServe(8080router))

ThissamplecodeshowsyouhowtowriteaverybasicRESTapplicationOurresourcesareusersandweusedifferentfunctionsfordifferentmethodsHereweimportedathird-partypackagecalledgithubcomjulienschmidthttprouterWevealreadycoveredhowtoimplementacustomrouterinpreviouschapters-thejulienschmidthttprouterpackageimplementssomeveryconvenientroutermappingrulesthatmakeitveryconvenientforimplementingRESTfularchitectureAsyoucanseeRESTrequiresyoutoimplementdifferentlogicfordifferentHTTPmethodsofthesameresource

SummaryRESTisastyleofwebarchitecturebuildingonpastsuccessfulexperienceswithWWWstatelessnessresource-centricfulluseofHTTPandURIprotocolsandtheprovisionofunifiedinterfacesThesesuperiordesignconsiderationshaveallowedRESTtobecomethemostpopularwebservicesstandardInasensebyemphasizingtheURIandleveraging

REST

199

earlyInternetstandardssuchasHTTPRESThaspavedthewayforlargeandscalablewebapplicationsCurrentlythesupportthatGohasForRESTisstillverybasicHoweverbyimplementingcustomroutingrulesanddifferentrequesthandlersforeachtypeofHTTPrequestwecanachieveRESTfularchitectureinourGowebapps

LinksDirectoryPrevioussectionWebSocketNextsectionRPC

REST

200

84RPCInprevioussectionswetalkedabouthowtowritenetworkapplicationsbasedonSocketsandHTTPWelearnedthatbothofthemusetheinformationexchangemodelinwhichclientssendrequestsandserversrespondtothemThiskindofdataexchangeisbasedonaspecificformatsothatbothsidesareabletocommunicatewithoneanotherHowevermanyindependentapplicationsdonotusethismodelbutinsteadcallservicesjustliketheywouldcallnormalfunctions

RPCwasintendedtobethefunctioncallmodefornetworkedsystemsClientsexecuteRPCsliketheycallnativefunctionsexcepttheypackagethefunctionparametersandsendthemthroughthenetworktotheserverTheservercanthenunpacktheseparametersandprocesstherequestexecutingtheresultsbacktotheclient

Incomputersciencearemoteprocedurecall(RPC)isatypeofinter-processcommunicationthatallowsacomputerprogramtocauseasubroutineorproceduretoexecuteinanotheraddressspace(commonlyonanothercomputeronasharednetwork)withouttheprogrammerexplicitlycodingthedetailsforthisremoteinteractionThatistheprogrammerwritesessentiallythesamecodewhetherthesubroutineislocaltotheexecutingprogramorremoteWhenthesoftwareinquestionusesobject-orientedprinciplesRPCiscalledremoteinvocationorremotemethodinvocation

RPCworkingprinciple

Figure88RPCworkingprinciple

NormallyanRPCcallfromclienttoserverhasthefollowingtensteps

1 Calltheclienthandleexecutetransferarguments

1 Calllocalsystemkerneltosendnetworkmessages

1 Sendmessagestoremotehosts

1 Theserverreceiveshandleandarguments

1 Executeremoteprocesses

1 Returnexecutionresulttocorrespondinghandle

1 Theserverhandlecallsremotesystemkernel

1 Messagessentbacktolocalsystemkernel

1 Theclienthandlereceivesmessagesfromsystemkernel

1 Theclientgetsresultsfromcorrespondinghandle

GoRPCGohasofficialsupportforRPCinitsstandardlibraryonthreelevelswhichareTCPHTTPandJSONRPCNotethatGoRPCisnotlikeothertraditionalRPCsystemsItrequiresyoutouseGoapplicationsonbothclientandserversidesbecauseitencodescontentusingGob

RPC

201

FunctionsofGoRPCmustabidebythefollowingrulesforremoteaccessotherwisethecorrespondingcallswillbeignored

Functionsareexported(capitalized)FunctionsmusthavetwoargumentswithexportedtypesThefirstargumentisforreceivingfromtheclientandthesecondonehastobeapointerandisforreplyingtotheclientFunctionsmusthaveareturnvalueoferrortype

Forexample

func(tT)MethodName(argTypeT1replyTypeT2)error

WhereTT1andT2mustbeabletobeencodedbythepackagegobpackage

AnykindofRPChastogothroughanetworktotransferdataGoRPCcaneitheruseHTTPorTCPThebenefitsofusingHTTPisthatyoucanreusesomefunctionsfromthenethttppackage

HTTPRPCHTTPserversidecode

RPC

202

packagemain

import(

errors

fmt

nethttp

netrpc

)

typeArgsstruct

ABint

typeQuotientstruct

QuoRemint

typeArithint

func(tArith)Multiply(argsArgsreplyint)error

reply=argsAargsB

returnnil

func(tArith)Divide(argsArgsquoQuotient)error

ifargsB==0

returnerrorsNew(dividebyzero)

quoQuo=argsAargsB

quoRem=argsAargsB

returnnil

funcmain()

arith=new(Arith)

rpcRegister(arith)

rpcHandleHTTP()

err=httpListenAndServe(1234nil)

iferr=nil

fmtPrintln(errError())

WeregisteredaRPCserviceofAriththenregisteredthisserviceonHTTPthroughrpcHandleHTTPAfterthatweareabletotransferdatathroughHTTP

Clientsidecode

RPC

203

packagemain

import(

fmt

log

netrpc

os

)

typeArgsstruct

ABint

typeQuotientstruct

QuoRemint

funcmain()

iflen(osArgs)=2

fmtPrintln(UsageosArgs[0]server)

osExit(1)

serverAddress=osArgs[1]

clienterr=rpcDialHTTP(tcpserverAddress+1234)

iferr=nil

logFatal(dialingerr)

Synchronouscall

args=Args178

varreplyint

err=clientCall(ArithMultiplyargsampreply)

iferr=nil

logFatal(aritherrorerr)

fmtPrintf(Arithdd=dnargsAargsBreply)

varquotQuotient

err=clientCall(ArithDivideargsampquot)

iferr=nil

logFatal(aritherrorerr)

fmtPrintf(Arithdd=dremainderdnargsAargsBquotQuoquotRem)

WecompiletheclientandtheserversidecodeseparatelythenstarttheserverandclientYoullthenhavesomethingsimilarasfollowsafteryouinputsomedata

$http_clocalhost

Arith178=136

Arith178=2remainder1

AsyoucanseewedefinedastructforthereturntypeWeuseitastypeoffunctionargumentontheserversideandasthetypeofthesecondandthirdargumentsontheclientclientCallThiscallisveryimportantIthasthreeargumentswherethefirstoneisthenameofthefunctionthatisgoingtobecalledthesecondistheargumentyouwanttopassandthelastoneisthereturnvalue(ofpointertype)SofarweseethatitseasytoimplementRPCinGo

TCPRPCLetstrytheRPCthatisbasedonTCPhereistheserversidecode

RPC

204

packagemain

import(

errors

fmt

net

netrpc

os

)

typeArgsstruct

ABint

typeQuotientstruct

QuoRemint

typeArithint

func(tArith)Multiply(argsArgsreplyint)error

reply=argsAargsB

returnnil

func(tArith)Divide(argsArgsquoQuotient)error

ifargsB==0

returnerrorsNew(dividebyzero)

quoQuo=argsAargsB

quoRem=argsAargsB

returnnil

funcmain()

arith=new(Arith)

rpcRegister(arith)

tcpAddrerr=netResolveTCPAddr(tcp1234)

checkError(err)

listenererr=netListenTCP(tcptcpAddr)

checkError(err)

for

connerr=listenerAccept()

iferr=nil

continue

rpcServeConn(conn)

funccheckError(errerror)

iferr=nil

fmtPrintln(FatalerrorerrError())

osExit(1)

ThedifferencebetweenHTTPRPCandTCPRPCisthatwehavetocontrolconnectionsbyourselvesifweuseTCPRPCthenpassconnectionstoRPCforprocessing

AsyoumayhaveguessedthisisablockingpatternYouarefreetousegoroutinestoextendthisapplicationasamoreadvancedexperiment

Theclientsidecode

RPC

205

packagemain

import(

fmt

log

netrpc

os

)

typeArgsstruct

ABint

typeQuotientstruct

QuoRemint

funcmain()

iflen(osArgs)=2

fmtPrintln(UsageosArgs[0]serverport)

osExit(1)

service=osArgs[1]

clienterr=rpcDial(tcpservice)

iferr=nil

logFatal(dialingerr)

Synchronouscall

args=Args178

varreplyint

err=clientCall(ArithMultiplyargsampreply)

iferr=nil

logFatal(aritherrorerr)

fmtPrintf(Arithdd=dnargsAargsBreply)

varquotQuotient

err=clientCall(ArithDivideargsampquot)

iferr=nil

logFatal(aritherrorerr)

fmtPrintf(Arithdd=dremainderdnargsAargsBquotQuoquotRem)

TheonlydifferenceintheclientsidecodeisthatHTTPclientsuseDialHTTPwhereasTCPclientsuseDial(TCP)

JSONRPC

JSONRPCencodesdatatoJSONinsteadofgobLetsseeanexampleofaGoJSONRPContheserver

RPC

206

packagemain

import(

errors

fmt

net

netrpc

netrpcjsonrpc

os

)

typeArgsstruct

ABint

typeQuotientstruct

QuoRemint

typeArithint

func(tArith)Multiply(argsArgsreplyint)error

reply=argsAargsB

returnnil

func(tArith)Divide(argsArgsquoQuotient)error

ifargsB==0

returnerrorsNew(dividebyzero)

quoQuo=argsAargsB

quoRem=argsAargsB

returnnil

funcmain()

arith=new(Arith)

rpcRegister(arith)

tcpAddrerr=netResolveTCPAddr(tcp1234)

checkError(err)

listenererr=netListenTCP(tcptcpAddr)

checkError(err)

for

connerr=listenerAccept()

iferr=nil

continue

jsonrpcServeConn(conn)

funccheckError(errerror)

iferr=nil

fmtPrintln(FatalerrorerrError())

osExit(1)

JSONRPCisbasedonTCPanddoesntsupportHTTPyet

Theclientsidecode

RPC

207

packagemain

import(

fmt

log

netrpcjsonrpc

os

)

typeArgsstruct

ABint

typeQuotientstruct

QuoRemint

funcmain()

iflen(osArgs)=2

fmtPrintln(UsageosArgs[0]serverport)

logFatal(1)

service=osArgs[1]

clienterr=jsonrpcDial(tcpservice)

iferr=nil

logFatal(dialingerr)

Synchronouscall

args=Args178

varreplyint

err=clientCall(ArithMultiplyargsampreply)

iferr=nil

logFatal(aritherrorerr)

fmtPrintf(Arithdd=dnargsAargsBreply)

varquotQuotient

err=clientCall(ArithDivideargsampquot)

iferr=nil

logFatal(aritherrorerr)

fmtPrintf(Arithdd=dremainderdnargsAargsBquotQuoquotRem)

SummaryGohasgoodsupportforHTTPTPCandJSONRPCimplementationwhichallowustoeasilydevelopdistributedwebapplicationshoweveritisregrettablethatGodoesnthavebuilt-insupportforSOAPRPCalthoughsomeopensourcethird-partypackagesdoofferthis

LinksDirectoryPrevioussectionRESTNextsectionSummary

RPC

208

85SummaryInthischapterIintroducedyoutoseveralmainstreamwebapplicationdevelopmentmodelsInsection81IdescribedthebasicsofnetworkprogrammingsocketsBecauseoftherapidevolutionofnetworktechnologyandinfrastructureandgiventhattheSocketisthecornerstoneofthesechangesyoumustmastertheconceptsbehindsocketprogramminginordertobeacompetentwebdeveloperInsection82IdescribedHTML5WebSocketswhichsupportfull-duplexcommunicationsbetweenclientandserverandeliminatetheneedforpollingwithAJAXInsection83weimplementedasimpleapplicationusingtheRESTarchitecturewhichisparticularlysuitableforthedevelopmentofnetworkAPIsduetotherapidriseofmobileapplicationsIbelievethatRESTfulAPIswillbeanongoingtrendInsection84welearnedaboutGoRPCs

GoprovidesexcellentsupportforthefourkindsofdevelopmentmethodsmentionedaboveNotethatthenetpackageanditssub-packagesistheplacewhereGosnetworkprogrammingtoolsGoresideIfyouwantamorein-depthunderstandingoftherelevantimplementationdetailsyoushouldtryreadingthesourcecodeofthosepackages

LinksDirectoryPrevioussectionRPCNextchapterSecurityandencryption

Summary

209

9SecurityandencryptionSecurityisanextremelyimportantaspectofmostwebapplicationsThistopichasbeengettingmoreandmoreattentionlatelyespeciallyinlightoftherecentCSDNLinkedinandYahoopasswordleaksAsGodeveloperswemustbeawareofvulnerabilitiesinourapplicationsandtakeprecautionsinordertopreventattackersfromtakingoveroursystems

Manyofthesecurityproblemsthatariseinmodernwebapplicationsoriginatefromdataprovidedbythird-partiesForexampleuserinputshouldalwaysbevalidatedandsanitizedbeforebeingstoredassecuredataIfthisisntdonewhenthedataisoutputtedtoaclientitmaycauseacross-sitescriptingattack(XSS)SimilarlyifunsafedataisuseddirectlyasyourapplicationsdatabasequeriesthenyoumaybevulnerabletoSQLinjectionattacksInsections93and94welllookathowtoavoidtheseproblems

Whenusingthird-partydata(whichincludesuser-supplieddata)firstverifytheintegrityofthedatabyfilteringtheinputSection92willdescribehowtofilterinput

UnfortunatelyfilteringinputandescapingoutputdoesnotsolveallsecurityproblemsInsection91wewillexplaincross-siterequestforgery(CSRF)attacksThisisamaliciousexploitwhereunauthorizedcommandsaretransmittedfromauserthatthewebsitetrusts

KeepingconfidentialdataencryptedcanalsohelpyoutosecureyourwebapplicationsInsection95wewilldescribehowtostorepasswordssafelyusingGosencryptionpackage

AgoodhashfunctionmakesithardtofindtwostringsthatwouldproducethesamehashvalueandthisisonewaywithwhichwecanencryptourdataThereisalsotwo-wayencryptionwhereyouuseasecretkeytodecryptencrypteddataInsection96wewilldescribehowtoperformbothone-wayandtwo-wayencryption

LinksDirectoryPreviousChapterChapter8SummaryNextsectionCSRFattacks

Securityandencryption

210

91CSRFattacks

WhatisCSRFCSRFandXSRFbothstandforCross-siterequestforgeryItsalsoknownasaoneclickattackorsessionriding

SohowdoesaCSRFattackworkACSRFattackhappenswhenanattackertricksatrusteduserintoaccessingawebsiteorclickingaURLthattransmitsmaliciousrequests(withouttheuserrsquosconsent)toatargetedwebsiteHeresasimpleexampleusingafewsocialengineeringtricksanattackercouldusetheQQchatsoftwaretofindandsendmaliciouslinkstovictimstargetedattheirusersonlinebankingwebsiteIfthevictimlogsintotheironlinebankaccountanddoesnotexitthenclickingonamaliciouslinksentfromtheattackercouldallowtheattackertostealalloftheusersbankaccountfunds

WhenunderaCSRFattackasingleend-userwithanadministratoraccountcanthreatentheintegrityoftheentirewebapplication

CSRFprincipleThefollowingdiagramprovidesasimpleoverviewofaCSRFattack

Figure91CSRFattackprocess

AscanbeseenfromthefiguretocompleteaCSRFattackthevictimmustcompletethefollowingtwosteps

-1LogintotrustedsiteAandstorealocalCookie-2WithoutgoingthroughexistingsiteAaccessthedangerouslinktositeB

AsareaderyoumaybeaskingIfIdonotmeettheabovetwoconditionsIwillnotbesubjectedtoCSRFattacksYesthisistruehoweveryoucannotguaranteethatthefollowingdoesnotoccur

YoucannotguaranteethatwhenyouareloggedintoasitethesitedidntlaunchanyhiddentabsYoucannotguaranteethatwhenyoucloseyourbrowseryourcookieswillimmediatelyexpireandyourlastsessionwillhaveendedTrustedhightrafficwebsiteswilllikelynothavehiddenvulnerabilitieseasilyexploitablebyCSRFbasedattacks

ThusitcanbedifficultforuserstovisitawebsitethroughalinkandknowthatitwillnotcarryoutunknownoperationsintheformofaCSRFattack

CSRFattacksworkmostlybecauseoftheprocessthroughwhichusersareauthenticatedAlthoughyoucanreasonablyguaranteethatarequestoriginatesfromausersbrowserthereisnoguaranteethattheusergrantedapprovalfortherequest

HowtopreventCSRFattacksYoumightbealittlescaredafterreadingthesectionaboveButfearisagoodthingItwillforceyoutoeducateyourselfonhowtopreventvulnerabilitieslikethisfromhappeningtoyou

PreventativemeasuresagainstCSRFattackscanbetakenonboththeserverandclientsidesofawebapplicationHoweverCSRFattacksaremosteffectivelythwartedontheserverside

TherearemanywaysofpreventingCSRFattacksontheserversideMostapproachesstemfromthefollowingtwoaspects

1 MaintainingproperuseofGETPOSTandcookies

CSRFattacks

211

2 Includingapseudo-randomnumberwithnon-GETrequests

InthepreviouschapteronRESTwesawhowmostwebapplicationsarebasedonGETandPOSTHTTPrequestsandthatcookieswereincludedalongwiththeserequestsWegenerallydesignapplicationsaccordingtothefollowingprinciples

1 GETiscommonlyusedtoviewinformationwithoutalteringanydata

2 POSTisusedinplacingorderschangingthepropertiesofaresourceorperformingothertasks

ImnowgoingtousetheGolanguagetoillustratehowtorestrictaccesstoresourcesmethods

muxGet(useruidgetuser)

muxPost(useruidmodifyuser)

SincewevestipulatedthatmodificationscanonlyusePOSTwhenaGETmethodisissuedinsteadofaPOSTwecanrefusetorespondtotherequestAccordingtothefigureaboveattacksutilizingGETasaCSRFexploitcanbepreventedIsthisenoughtopreventallpossibleCSRFattacksOfcoursenotbecausePOSTscanalsobeforged

Weneedtoimplementasecondstepwhichis(inthecaseofnon-GETrequests)toincreasethelengthofthepseudo-randomnumberincludedwiththerequestThisusuallyinvolvessteps

Foreachusergenerateauniquecookietokenwithapseudo-randomvalueAllformsmustcontainthesamepseudo-randomvalueThisproposalisthesimplestonebecauseintheoryanattackercannotreadthirdpartycookiesAnyformthatanattackermaysubmitwillfailthevalidationprocesswithoutknowingwhattherandomvalueisDifferentformscontaindifferentpseudo-randomvaluesasweveintroducedinsection44HowtopreventmultipleformsubmissionWecanreusetherelevantcodefromthatsectiontomeetourneeds

Generatingarandomnumbertoken

h=md5New()

ioWriteString(hstrconvFormatInt(crutime10))

ioWriteString(hganraomaxxxxxxxxx)

token=fmtSprintf(xhSum(nil))

t_=templateParseFiles(logingtpl)

tExecute(wtoken)

Outputtoken

ltinputtype=hiddenname=tokenvalue=gt

Authenticationtoken

rParseForm()

token=rFormGet(token)

iftoken=

Verificationtokenoflegitimacy

Else

Errortokendoesnotexist

WecanusetheprecedingcodetosecureourPOSTsYoumightbewonderinginaccordancewithourtheorywhethertherecouldbesomewayforamaliciousthirdpartytosomehowfigureoutoursecrettokenvalueInfactcrackingitisbasicallyimpossible-successfullycalculatingthecorrectstringvalueusingbruteforcemethodsneedsabout2tothe11thtime

Summary

CSRFattacks

212

Cross-siterequestforgeryalsoknownasCSRFisaverydangerouswebsecuritythreatItisknowninwebsecuritycirclesasasleepinggiantsecurityissueasyoucantellCSRFattackshavequitethereputationThissectionnotonlyintroducedcross-siterequestforgeryitselfbutfactorsunderlyingthisvulnerabilityItconcludeswithsomesuggestionsandmethodsforpreventingsuchattacksIhopethissectionwillhaveinspiredyouasareadertowritebetterandmoresecurewebapplications

LinksDirectoryPrevioussectionSecurityandencryptionNextsectionFilterinputs

CSRFattacks

213

92FilteringinputsFilteringuserdataisonewaywecanimprovethesecurityofourwebappsusingittoverifythelegitimacyofincomingdataAlloftheinputdataisfilteredinordertoavoidmaliciouscodeordatafrombeingmistakenlyexecutedorstoredMostwebapplicationvulnerabilitiesariseformneglectingtofilterinputdataandnaivelytrustingit

Ourintroductiontofilteringdataisdividedintothreesteps

1 identifyingthedataweneedtofilterthedatatofigureoutwhereitoriginatedfrom2 filteringofthedataitselfweneedtofigureoutwhatkindofdatawehavereceived3 distinguishbetweenfiltered(sanitized)andtainteddataafterthedatahasbeenfilteredwecanbeassuredthatitis

secure

IdentifyingdataIdentifyingthedataisourfirststepbecausemostofthetimeasmentionedwedontknowwhereitoriginatesfromWithoutthisknowledgewewouldbeunabletoproperlyfilteritThedatahereisprovidedinternallyallfromnon-codedataForexamplealldatacomesfromclientshoweverclientsthatareusersarenottheonlyexternalsourcesofdataAdatabaseinterfaceprovidingthirdpartydatacouldalsobeanexternaldatasource

DatathathasbeenenteredbyauserisveryeasytorecognizeinGoWeuserParseFormaftertheuserPOSTsaformtogetallofthedatainsidetherFormOthertypesofinputaremuchhardertoidentifyForexampleinrHeadersmanyoftheelementsareoftenmanipulatedbytheclientItcanoftenbedifficulttoidentifywhichoftheseelementshavebeenmanipulatedbyclientssoitsbesttoconsiderallofthemashavingbeentaintedTherHeaderGet(Accept-Charset)headerfieldforinstanceisalsoconsideredasuserinputalthoughthesearetypicallyonlymanipulatedbybrowsers

FilteringdataIfweknowthesourceofthedatawecanfilteritFilteringisabitofaformaluseofthetermTheprocessisknownbymanyothertermssuchasinputcleaningvalidationandsanitizationDespitethefactthatthesetermsdiffersomewhatintheirmeaningtheyallrefertothesamethingtheprocessofpreventingillegaldatafrommakingitswayintoyourapplications

TherearemanywaystofilterdatasomeofwhicharelesssecurethanothersThebestmethodistocheckwhetherornotthedataitselfmeetsthelegalrequirementsdictatedbyyourapplicationWhenattemptingtodosoitsveryimportantnottomakeanyattemptsatcorrectingtheillegaldatathiscouldallowmalicioususerstomanipulateyourvalidationrulesfortheirownneedsaltogetherdefeatingthepurposeoffilteringthedatainthefirstplaceHistoryhasproventhatattemptingtocorrectinvaliddataoftenleadstosecurityvulnerabilitiesLetstakealookatanoverlysimpleexampleforillustrationpurposesSupposethatabankingsystemasksuserstosupplyasecure6digitpasswordThesystemvalidatesthelengthofallpasswordsOnemightnaivelywriteavalidationrulethatcorrectspasswordsofillegallengthsIfapasswordisshorterthanthelegallengthfillintheremainingdigitswith0sThissimplerulewouldallowattackerstoguessjustthefirstfewdigitsofapasswordtosuccessfullygainaccesstouseraccounts

Wecanuseseverallibrariestohelpustofilterdata

ThestrconvpackagecanhelpustoconvertstringsinputbyusersintospecifictypessincerFormsaremapsofstringvaluesSomecommonstringconversionsprovidedbystrconvareAtoiParseBoolParseFloatandParseIntGosstringspackagecontainssomefilterfunctionslikeTrimToLowerandToTitlewhichcanhelpustoobtaindatainaspecificformatsaccordingtoourneedsGosregexppackagecanbeusedtohandlecaseswhicharemorecomplexinnaturesuchasdeterminingwhetheraninputisanemailaddressabirthdayetc

Filterinputs

214

FilteringincomingdatainadditiontoauthenticationcanbequiteeffectiveLetsaddanothertechniquetoourrepertoirecalledwhitelistingWhitelistingisagoodwayofconfirmingthelegitimacyofincomingdataUsingthismethodifanerroroccursitcanonlymeanthattheincomingdataisillegalandnottheoppositeOfcoursewedontwanttomakeanymistakesinourwhitelistbyfalselylabellinglegitimatedataasillegalbutthisscenarioismuchbetterthanillegaldatabeinglabeledaslegitimateandthusmuchmoresecure

DistinguishingbetweenfilteredandtainteddataIfyouhavecompletedtheabovestepsthejoboffilteringdatahasbasicallybeencompletedHoweverwhenwritingwebapplicationswealsoneedtodistinguishbetweenfilteredandtainteddatabecausedoingsocanguaranteetheintegrityofourdatafilteringprocesswithoutaffectingtheinputdataLetsputallofourfiltereddataintoaglobalmapvariablecalledCleanMapThentwoimportantstepsarerequiredtopreventcontaminationviadatainjection

EachrequestmustinitializeCleanMapasanemptymapPreventvariablesfromexternaldatasourcesnamedCleanMapfrombeingintroducedintotheapp

Nextletsuseanexampleformtoreinforcetheseconcepts

ltformaction=whoamimethod=POSTgt

WhoamI

ltselectname=namegt

ltoptionvalue=astaxiegtastaxieltoptiongt

ltoptionvalue=herrygtherryltoptiongt

ltoptionvalue=marrygtmarryltoptiongt

ltselectgt

ltinputtype=submitgt

ltformgt

IndealingwiththistypeofformitcanbeveryeasytomakethemistakeofthinkingthatuserswillonlybeabletosubmitoneofthethreeselectoptionsInfactPOSToperationscaneasilybesimulatedbyattackersForexamplebysubmittingthesameformwithname=attackamalicioususercouldintroduceillegaldataintooursystemWecanuseasimplewhitelisttocounterthesetypesofattacks

rParseForm()

name=rFormGet(name)

CleanMap=make(map[string]interface0)

ifname==astaxie||name==herry||name==marry

CleanMap[name]=name

TheabovecodeinitializesaCleanMapvariableandanameisonlyassignedaftercheckingitagainstaninternalwhitelistoflegitimatevalues(astaxieherryandmarryinthiscase)WestorethedataintheCleanMapinstancesoyoucanbesurethatCleanMap[name]holdsavalidatedvalueAnycodewishingtoaccessthisvaluecanthenfreelydosoWecanalsoaddanadditionalelsestatementtotheaboveifwhitelistfordealingwithillegaldataapossibilitybeingthattheformwasdisplayedwithanerrorDonottrytobetooaccommodatingthoughoryouruntheriskofaccidentallycontaminatingyourCleanMap

TheabovemethodforfilteringdataagainstasetofknownlegitimatevaluesisveryeffectiveThereisanothermethodforcheckingwhetherornotincomingdataconsistsoflegalcharactersusingregexphoweverthiswouldbeineffectualintheabovecasewherewerequirethatthenamebeanoptionfromtheselectForexampleyoumayrequirethatusernamesonlyconsistoflettersandnumbers

rParseForm()

username=rFormGet(username)

CleanMap=make(map[string]interface0)

ifok_=regexpMatchString(^[a-zA-Z0-9]$username)ok

CleanMap[username]=username

Filterinputs

215

SummaryDatafilteringplaysavitalroleinthesecurityofmodernwebapplicationsMostsecurityvulnerabilitiesaretheresultofimproperlyfilteringdataorneglectingtoproperlyvalidateitBecausetheprevioussectiondealtwithCSRFattacksandthenexttwowillbeintroducingXSSattacksandSQLinjectiontherewasnonaturalsegueintodealingwithatopicasimportantasdatasanitizationsointhissectionwepaidspecialattentiontoit

LinksDirectoryPrevioussectionCSRFattacksNextsectionXSSattacks

Filterinputs

216

93XSSattacksWiththedevelopmentofInternettechnologywebapplicationsareoftenpackedwithdynamiccontenttoimproveuserexperienceDynamiccontentiscontentthatreactsandchangesaccordingtouserrequestsandactionsDynamicsitesareoftensusceptibletocross-sitescriptingattacks(oftenreferredtobysecurityexpertsinitsabbreviatedformXSS)somethingwhichstaticwebsitesarecompletelyunaffectedby

WhatisXSSAsmentionedthetermXSSisanacronymforCross-SiteScriptingwhichisatypeofattackcommononthewebInordernottoconfuseitwithanothercommonwebacronymCSS(CascadingStyleSheets)weuseanXinsteadofaCforthecrossincross-sitescriptingXSSisacommonwebsecurityvulnerabilitywhichallowsattackerstoinjectmaliciouscodeintowebpagesUnlikemosttypesofattackswhichgenerallyinvolveonlyanattackerandavictimXSSinvolvesthreepartiesanattackeraclientandawebapplicationThegoalofanXSSattackistostealcookiesstoredonclientsbywebapplicationsforthepurposeofreadingsensitiveclientinformationOnceanattackergetsaholdofthisinformationtheycanimpersonateusersandinteractwithwebsiteswithouttheirknowledgeorapproval

XSSattackscanusuallybedividedintotwocategoriesoneisastoredXSSattackThisformofattackariseswhenusersareallowedtoinputdataontoapublicpagewhichafterbeingsavedbytheserverwillbereturned(unescaped)tootherusersthathappentobebrowsingitSomeexamplesofthetypesofpagesthatareoftenaffectedincludecommentsreviewsblogpostsandmessageboardsTheprocessoftengoeslikethisanattackerenterssomehtmlfollowedbyahiddenltscriptgttagcontainingsomemaliciouscodethenhitssaveThewebapplicationsavesthistothedatabaseWhenanotheruserrequeststhispagetheapplicationqueriesthistainteddatafromthedatabaseandservesthepagetotheuserTheattackersscriptthenexecutesarbitrarycodeontheclientscomputer

TheothertypeisareflectedXSSattackThemainideaistoembedamaliciousscriptdirectlyintothequeryparametersofaURLaddressAserverthatimmediatelyparsesthisdataintoapageofresultsandreturnsit(totheclientwhomadetherequest)unsanitizedcanunwittinglycausetheclientscomputertoexecutethiscodeAnattackercansendauseralegitimatelookinglinktoatrustedwebsitewiththeencodedpayloadclickingonthislinkcancausetheusersbrowsertoexecutethemaliciousscript

XSSpresentthemainmeansandendsasfollows

TheftofcookiesaccesstosensitiveinformationTheuseofembeddedFlashthroughcrossdomainpermissionscanalsobeusedbyanattackertoobtainhigheruserprivilegesThisalsoappliesforothersimilarattackvectorssuchasJavaandVBScriptTheuseofiframesframesXMLHttpRequestsetccanallowanattackertoassumetheidentityofausertoperformadministrativeactionssuchasmicro-bloggingaddingfriendssendingprivatemessagesandotherroutineoperationsAwhileagotheSinamicrobloggingplatformsufferedfromthistypeofXSSvulnerabilityWhenmanyusersvisitapageaffectedbyanXSSattacktheeffectonsomesmallersitescanbecomparabletothatofaDDoSattack

XSSprinciplesWebapplicationsthatreturnrequesteddatatouserswithoutfirstinspectingandfilteringitcanallowmalicioususerstoinjectscripts(typicallyembeddedinsideHTMLwithinltscriptgttags)ontootherusersbrowsersWhenthismaliciouscodeisrenderedonausersbrowserwithoutfirsthavingbeenescapedfromtheusersbrowserwillinterpretthiscodethisisthedefinitionofanXSSattackandthistypeofmistakeistheleadingcauseofXSSvulnerabilities

LetsgothroughtheprocessofareflectiveXSSattackLetssaytheresawebsitethatoutputsausersnameaccordingtotheURLqueryparametersaccessthefollowingURLhttp127001name=astaxiewillcausetheservertooutputthefollowing

XSSattacks

217

helloastaxie

Letssaywepassthefollowingparameterinsteadaccessingthesameurlhttp127001name=ltscriptgtalert(astaxiexss)ltscriptgtIfthiscausesthebrowsertoproduceanalertpop-upboxwecanconfirmthatthesiteisvulnerabletoXSSattacksSohowdomalicioususersstealcookiesusingthesametypeofattack

JustlikebeforewehaveaURL

http127001

name=amp60scriptamp62documentlocationhref=httpwwwxxxcomcookie+documentcookieamp60scriptamp62

ByclickingonthisURLyoudbesendingthecurrentcookietothespecifiedsitewwwxxxcomYoumightbewonderingwhywouldanybodyclickonsuchastrangelookingURLinthefirstplaceWhileitstruethatthiskindofURLwillmakemostpeopleskepticalifanattackerweretouseoneofthemanypopularURLshorteningservicestoobscureitwouldyoustillbeabletoseeitMostattackerswouldobfuscatetheURLinonewayoranotherandyoudonlyknowthelegitimacyofthelinkafterclickingonitHoweverbythispointcookiedatawillhavealreadybeensenttothe3rdpartywebsitecompromisingyoursensitiveinformationYoucanusetoolslikeWebsleuthtoauditthesecurityofyourwebapplicationsforthesetypesofvulnerabilities

ForamoredetailedanalysisonanXSSattackhavealookatthearticle[SinamicrobloggingXSSeventanalysis](httpwwwrisingcomcnnewsletternews2011-08-189621html)

HowtopreventXSSTheanswerissimplenevertrustuserinputandalwaysfilteroutallspecialcharactersinanyinputdatayoumayreceiveThiswilleliminatethemajorityofXSSattacks

UsethefollowingtechniquestodefendagainstXSSattacks

Filterspecialcharacters

OnewaytoavoidXSSistofilteruser-suppliedcontentTheGolanguageprovidessomeHTMLfilteringfunctionsinitstexttemplatepackgesuchasHTMLEscapeStringandJSEscapeStringtonameafew

SpecifythecontenttypeinyourHTTPheaders

wHeader()Set(Content-Typetextjavascript)

Thisallowsclientbrowserstoparsetheresponseasjavascriptcode(applyingtheneccessaryfilters)insteadofrenderingthecontentinanunspecifiedandpotentiallydangerousmanner

SummaryIntroducingXSSvulnerabilitiesisaveryrealhazardwhendevelopingwebapplicationsItisimportanttoremembertofilteralldataespeciallybeforeoutputtingittoclientsthisisnowawell-establishedmeansofpreventingXSS

LinksDirectoryPrevioussectionFilterinputsNextsectionSQLinjection

XSSattacks

218

94SQLinjection

WhatisSQLinjectionSQLinjectionattacksare(asthenamewouldsuggest)oneofthemanytypesofscriptinjectionattacksInwebdevelopmentthesearethemostcommonformofsecurityvulnerabilitiesAttackerscanuseittoobtainsensitiveinformationfromdatabasesandaspectsofanattackcaninvolveaddinguserstothedatabaseexportingprivatefilesandevenobtainingthehighestsystemprivilegesfortheirownnefariouspurposes

SQLinjectionoccurswhenwebapplicationsdonoteffectivelyfilteroutuserinputleavingthedoorwideopenforattackerstosubmitmaliciousSQLquerycodetotheserverApplicationsoftenreceiveinjectedcodeaspartofanattackersinputwhichaltersthelogicoftheoriginalqueryinsomewayWhentheapplicationattemptstoexecutethequerytheattackersmaliciouscodeisexecutedinstead

SQLinjectionexamplesManywebdevelopersdonotrealizehowSQLqueriescanbetamperedwithandmayholdthemisconceptionthattheyaretrustedcommandsAseveryoneknowsSQLqueriesareabletocircumventaccesscontrolstherebybypassingthestandardauthenticationandauthorizationchecksWhatsmoreitspossibletorunSQLqueriesthroughcommandsatthelevelofthehostsystem

LetshavealookatsomerealexamplestoexplaintheprocessofSQLinjectionindetail

Considerthefollowingsimpleloginform

ltformaction=loginmethod=POSTgt

ltpgtUsernameltinputtype=textname=usernamegtltpgt

ltpgtPasswordltinputtype=passwordname=passwordgtltpgt

ltpgtltinputtype=submitvalue=Logingtltpgt

ltformgt

Ourformprocessingmightlooklikethis

username=rFormGet(username)

password=rFormGet(password)

sql=SELECTFROMuserWHEREusername=+username+ANDpassword=+password+

Iftheuserinputsausernameorpasswordas

myuserorfoo=foo--

ThenourSQLbecomesthefollowing

SELECTFROMuserWHEREusername=myuserorfoo=foo--ANDpassword=xxx

InSQLanythingafter--isacommentThusinsertingthe--astheattackerdidabovealtersthequeryinafatalwayallowinganattackertosuccessfullyloginasauserwithoutavalidpassword

FarmoredangerousexploitsexistforMSSQLSQLinjectionsandsomecanevenperformsystemcommandsThefollowingexampleswilldemonstratehowterribleSQLinjectionscanbeinsomeversionsofMSSQLdatabases

sql=SELECTFROMproductsWHEREnameLIKE+prod+

DbExec(sql)

SQLinjection

219

Ifanattackersubmitsaexecmasterxp_cmdshellnetusertesttestpassADD--astheprodvariablethenthesqlwillbecome

sql=SELECTFROMproductsWHEREnameLIKEaexecmasterxp_cmdshellnetusertesttestpassADD--

TheMSSQLServerexecutestheSQLstatementincludingthecommandsintheusersuppliedprodvariablewhichaddsnewuserstothesystemIfthisprogramisrunasisandtheMSSQLSERVERservicehassufficientprivilegesanattackercanregisterasystemaccounttoaccessthismachine

AlthoughtheexamplesabovearetiedtoaspecificdatabasesystemthisdoesnotmeanthatotherdatabasesystemscannotbesubjectedtosimilartypesofattacksTheprinciplesbehindSQLinjectionattacksremainthesamethoughthemethodwithwhichtheyareperpetratedmayvary

HowtopreventSQLinjectionYoumightbethinkingthatanattackerwouldhavetoknowinformationaboutthetargetdatabasesstructureinordertocarryoutanSQLinjectionattackWhilethisistrueitsdifficulttoguaranteethatanattackerwontbeabletofindthisinformationandoncetheygetitthedatabasecanbecompromisedIfyouareusingopensourcesoftwaretoaccessthedatabasesuchasaforumapplicationintruderscaneasilygettherelatedcodeObviouslywithpoorlydesignedcodethesecurityrisksareevengreaterDiscuzphpwindandphpcmsaresomeexamplesofpopularopensourceprogramsthathavebeenvulnerabletoSQLinjectionattacks

TheseattackshappentosystemswheresafetyprecautionsarenotprioritizedWevesaiditbeforewellsayitagainnevertrustanykindofinputespeciallyuserdataThisincludesdatacomingfromselectionboxeshiddeninputfieldsorcookiesAsourfirstexampleabovehasshownevensupposedlynormalqueriescancausedisasters

SQLinjectionattackscanbedevastating-howcandoweevenbegintodefendagainstthemThefollowingsuggestionsareagoodstartingpointforpreventingSQLinjection

1 Strictlylimitpermissionsfordatabaseoperationssothatusersonlyhavetheminimumsetofpermissionsrequiredtoaccomplishtheirworkthusminimizingtheriskofdatabaseinjectionattacks

2 CheckthatinputdatahastheexpecteddataformatandstrictlylimitthetypesofvariablesthatcanbesubmittedThiscaninvolveregexpmatchingorusingthestrconvpackagetoconvertstringsintootherbasictypesforsanitizationandevaluation

3 Transcodeorescapefrompairsofspecialcharacters(ampetc)beforepersistingthemintothedatabaseGostexttemplatepackagehasaHTMLEscapeStringfunctionthatcanbeusedtoreturnescapedHTML

4 UseyourdatabasesparameterizedqueryinterfaceParameterizedstatementsuseparametersinsteadofconcatenatinguserinputvariablesinembeddedSQLstatementsinotherwordstheydonotdirectlyspliceSQLstatementsForexampleusingthePreparefunctioninGosdatabasesqlpackagewecancreatepreparedstatementsforlaterexecutionwithQueryorExec(querystringargsinterface)

5 BeforereleasingyourapplicationthoroughlytestitusingprofessionaltoolsfordetectingSQLinjectionvulnerabilitiesandtorepairthemiftheyexistTherearemanyonlineopensourcetoolsthatdojustthissuchassqlmapSQLninjatonameafew

6 AvoidprintingoutSQLerrorinformationonpublicwebpagesAttackerscanusetheseerrormessagestocarryoutSQLinjectionattacksExamplesofsucherrorsaretypeerrorsfieldsnotmatchingerrorsoranyerrorscontainingSQLstatements

SummaryThroughtheaboveexampleswevelearnedthatSQLinjectionisaveryrealandverydangerouswebsecurityvulnerabilityWhenwewritewebapplicationweshouldpayattentiontoeverylittledetailandtreatsecurityissueswiththeutmostcareDoingsowillleadtobetterandmoresecurewebapplicationsandcanultimatelybethedetermingfactorinwhetherornotyourapplicationsucceeds

SQLinjection

220

LinksDirectoryPrevioussectionXSSattacksNextsectionPasswordstorage

SQLinjection

221

95PasswordstorageOvertheyearsmanywebsiteshavesufferedfrombreachesinuserpassworddataEventopinternetcompaniessuchasLinkedinandCSDNnethavebeenaffectedTheimpactoftheseeventshasbeenfeltacrosstheentireinternetandcannotbeunderestimatedThisisespeciallythecasefortodaysinternetuserswhooftenadoptthehabitofusingthesamepasswordformanydifferentwebsites

AswebdeveloperswehavemanychoiceswhenitcomestoimplementingapasswordstorageschemeHoweverthisfreedomisoftenadoubleedgedswordSowhatarethecommonpitfallsandhowcanweavoidfallingintothem

BadsolutionCurrentlythemostfrequentlyusedpasswordstorageschemeistoone-wayhashplaintextpasswordsbeforestoringthemThemostimportantcharacteristicofone-wayhashingisthatitisnotfeasibletorecovertheoriginaldatagiventhehasheddata-hencetheone-wayinone-wayhashingCommonlyusedcryptographicone-wayhashalgorithmsincludeSHA-256SHA-1MD5andsoon

YoucaneasilyusethethreeaforementionedhashingalgorithmsinGoasfollows

importcryptosha256

h=sha256New()

ioWriteString(hHismoneyistwicetaintedtaintyoursandtaintmine)

fmtPrintf(xhSum(nil))

importcryptosha1

h=sha1New()

ioWriteString(hHismoneyistwicetaintedtaintyoursandtaintmine)

fmtPrintf(xhSum(nil))

importcryptomd5

h=md5New()

ioWriteString(h需要加密的密码)

fmtPrintf(xhSum(nil))

Therearetwokeyfeaturesofone-wayhashing

1)givenaone-wayhashofapasswordtheresultingsummaryisalwaysuniquelydetermined2)calculationspeedAstechnologyadvancesitonlytakesasecondtocompletebillionsofone-wayhashcalculations

GiventhecombinationoftheabovetwocharacteristicsandtakingintoaccountthefactthatthemajorityofpeopleusesomecombinationofcommonpasswordsanattackercancomputeacombinationofallthecommonpasswordsEventhoughthepasswordsyoustoreinyourdatabasemaybehashvaluesonlyifattackersgainaccesstothisdatabasetheycancomparethestoredhashestotheirprecomputedhashestoobtainthecorrespondingpasswordsThistypeofattackreliesonwhatistypicallycalledarainbowtable

Wecanseethathashinguserdatausingone-wayhashesmaynotbeenoughOnceawebsitesdatabasegetsleakedtheusersoriginalpasswordcouldpotentiallyberevealedtotheworld

GoodsolutionThemethodmentionedabovemayhavebeensecureenoughtothwartmosthackingattemptsafewyearsagosincemostattackerswouldnothavehadthecomputingresourcestocomputelargerainbowtablesHoweverwiththeriseofparallelcomputingcapabilitiesthesetypesofattacksarebecomingmoreandmorefeasible

Passwordstorage

222

HowdowesecurelystoreapasswordsothatitcannotbedecipheredbyathirdpartygivenreallifelimitationsintimeandmemoryresourcesThesolutionistocalculateahashedpasswordtodeliberatelyincreasetheamountofresourcesandtimeitwouldtaketocrackitWewanttodesignahashsuchthatnobodycouldpossiblyhavetheresourcesrequiredtocomputetherequiredrainbowtable

VerysecuresystemsutilizehashalgorithmsthattakeintoaccountthetimeandresourcesitwouldrequiretocomputeagivenpassworddigestThisallowsustocreatepassworddigeststhatarecomputationallyexpensivetoperformonalargescaleThegreatertheintensityofthecalculationthemoredifficultitwillbeforanattackertopre-computerainbowtables-somuchsothatitmayevenbeinfeasibletotry

InGoitsrecommendedthatyouusethebcryptpackage

Thepackagessourcecodecanbefoundatthefollowinglinkhttpsgithubcomgolangcryptoblobmasterbcryptbcryptgo

Hereisanexamplecodesnippetwhichcanbeusedtohashstoreandvalidateuserpasswords

packagemain

import(

fmt

log

golangorgxcryptobcrypt

)

funcmain()

userPassword1=someuser-providedpassword

Generatehashtostorefromuserpassword

hasherr=bcryptGenerateFromPassword([]byte(userPassword1)bcryptDefaultCost)

iferr=nil

TODOProperlyhandleerror

logFatal(err)

fmtPrintln(Hashtostorestring(hash))

Storethishashsomewhereeginyourdatabase

Afterawhiletheuserwantstologinandyouneedtocheckthepasswordheentered

userPassword2=someuser-providedpassword

hashFromDatabase=hash

Comparingthepasswordwiththehash

iferr=bcryptCompareHashAndPassword(hashFromDatabase[]byte(userPassword2))err=nil

TODOProperlyhandleerror

logFatal(err)

fmtPrintln(Passwordwascorrect)

SummaryIfyoureworriedaboutthesecurityofyouronlinelifeyoucantakethefollowingsteps

1)AsaregularinternetuserwerecommendusingLastPassforpasswordstorageandgenerationondifferentsitesusedifferentpasswords

2)AsaGowebdeveloperwestronglysuggestthatyouuseoneoftheprofessionalwelltestedmethodsaboveforstoringuserpasswords

LinksDirectory

Passwordstorage

223

PrevioussectionSQLinjectionNextsectionEncryptanddecryptdata

Passwordstorage

224

96EncryptinganddecryptingdataTheprevioussectiondescribeshowtosecurelystorepasswordsbutsometimesitmightbeneccessarytomodifysomesensitiveencrypteddatathathasalreadybeenstoredintoourdatabaseWhendatadecryptionisrequiredweshoulduseasymmetricencryptionalgorithminsteadoftheone-wayhashingtechniqueswevepreviouslycovered

AdvancedencryptionanddecryptionTheGolanguagesupportssymmetricencryptionalgorithmsinitscryptopackageDonotuseanythingexceptAESinGCMmodeifyoudontknowwhatyouredoing

cryptoaespackageAES(AdvancedEncryptionStandard)alsoknownasRijndaelencryptionmethodisusedbytheUSfederalgovernmentasablockencryptionstandard

InthefollowingexamplewedemonstratehowtoencryptdatausingAESinGCMmode

Encryptanddecryptdata

225

packagemain

import(

cryptoaes

cryptocipher

cryptorand

errors

fmt

io

log

)

funcmain()

text=[]byte(MynameisAstaxie)

key=[]byte(the-key-has-to-be-32-bytes-long)

ciphertexterr=encrypt(textkey)

iferr=nil

TODOProperlyhandleerror

logFatal(err)

fmtPrintf(s=gtxntextciphertext)

plaintexterr=decrypt(ciphertextkey)

iferr=nil

TODOProperlyhandleerror

logFatal(err)

fmtPrintf(x=gtsnciphertextplaintext)

funcencrypt(plaintext[]bytekey[]byte)([]byteerror)

cerr=aesNewCipher(key)

iferr=nil

returnnilerr

gcmerr=cipherNewGCM(c)

iferr=nil

returnnilerr

nonce=make([]bytegcmNonceSize())

if_err=ioReadFull(randReadernonce)err=nil

returnnilerr

returngcmSeal(noncenonceplaintextnil)nil

funcdecrypt(ciphertext[]bytekey[]byte)([]byteerror)

cerr=aesNewCipher(key)

iferr=nil

returnnilerr

gcmerr=cipherNewGCM(c)

iferr=nil

returnnilerr

nonceSize=gcmNonceSize()

iflen(ciphertext)ltnonceSize

returnnilerrorsNew(ciphertexttooshort)

nonceciphertext=ciphertext[nonceSize]ciphertext[nonceSize]

returngcmOpen(nilnonceciphertextnil)

Encryptanddecryptdata

226

CallingtheabovefunctionaesNewCipher(whose[]bytekeyparametermustbe1624or32correspondingtotheAES-128AES-192orAES-256algorithmsrespectively)returnsacipherBlockInterfacethatimplementsthreefunctions

typeBlockinterface

BlockSizereturnstheciphersblocksize

BlockSize()int

Encryptencryptsthefirstblockinsrcintodst

Dstandsrcmaypointatthesamememory

Encrypt(dstsrc[]byte)

Decryptdecryptsthefirstblockinsrcintodst

Dstandsrcmaypointatthesamememory

Decrypt(dstsrc[]byte)

ThesethreefunctionsimplementencryptionanddecryptionoperationsseetheGodocumentationforamoredetailedexplanation

SummaryThissectiondescribesencryptionalgorithmswhichcanbeusedindifferentwaysaccordingtoyourwebapplicationsencryptionanddecryptionneedsForapplicationswithevenbasicsecurityrequirementsitisrecommendedtouseAESinGCMmode

LinksDirectoryPreviousstorepasswordsNextSummary

Encryptanddecryptdata

227

97SummaryInthischapterwevedescribedCSRFXSSandSQLinjectionbasedattacksMostwebapplicationsarevulnerabletothesetypesofattacksduetoalackofadequateinputfilteringonthepartoftheapplicationSoinadditiontointroducingtheprinciplesbehindtheseattackswevealsointroducedafewtechniquesforeffectivelyfilteringuserdataandpreventingtheseattacksfromevertakingplaceWethendiscussedafewmethodsforsecurelystoringuserpasswordsfirstintroducingbasicone-wayhashingforwebapplicationswithloosesecurityrequirementsthenpasswordsaltingandencryptionalgorithmsformoreseriousapplicationsFinallywebrieflydiscussedtwo-wayhashingandtheencryptionanddecryptionofsensitivedataWelearnedthattheGolanguageprovidespackagesforthreesymmetricencryptionalgorithmsbase64AESandDESThepurposeofthischapteristohelpreadersbecomemoreconsciousofthesecurityissuesthatexistinmoderndaywebapplicationsHopefullyitcanhelpdeveloperstoplananddesigntheirwebapplicationsalittlemorecarefullysotheycanwritesystemsthatareabletopreventhackersfromexploitinguserdataTheGolanguagehasalargeandwelldesignedanti-attacktoolkitandeveryGodevelopershouldtakefulladvantageofthesepackagestobettersecuretheirwebapplications

LinksDirectoryPrevioussectionEncryptanddecryptdataNextchapterInternationalizationandlocalization

Summary

228

10InternationalizationandlocalizationInordertoadapttotheincreasingglobalizationoftheinternetasdeveloperswemaysometimesneedtobuildmultilingualinternationalwebapplicationsThismeansthatsomepageswillappearindifferentlanguagesaccordingtouserregionsandperhapstheUIandUXwillalsobeadaptedtoshowdifferenteffectsbasedonlocalholidaysorcultureForexampleatruntimetheapplicationwillbeabletorecognizeandprocessrequestscomingfromdifferentgeographicalregionsandrenderpagesinthelocaldialectordisplaydifferentuserinterfaceAscompetentdeveloperswedontwanttohavetomanuallymodifyourapplicationssourcecodetocatertoeverypossibleregionoutthereWhenanapplicationneedstoaddsupportforanewlanguageweshouldbeabletosimplydropintheappropriatelanguagepackandbedonewithit

Inthissectionwellbetalkingaboutinternationalizationandlocalization(usuallyexpressedasi18nandL10Nrespectively)InternationalizationistheprocessofdesigningapplicationsthatareflexibleenoughtobeservedtomultipleregionsaroundtheworldInsomewayswecanthinkofinternationalizationassomethingthathelpstofacilitatelocalizationwhichistheadaptationofawebapplicationscontentanddesigntosuitthelanguageorculturalneedsofspecificlocales

CurrentlyGosstandardpackagedoesnotprovidei18nsupportbuttherearesomeusefulandrelativelysimplethird-partyimplementationsavailableInthischapterwellbeusingtheopen-sourcego-i18nlibrarytosupportinternationalizationinourexamples

WhenwetalkaboutmakingourwebapplicationsinternationalwemeanthateachwebpageshouldbeconstructedwithlocalespecificinformationandassembledwiththecorrespondinglocalstringstimeandcurrencyformatsetcThisinvolvesthreethings

1 howtodeterminetheuserslocale

2 howtosavestringsorotherinformationassociatedwiththelocale

3 howtoembedstringsandotherinformationaccordingtotheuserslocale

InthefirstsectionwelldescribehowtodetectandsetthecorrectlocaleinordertoallowwebsiteusersaccesstotheirlanguagespecificpagesThesecondsectiondescribeshowtohandleorstorestringscurrenciestimesdatesandotherlocalerelatedinformationFinallythethirdsectionwilldescribehowtointernationalizeyourwebapplicationmorespecificallywelldiscusshowtoreturndifferentpageswithlocaleappropriatecontentThroughthesethreesectionswellbeabletosupportfulli18ninourwebapplications

LinksDirectoryPreviousChapterChapter9SummaryNextsectionSettingthedefaultregion

Internationalizationandlocalization

229

101Settingthedefaultregion

FindingoutthelocaleAlocaleisasetofdescriptorsforaparticulargeographicalregionandcanincludespecificlanguagehabitstextformattingculturalidiomsandamultitudeofothersettingsAlocalesnameisusuallycomposedofthreepartsFirst(andmandatory)isthelocaleslanguageabbreviationsuchasenforEnglishorzhforChineseThesecondpartisanoptionalcountryspecifierandfollowsthefirstwithanminussignThisspecifierallowswebapplicationstodistinguishbetweendifferentcountrieswhichspeakthesamelanguagesuchasen-USforUSEnglishanden-GBforBritishEnglishThelastpartisanotheroptionalspecifierandisaddedtothelocalewithaperiodItspecifieswhichcharactersettouseforinstancezh-CNgb2312specifiesthegb2312charactersetforChinese

GodefaultstotheUTF-8encodingsetsoi18ninGoapplicationsdonotneedtoconsiderthelastparameterThusinourexampleswellonlyusethefirsttwopartsoflocaledescriptionsasourstandardi18nlocalenames

OnLinuxandSolarissystemsyoucanusethelocale-acommandtogetalistofallsupportedregionalnamesYoucanusethislistasexamplesofsomecommonlocalesForBSDandothersystemsthereisnolocalecommandbuttheregionalinformationisstoredinusrsharelocale

SettingthelocaleNowthatwevedefinedwhatalocaleisweneedtobeabletosetitaccordingtovisitingusersinformation(eitherfromtheirpersonalsettingsthevisiteddomainnameetc)Herearesomemethodswecanusetosettheuserslocale

Fromthedomainname

WecansetauserslocaleviathedomainnameitselfwhentheapplicationusesdifferentdomainsfordifferentregionsForexamplewecanusewwwastacomasourdefaultEnglishwebsiteandthedomainnamewwwastacnasitsChinesecounterpartBysettingupseparatedomainsforseparateregionsyoucandetectandservetherequestedlocaleThistypeofsetuphasseveraladvantages

IdentifyingthelocaleviaURLisdistinctiveandunambiguousUsersintuitivelyknowwhichdomainnamestovisitfortheirspecificregionorlanguageImplementingthisschemeinaGoapplicationisverysimpleandconvenientandcanbeachievedthroughamapConducivetosearchenginecrawlerswhichcanimprovethesitesSEO

Wecanusethefollowingcodetoimplementacorrespondingdomainnamelocale

ifrHost==wwwastacom

i18nSetLocale(en)

elseifrHost==wwwastacn

i18nSetLocale(zh-CN)

elseifrHost==wwwastatw

i18nSetLocale(zh-TW)

Alternativelywecouldhavealsosetlocalesthroughtheuseofsub-domainsuchasenastacomforEnglishsitesandcnastacomforChinesesiteThisschemecanberealizedincodeasfollows

Timezone

230

prefix=stringsSplit(rHost)

ifprefix[0]==en

i18nSetLocale(en)

elseifprefix[0]==cn

i18nSetLocale(zh-CN)

elseifprefix[0]==tw

i18nSetLocale(zh-TW)

Settinglocalesfromthedomainnameaswevedoneabovehasitsadvantageshoweverl10nisgenerallynotimplementedinthiswayFirstofallthecostofdomainnames(althoughusuallyquiteaffordableindividually)canquicklyaddupgiventhateachlocalewillneeditsowndomainnameandoftenthenameofthedomainwillnotnecessarilyfitinwiththelocalcontextSecondlywedontwanttohavetoindividuallyconfigureeachwebsiteforeachlocaleRatherweshouldbeabletodothisprogrammaticallyforinstancebyusingURLparametersLetshavealookatthefollowingdescription

FromURLparameters

Themostcommonwayofimplementingl10nistosetthedesiredlocaledirectlyintheURLparameterssuchwwwastacomhellolocale=zhorwwwastacomzhhelloThiswaywecansettheregionlikesoi18nSetLocale(params[locale])

ThissetuphasalmostalltheadvantagesofprependingthelocaleinfrontofthedomainanditsRESTfulsowedontneedtoaddadditionalmethodstoimplementitThedownsidetothisapproachisthatitrequiresacorrespondinglocaleparameterinsideeachlinkwhichcanbequitecumbersomeandmayincreasecomplexityHoweverwecanwriteagenericfunctionthatproducestheselocale-specificURLssothatalllinksaregeneratedthroughitThisfunctionshouldautomaticallyaddalocaleparametertoeachlinksowhenusersclickthemweareabletoparsetheirrequestswitheaselocale=params[locale]

PerhapswewantourURLstolookevenmoreRESTfulForexamplewecouldmapeachofourresourcesunderaspecificlocalelikewwwastacomenbooksforourEnglishsiteandwwwastacomzhbooksfortheChineseoneThisapproachisnotonlymoreconducivetoURLSEObutisalsomorefriendlyforusersAnybodyvisitingthesiteshouldbeabletoaccesslocale-specificwebsiteresourcesdirectlyfromtheURLSuchURLaddressescanthenbepassedthroughtheapplicationrouterinordertoobtaintheproperlocale(refertotheRESTsectionwhichdescribestherouterplug-inimplementation)

muxGet(localebookslistbook)

Fromtheclientsettingsarea

InsomespecialcaseswerequireexplicitclientinformationinordertosetthelocaleratherthanobtainingitfromtheURLorURLparametersThisinformationmaycomedirectlyfromtheclientsbrowsersettingstheusersIPaddressorthelocationsettingsfilledoutbytheuseratthetimeofregistrationThisapproachismoresuitableforweb-basedapplications

Accept-Language

WhenaclientrequestsinformationusinganHTTPheadersetwiththeAccept-LanguagefieldwecanusethefollowingGocodetoparsetheheaderandsettheappropriateregioncode

AL=rHeaderGet(Accept-Language)

ifAL==en

i18nSetLocale(en)

elseifAL==zh-CN

i18nSetLocale(zh-CN)

elseifAL==zh-TW

i18nSetLocale(zh-TW)

Ofcourseinrealworldapplicationswemayrequiremorerigorousprocessesandrulesforsettinguserregions

Timezone

231

IPAddress

AnotherwayofsettingaclientsregionistolookattheusersIPaddressWecanusethepopularGeoIPGeoLiteCountryorCitylibrariestohelpusrelateuserIPaddressestotheircorrespondingregionalareasImplementingthismechanismisverysimpleweonlyneedtolookuptheusersIPaddressinsideourdatabaseandthenreturnlocale-specificcontentaccordingtowhichregionwasreturned

Userprofile

Youcanalsoletusersprovideyouwiththeirlocaleinformationthroughaninputelementsuchasadrop-downmenu(orsomethingsimilar)WhenwereceivethisinformationwecansaveittotheaccountassociatedwiththeusersprofileWhentheuserlogsinagainwewillbeabletocheckandsettheirlocalesettings-thisguaranteesthateverytimetheuseraccessesthewebsitethereturnedcontentwillbebasedontheirpreviouslysetlocale

SummaryInthissectionwevedemonstratedavarietyofwayswithwhichuserspecificlocalescanbedetectedandsetThesemethodsincludedsettingtheuserlocaleviadomainnamesubdomainnameURLparametersanddirectlyfromclientsettingsBycateringtothespecificneedsofspecificregionswecanprovideacomfortablefamiliarandintuitiveenvironmentforuserstoaccesstheservicesthatweprovide

LinksDirectoryPreviousoneInternationalizationandlocalizationNextsectionLocalizedresources

Timezone

232

102LocalizedResourcesTheprevioussectiondescribedhowtosetlocalesAfterthelocalehasbeensetwethenneedtoaddresstheproblemofstoringtheinformationcorrespondingtospecificlocalesThisinformationcanincludetextualcontenttimeanddatecurrencyvaluespicturesspecificfilesandotherviewresourcesInGoallofthiscontextualinformationisstoredinJSONformatonourbackendtobecalleduponandinjectedintoourviewswhenusersfromspecificregionsvisitourwebsiteForexampleEnglishandChinesecontentwouldbestoredinenjsonandzh-CNjsonfilesrespectively

LocalizedtextualcontentPlaintextisthemostcommonwayofrepresentinginformationinwebapplicationsandthebulkofyourlocalizedcontentwilllikelytakethisformThegoalistoprovidetextualcontentthatisbothidiomatictoregionalexpressionsandfeelsnaturalforforeignusersofyoursiteOnesolutionistocreateanestedmapoflocalesnativelanguagestringsandtheirlocalcounterpartsWhenclientsrequestpageswithsometextualcontentwefirstchecktheirdesiredlocalethenretrievethecorrespondingstringsfromtheappropriatemapThefollowingsnippetisasimpleexampleofthisprocess

packagemain

importfmt

varlocalesmap[string]map[string]string

funcmain()

locales=make(map[string]map[string]string2)

en=make(map[string]string10)

en[pea]=pea

en[bean]=bean

locales[en]=en

cn=make(map[string]string10)

cn[pea]=豌豆

cn[bean]=毛豆

locales[zh-CN]=cn

lang=zh-CN

fmtPrintln(msg(langpea))

fmtPrintln(msg(langbean))

funcmsg(localekeystring)string

ifvok=locales[locale]ok

ifv2ok=v[key]ok

returnv2

return

Theaboveexamplesetsupmapsoftranslatedstringsfordifferentlocales(inthiscasetheChineseandEnglishlocales)WemapourcntranslationstothesameEnglishlanguagekeyssothatwecanreconstructourEnglishtextmessageinChineseIfwewantedtoswitchourtexttoanyotherlocalewemayhaveimplementeditdbeasimplematterofsettingonelangvariable

Simplekey-valuesubstitutionscansometimesbeinadequateforourneedsForexampleifwehadaphrasesuchasIam30yearsoldwhere30isavariablehowwouldwelocalizeitIncaseslikethesewecancombineusethefmtPrintffunctiontoachievethedesiredresult

en[howold]=Iamdyearsold

cn[howold]=我今年d岁了

fmtPrintf(msg(langhowold)30)

Localizedresources

233

TheexamplecodeaboveisonlyforthepurposeofdemonstrationactuallocaledataistypicallystoredinJSONformatinourdatabaseallowingustoexecuteasimplejsonUnmarshaltopopulatemaplocaleswithourstringtranslations

LocalizeddateandtimeBecauseofourtimezoneconventionsthetimeinoneregionoftheworldcanbedifferentthanthetimeinanotherregionSimilarlythewayinwhichtimeisrepresentedcanalsovaryfromlocaletolocaleForexampleaChineseenvironmentmayread2012年10月24日星期三23时11分13秒CSTwhileinEnglishitmightbeWedOct24231113CST2012NotonlyaretherevariationsinlanguagebuttherearedifferencesinformattingalsoSowhenitcomestolocalizingdatesandtimesweneedtoaddressthefollowingtwopoints

1 timezones2 formattingissues

The$GOROOTlibtimepackagetimeinfozipdirectorycontainslocalescorrespondingtotimezonedefinitionsInordertoobtainthetimecorrespondingtoauserscurrentlocaleweshouldfirstusetimeLoadLocation(namestring)togetaLocationobjectcorrespondingtoourlocalepassinginastringrepresentingthelocalesuchasAsiaShanghaiorAmericaChicagoWecanthenusethisLocationobjectinconjunctionwithaTimeobject(obtainedbycallingtimeNow)togetthefinaltimeusingtheTimeobjectsInmethodAdetailedlookatthisprocesscanbeseenbelow(thisexampleusessomeofthevariablesfromtheexampleabove)

en[time_zone]=AmericaChicago

cn[time_zone]=AsiaShanghai

loc_=timeLoadLocation(msg(langtime_zone))

t=timeNow()

t=tIn(loc)

fmtPrintln(tFormat(timeRFC3339))

Wecanhandletextformattinginasimilarwaytosolveourtimeformattingproblem

en[date_format]=Y-m-dHMS

cn[date_format]=Y年m月d日H时M分S秒

fmtPrintln(date(msg(langdate_format)t))

funcdate(fomatstringttimeTime)string

yearmonthday=tDate()

hourminsec=tClock()

ParsingthecorrespondingYmdHMSandthenreturningtheinformation

Yreplacedby2012

mreplacedby10

dreplacedby24

LocalizedcurrencyvalueObviouslycurrencydiffersfromregiontoregionalsoWecantreatitthesamewaywetreatedourdates

en[money]=USDd

cn[money]=¥d元

fmtPrintln(date(msg(langdate_format)100))

funcmoney_format(fomatstringmoneyint64)string

returnfmtSprintf(fomatmoney)

Localizedresources

234

LocalizationofviewsandresourcesWecanservecustomizedviewswithdifferentimagescssjsandotherstaticresourcesdependingonthecurrentlocaleOnewaytoaccomplishthisisbyorganizingthesefilesintotheirrespectivelocalesHeresanexample

views

|--enEnglishTemplates

|--imagesstorepictureinformation

|--jsJSfiles

|--cssCSSfiles

indextplUserHome

logintplLogHome

|--zh-CNChineseTemplates

|--images

|--js

|--css

indextpl

logintpl

Withthisdirectorystructurewecanrenderlocale-specificviewslikeso

s1_=templateParseFiles(views+lang+indextpl)

VVLang=lang

s1Execute(osStdoutVV)

Theresourcesreferencedintheindextplfilecanbedealtwithasfollows

jsfile

ltscripttype=textjavascriptsrc=viewsVVLangjsjqueryjquery-180minjsgtltscriptgt

cssfile

ltlinkhref=viewsVVLangcssbootstrap-responsivemincssrel=stylesheetgt

Picturefiles

ltimgsrc=viewsVVLangimagesbtnpnggt

Withdynamicviewsandthewaywevelocalizedourresourceswewillbeabletoaddmorelocaleswithoutmucheffort

SummaryThissectiondescribedhowtouseandstorelocalresourcesWelearnedthatwecanuseconversionfunctionsandstringinterpolationforthisandsawthatmapscanbeaneffectivewayofstoringlocale-specificdataForthelatterwecouldsimplyextractthecorrespondinglocaleinformationwhenneeded-ifitwastextualcontentwedesiredourmappedtranslationsandidiomscouldbepipeddirectlytotheoutputIfitwassomethingmoresophisticatedliketimeorcurrencywesimplyusedthefmtPrintffunctiontoformatitbefore-handLocalizingourviewsandresourceswastheeasiestcaseandsimplyinvolvedorganizingourfilesintotheirrespectivelocalesthenreferencingthemfromtheirlocalerelativepaths

LinksDirectoryPrevioussectionSettingthedefaultregionNextsectionInternationalsites

Localizedresources

235

103InternationalsitesTheprevioussectionexplainedhowtodealwithlocalizedresourcesnamelybyusinglocaleconfigurationfilesSowhatcanwedoifweneedtodealwithmultiplelocalizedresourcesliketexttranslationstimesanddatesnumbersetcThissectionwilladdresstheseissuesonebyone

ManagingmultiplelocalepackagesInthedevelopmentofanapplicationoftenthefirstthingyouneedtodoistodecidewhetherornotyouwanttosupportmorethanonelanguageIfyoudodecidetosupportmultiplelanguagesyoullneedtodevelopanorganizationalstructuretofacilitatetheprocessofaddingmorelanguagesinthefutureOnewaywecandothisistoputallourrelatedlocalefilestogetherinaconfiglocalesdirectoryorsomethingofthelikeLetssupposeyouwanttosupportbothChineseandEnglishInthiscaseyoudbeplacingboththeenjsonandzhjsonlocalefilesintotheaforementionedfolderTheircontentswouldprobablylooksomethinglikethefollowing

zhjson

zh

submit提交

create创建

enjson

en

submitSubmit

createCreate

Wedecidedtousesome3rdpartyGopackagestohelpusinternationalizeourwebapplicationsInthecaseofgo-i18n(Amoreadvancedi18npackagecanbefoundhere)wefirsthavetoregisterourconfiglocalesdirectorytoloadallofourlocalefiles

Tr=i18nNewLocale()

TrLoadPath(configlocales)

ThispackageissimpletouseWecantestthatitworkslikeso

fmtPrintln(TrTranslate(submit))

Outputsubmit

TrSetLocale(zn)

fmtPrintln(TrTranslate(submit))

Outputs递交

AutomaticallyloadlocalpackageWevejustdescribedhowtoautomaticallyloadcustomlanguagepacksInfactthego-i18nlibrarycomespre-loadedwithabunchofdefaultformattinginformationsuchastimeandcurrencyformatsThesedefaultconfigurationscanbeoverriddenandcustomizedbyuserstosuittheirneedsConsiderthefollowingprocess

Internationalsites

236

Loadthedefaultconfigurationfileswhichareplacedbelowin`go-i18nlocales`

Fileshouldbenamedzhjsonen-jsonen-USjsonetcsowecancontinuouslysupportmorelanguages

func(ilIL)loadDefaultTranslations(dirPathstring)error

direrr=osOpen(dirPath)

iferr=nil

returnerr

deferdirClose()

nameserr=dirReaddirnames(-1)

iferr=nil

returnerr

for_name=rangenames

fullPath=pathJoin(dirPathname)

fierr=osStat(fullPath)

iferr=nil

returnerr

iffiIsDir()

iferr=illoadTranslations(fullPath)err=nil

returnerr

elseiflocale=ilmatchingLocaleFromFileName(name)locale=

fileerr=osOpen(fullPath)

iferr=nil

returnerr

deferfileClose()

iferr=illoadTranslation(filelocale)err=nil

returnerr

returnnil

Usingtheabovecodetoloadallofourdefaulttranslationswecanthenusethefollowingcodetoselectandusealocale

fmtPrintln(TrTime(timeNow()))

Output2009年1月08日星期四203758CST

fmtPrintln(TrTime(timeNow()long))

Output2009年1月08日

fmtPrintln(TrMoney(1111))

Outputyen1111

TemplatemapfuncAbovewevepresentedonewayofmanagingandintegratinganumberoflanguagepacksSomeofthefunctionsweveimplementedarebasedonthelogicallayerforexampleTrTranslateTrTimeTrMoneyandsoonInthelogicallayerwecanusethesefunctions(aftersupplyingtherequiredparameters)forapplyingyourtranslationsoutputtingtheresultsdirectlytothetemplatelayeratrendertimeWhatcanwedoifwewanttousethesefunctionsdirectlyinthetemplatelayerIncaseyouveforgottenearlierinthebookwementionedthatGotemplatessupportcustomtemplatefunctionsThefollowingcodeshowshoweasymapfuncistoimplement

1textinformation

Internationalsites

237

AsimpletextconversionfunctionimplementingamapfunccanbeseenbelowItusesTrTranslatetoperformtheappropriatetranslations

funcI18nT(argsinterface)string

ok=false

varsstring

iflen(args)==1

sok=args[0](string)

ifok

s=fmtSprint(args)

returnTrTranslate(s)

Weregisterthefunctionlikeso

tFuncs(templateFuncMapTI18nT)

Thenuseitfromyourtemplate

VSubmit|T

1 Thedateandtime

DatesandtimescalltheTrTimefunctiontoperformtheirtranslationsThemapfuncisimplementedasfollows

funcI18nTimeDate(argsinterface)string

ok=false

varsstring

iflen(args)==1

sok=args[0](string)

ifok

s=fmtSprint(args)

returnTrTime(s)

Registerthefunctionlikeso

tFuncs(templateFuncMapTDI18nTimeDate)

Thenuseitfromyourtemplate

VNow|TD

3CurrencyInformation

CurrenciesusetheTrMoneyfunctiontoconvertmoneyThemapFuncisimplementedasfollows

Internationalsites

238

funcI18nMoney(argsinterface)string

ok=false

varsstring

iflen(args)==1

sok=args[0](string)

ifok

s=fmtSprint(args)

returnTrMoney(s)

Registerthefunctionlikeso

tFuncs(templateFuncMapMI18nMoney)

Thenuseitfromyourtemplate

VMoney|M

SummaryInthissectionwelearnedhowtoimplementmultiplelanguagepacksinourwebapplicationsWesawthatthroughcustomlanguagepackswecannotonlyeasilyinternationalizeourapplicationsbutfacilitatetheadditionofotherlanguagesalso(throughtheuseofaconfigurationfile)Bydefaultthego-i18npackagewillprovidesomecommonconfigurationsfortimecurrencyetcwhichcanbeveryconvenienttouseWelearnedthatthesefunctionscanalsobeuseddirectlyfromourtemplatesusingmappingfunctionseachtranslatedstringcanbepipeddirectlytoourtemplatesThisenablesourwebapplicationstoaccommodatemultiplelanguageswithminimaleffort

LinksDirectoryPrevioussectionLocalizedresourcesNextsectionSummary

Internationalsites

239

104SummaryThroughthisintroductorychapteroni18nyoushouldnowbefamiliarwithsomeofthestepsandprocessesthatarenecessaryforinternationalizingandlocalizingyourwebsitesIvealsointroducedanopensourcesolutionfori18ninGogo-i18nUsingthisopensourcelibrarywecaneasilyimplementmulti-languageversionsofourwebapplicationsThisallowsourapplicationstobeflexibleandresponsivetolocalaudiencesallaroundtheworldIfyoufindanerrorinthisopensourcelibraryoranymissingfeaturespleaseopenanissueorapullrequestLetsstrivetomakeitoneofGosstandardlibraries

LinksDirectoryPrevioussectionInternationalsitesNextchapterErrorhandlingdebuggingandtesting

Summary

240

11ErrorHandlingDebuggingandTestingWeoftenseethemajorityofaprogrammersprogrammingtimespentoncheckingforbugsandworkingonbugfixesWhetheryouarerefactoringcodeorre-configuringsystemsmuchofyourtimewillundoubtedlybespenttroubleshootingandtestingFromtheoutsidepeoplemaythinkthatallwedoasprogrammersisdesignoursystemsandthenwriteourcodeTheymightthinkthatwehavetheidealjobWedoworkthatisveryengagingandimplementsystemsthathaveneverbeendonebeforeWhilethislastpartmaybetruewhattheydontknowisthatwespendthemajorityofourtimecyclingbetweentroubleshootingdebuggingandtestingourcodeOfcourseifyouhavegoodprogramminghabitsandthetechnologicalsolutionstohelpyoutakeonthesetasksthenyoucanminimizethetimespentdoingthesethingsenablingyoutofocusinsteadonmorevaluablethingsliketheapplicationlogic

UnfortunatelymanyprogrammersarenotthoroughinfulfillingtheirerrorhandlingdebuggingandtestingresponsibilitiesbeforehandInexperiencedprogrammerswilloftenonlymakeanefforttofinderrorsandflawsaftertheyhaveoccurredspendinghourslocatingandfixingproblemsaftertheapplicationisalreadyonlineItsgoodpractice(andprobablycommonsense)thatweshoulddesignourapplicationswithpropererrorhandlingtestcasesetcfromthegetgoThiswillmakeyourjobandthejobsofalltheotherdeveloperswhomaybeworkingonyourapplicationsomedaymucheasierwhentheyinevitablyneedtomodifythecodeorupgradethesystem

IntheprocessofdevelopingwebapplicationsyouwillinevitablyencounterunforeseenerrorsWhatsthemostefficientwayoffindingthecausesoftheseerrorsandsolvingthemSection111describeshowtohandleerrorsintheGolanguageaswellashowtodesignyourownerrorhandlingpackageandfunctionsSection112describeshowtouseGDBtodebugprogramsunderdynamicoperatingconditionsdependingonavarietyofvariableinformationWethendiscussapplicationmonitoringanddebuggingoperations

Section113willexplainunittestinginGoandfeaturesomein-depthdiscussionsandexamplesonhowtowriteunittestsaswellasdefiningGosunittestingrulesWellseehowfollowingtheseruleswillensurethatwhenupgradingormodifyingyourapplicationthetestcodewillbeabletorunsmoothly

ManyprogrammersavoidspendingtimetolearnandcultivategooddebuggingandtestinghabitsThischaptertakesontheseissueshead-onsoyouwonthavetorunawayfromthesetasksanylongerSinceyourejustlearninghowtobuildwebapplicationsinGoletsusethisopportunitytoestablishthesegoodhabitsfromtheverybeginning

LinksDirectoryPreviouschapterChapter10summaryNextsectionErrorhandling

Errorhandlingdebuggingandtesting

241

111ErrorhandlingGosmajordesignconsiderationsarerootedinthefollowingideasasimpleclearandconcisesyntax(similartoC)andstatementswhichareexplicitanddontcontainanyhiddenorunexpectedthingsGoserrorhandlingschemereflectsalloftheseprinciplesinthewaythatitsimplementedIfyourefamiliarwiththeClanguageyoullknowthatitscommontoreturn-1orNULLvaluestoindicatethatanerrorhasoccurredHoweveruserswhoarenotfamiliarwithCsAPIwillnotknowexactlywhatthesereturnvaluesmeanInCitsnotexplicitwhetheravalueof0indicatessuccessoffailureOntheotherhandGoexplicitlydefinesatypecallederrorforthesolepurposeofexpressingerrorsWheneverafunctionreturnswechecktoseewhethertheerrorvariableisnilornottodetermineiftheoperationwassuccessfulForexampletheosOpenfunctionfailsitwillreturnanon-nilerrorvariable

funcOpen(namestring)(fileFileerrerror)

HeresanexampleofhowwedhandleanerrorinosOpenFirstweattempttoopenafileWhenthefunctionreturnswechecktoseewhetheritsucceededornotbycomparingtheerrorreturnvaluewithnilcallinglogFataltooutputanerrormessageifitsanon-nilvalue

ferr=osOpen(filenameext)

iferr=nil

logFatal(err)

SimilartotheosOpenfunctionthefunctionsinGosstandardpackagesallreturnerrorvariablestofacilitateerrorhandlingThissectionwillgointodetailaboutthedesignoferrortypesanddiscusshowtoproperlyhandleerrorsinwebapplications

Errortypeerrorisaninterfacetypewiththefollowingdefinition

typeerrorinterface

Error()string

errorisabuilt-ininterfacetypeWecanfinditsdefinitioninthebuiltinpackagebelowWealsohavealotofinternalpackageswhichuseerrorinaprivatestructurecallederrorStringwhichimplementstheerrorinterface

errorStringisatrivialimplementationoferror

typeerrorStringstruct

sstring

func(eerrorString)Error()string

returnes

YoucanconvertaregularstringtoanerrorStringthrougherrorsNewinordertogetanobjectthatsatisfiestheerrorinterfaceItsinternalimplementationisasfollows

Newreturnsanerrorthatformatsasthegiventext

funcNew(textstring)error

returnamperrorStringtext

Errorhandling

242

ThefollowingexampledemonstrateshowtouseerrorsNew

funcSqrt(ffloat64)(float64error)

ifflt0

return0errorsNew(mathsquarerootofnegativenumber)

implementation

InthefollowingexamplewepassanegativenumbertoourSqrtfunctionCheckingtheerrvariablewecheckwhethertheerrorobjectisnon-nilusingasimplenilcomparisonTheresultofthecomparisonistruesofmtPrintln(thefmtpackagecallstheerrormethodwhendealingwitherrorcalls)iscalledtooutputanerror

ferr=Sqrt(-1)

iferr=nil

fmtPrintln(err)

CustomErrorsThroughtheabovedescriptionweknowthatagoErrorisaninterfaceBydefiningastructthatimplementsthisinterfacewecanimplementtheirerrordefinitionsHeresanexamplefromtheJSONpackage

typeSyntaxErrorstruct

msgstringerrordescription

Offsetint64wheretheerroroccurred

func(eSyntaxError)Error()stringreturnemsg

TheerrorsOffsetfieldwillnotbeprintedatruntimewhensyntaxerrorsoccurbutusingatypeassertionerrortypeyoucanprintthedesirederrormessage

iferr=decDecode(ampval)err=nil

ifserrok=err(jsonSyntaxError)ok

linecol=findLine(fserrOffset)

returnfmtErrorf(sddvfName()linecolerr)

returnerr

ItshouldbenotedthatwhenthefunctionreturnsacustomerrorthereturnvalueissettotherecommendedtypeoferrorratherthanacustomerrortypeBecarefulnottopre-declarevariablesofcustomerrortypesForexample

funcDecode()SyntaxError

errorwhichmayleadtothecallerserr=nilcomparisontoalwaysbetrue

varerrSyntaxErrorpre-declareerrorvariable

ifanerrorcondition

err=ampSyntaxError

returnerrerrorerralwaysequalnon-nilcausescallerserr=nilcomparisontoalwaysbetrue

Seehttpgolangorgdocfaqnil_errorforanindepthexplanation

TheaboveexampleshowshowtoimplementasimplecustomErrortypeButwhatifweneedmoresophisticatederrorhandlingInthiscasewehavetorefertothenetpackageapproach

Errorhandling

243

packagenet

typeErrorinterface

error

Timeout()boolIstheerroratimeout

Temporary()boolIstheerrortemporary

UsingtypeassertionwecancheckwhetherornotourerrorisoftypenetErrorasshowninthefollowingexampleThisallowsustorefineourerrorhandling-ifatemporaryerroroccursonthenetworkitwillsleepfor1secondthenretrytheoperation

ifnerrok=err(netError)okampampnerrTemporary()

timeSleep(1e9)

continue

iferr=nil

logFatal(err)

ErrorhandlingGohandleserrorsandchecksthereturnvaluesoffunctionsinaC-likefashionwhichisdifferenttohowmostoftheothermajorlanguagesdoThismakesthecodemoreexplicitandpredictablebutalsomoreverboseToreducetheredundancyofourerror-handlingcodewecanuseabstracterrorhandlingfunctionsthatallowustoimplementsimilarerrorhandlingbehaviour

funcinit()

httpHandleFunc(viewviewRecord)

funcviewRecord(whttpResponseWriterrhttpRequest)

c=appengineNewContext(r)

key=datastoreNewKey(cRecordrFormValue(id)0nil)

record=new(Record)

iferr=datastoreGet(ckeyrecord)err=nil

httpError(werrError()500)

return

iferr=viewTemplateExecute(wrecord)err=nil

httpError(werrError()500)

TheaboveexampledemonstratehowthedataaccessandtemplatecallhasdetectedanerrorWhenanerroroccursacalltounifiedhandlerhttpErrorreturnsa500errorcodetotheclientanddisplaysthecorrespondingerrordataButwhenmoreandmoreHandleFunccallsaremadesoerror-handlinglogiccodewillincreaseWecancustomizetheroutertoreducecode(refertothethirdchapterofHTTPformoredetail)

typeappHandlerfunc(httpResponseWriterhttpRequest)error

func(fnappHandler)ServeHTTP(whttpResponseWriterrhttpRequest)

iferr=fn(wr)err=nil

httpError(werrError()500)

AbovewevedefinedacustomrouterWecanthenregisterourhandlerasusual

Errorhandling

244

funcinit()

httpHandle(viewappHandler(viewRecord))

Theviewhandlercanthenbehandledbythefollowingcodeitisalotsimplerthanouroriginalimplementationisntit

funcviewRecord(whttpResponseWriterrhttpRequest)error

c=appengineNewContext(r)

key=datastoreNewKey(cRecordrFormValue(id)0nil)

record=new(Record)

iferr=datastoreGet(ckeyrecord)err=nil

returnerr

returnviewTemplateExecute(wrecord)

Theerrorhandlerexampleabovewillreturnthe500InternalErrorcodetouserswhenanyerrorsoccurinadditiontoprintingoutthecorrespondingerrorcodeInfactwecancustomizethetypeoferrorreturnedtooutputamoredeveloperfriendlyerrormessagewithinformationthatisusefulfordebugginglikeso

typeappErrorstruct

Errorerror

Messagestring

Codeint

Ourcustomroutercanbechangedaccordingly

typeappHandlerfunc(httpResponseWriterhttpRequest)appError

func(fnappHandler)ServeHTTP(whttpResponseWriterrhttpRequest)

ife=fn(wr)e=nileisappErrornotosError

c=appengineNewContext(r)

cErrorf(veError)

httpError(weMessageeCode)

Afterwevefinishedmodifyingourcustomerrorourlogiccanbechangedasfollows

funcviewRecord(whttpResponseWriterrhttpRequest)appError

c=appengineNewContext(r)

key=datastoreNewKey(cRecordrFormValue(id)0nil)

record=new(Record)

iferr=datastoreGet(ckeyrecord)err=nil

returnampappErrorerrRecordnotfound404

iferr=viewTemplateExecute(wrecord)err=nil

returnampappErrorerrCantdisplayrecord500

returnnil

AsshownabovewecanreturndifferenterrorcodesanderrormessagesinourviewsdependingonthesituationAlthoughthisversionofourcodefunctionssimilarlytothepreviousversionitsmoreexplicitanditserrormessagepromptsaremorecomprehensibleAllofthesefactorscanhelptomakeyourapplicationmorescalableascomplexityincreases

Summary

Errorhandling

245

FaulttoleranceisaveryimportantaspectofanyprogramminglanguageInGoitisachievedthrougherrorhandlingAlthoughErrorisonlyoneinterfaceitcanhavemanyvariationsinthewaythatitsimplementedandwecancustomizeitaccordingtoourneedsonacasebycasebasisByintroducingthesevariouserrorhandlingconceptswehopethatyouwillhavegainedsomeinsightonhowtoimplementbettererrorhandlingschemesinyourownwebapplications

LinksDirectoryPrevioussectionErrorhandlingdebuggingandtestingNextsectionDebuggingbyusingGDB

Errorhandling

246

112DebuggingwithGDBDuringthedevelopmentprocessofanyapplicationdeveloperswillalwaysneedtoperformsomekindofcodedebuggingPHPPythonandmostoftheotherdynamiclanguagesareabletobemodifiedatruntimeaslongasthemodificationsdonotexplicitlyneedtobecompiledWecaneasilyprintdataindynamicoperatingenvironmentsoutputtingourchangesandprintingvariableinformationdirectlyInGoyoucanofcoursespeckleyourcodewithPrintlnsbefore-handtodisplayvariableinformationfordebuggingpurposesbutanychangestoyourcodeneedtoberecompiledeverytimeThiscanquicklybecomecumbersomeIfyouveprogrammedinPythonorJavascriptyoullknowthattheformerprovidestoolssuchaspdbandipdbfordebuggingandthelatterhassimilartoolsthatareabletodynamicallydisplayvariableinformationandfacilitatesingle-stepdebuggingFortunatelyGohasnativesupportforasimilartoolwhichprovidessuchdebuggingfeaturesGDBThissectionservesasabriefintroductionintodebuggingGoapplicationsusingGDB

GDBdebuggingprofileGDBisapowerfuldebuggingtooltargetingUNIX-likesystemsreleasedbytheFSF(FreeSoftwareFoundation)GDBallowsustodothefollowingthings

1 Initialsettingscanbecustomizeaccordingtothespecificrequirementsofyourapplication2 Canbesetsothattheprogrambeingdebuggedinthedevelopersconsolestopsattheprescribedbreakpoints

(breakpointscanbeconditionalexpressions)3 Whentheprogramhasbeenstoppedyoucancheckitscurrentstatetoseewhathappened4 Dynamicallychangethecurrentprogramsexecutionenvironment

TodebugyourGoapplicationsusingGDBtheversionofGDByouusemustbegreaterthan71

WhencompilingGoprogramsthefollowingpointsrequireparticularattention

1 Using-ldflags-swillpreventthestandarddebugginginformationfrombeingprinted2 Using-gcflags-N-lwillpreventGofromperformingsomeofitsautomatedoptimizations-optimizationsof

aggregatevariablesfunctionsetcTheseoptimizationscanmakeitverydifficultforGDBtodoitsjobsoitsbesttodisablethematcompiletimeusingtheseflags

SomeofGDBsmostcommonlyusedcommandsareasfollows

list

AlsousedinitsabbreviatedformllistisusedtodisplaythesourcecodeBydefaultitdisplaystenlinesofcodeandyoucanspecifythelineyouwishtodisplayForexamplethecommandlist15displaystenlinesofcodecenteredaroundline15asshownbelow

10timeSleep(2timeSecond)

11clt-i

12

13close(c)

14

15

16funcmain()

17msg=Startingmain

18fmtPrintln(msg)

19bus=make(chanint)

break

AlsousedinitsabbreviatedformbbreakisusedtosetbreakpointsandtakesasanargumentthatdefineswhichpointtosetthebreakpointatForexampleb10setsabreakpointatthetenthrow

delete

DebuggingbyusingGDB

247

AlsousedinitsabbreviatedformddeleteisusedtodeletebreakpointsThebreakpointissetfollowedbytheserialnumberTheserialnumbercanbeobtainedthroughtheinfobreakpointscommandBreakpointssetwiththeircorrespondingserialnumbersaredisplayedasfollowstosetabreakpointnumber

NumTypeDispEnbAddressWhat

2breakpointkeepy0x0000000000400dc3inmainmainathomexiemengjungdbgo23

breakpointalreadyhit1time

backtrace

Abbreviatedasbtthiscommandisusedtoprinttheexecutionofthecodeforinstance

0mainmain()athomexiemengjungdbgo23

10x000000000040d61einruntimemain()athomexiemengjungosrcpkgruntimeprocc244

20x000000000040d6c1inschedunlock()athomexiemengjungosrcpkgruntimeprocc267

30x0000000000000000in()

info

TheinfocommandcanbeusedinconjunctionwithseveralparameterstodisplayinformationThefollowingparametersarecommonlyused

infolocals

Displaysthecurrentlyexecutingprogramsvariablevalues

infobreakpoints

Displaysalistofcurrentlysetbreakpoints

infogoroutines

Displaysthecurrentlistofrunninggoroutinesasshowninthefollowingcodewiththeindicatingthecurrentexecution

1runningruntimegosched

2syscallruntimeentersyscall

3waitingruntimegosched

4runnableruntimegosched

print

AbbreviatedaspthiscommandisusedtoprintvariablesorotherinformationIttakesasargumentsthevariablenamestobeprintedandofcoursetherearesomeveryusefulfunctionssuchas$len()and$cap()thatcanbeusedtoreturnthelengthorcapacityofthecurrentstringsslicesormaps

whatis

whatisisusedtodisplaythecurrentvariabletypefollowedbythevariablenameForinstancewhatismsgwilloutputthefollowing

type=structstring

next

Abbreviatedasnnextisusedinsingle-stepdebuggingtoskiptothenextstepWhenthereisabreakpointyoucanenterntojumptothenextsteptocontinue

continue

AbbreviatedasccontinueisusedtojumpoutofthecurrentbreakpointandcanbefollowedbyaparameterNwhichspecifiesthenumberoftimestoskipthebreakpoint

setvariable

DebuggingbyusingGDB

248

ThiscommandisusedtochangethevalueofavariableintheprocessItcanbeusedlikesosetvariableltvargt=ltvaluegt

ThedebuggingprocessNowletstakealookatthefollowingcodetoseehowGDBistypicallyusedtodebugGoprograms

packagemain

import(

fmt

time

)

funccounting(cchanlt-int)

fori=0ilt10i++

timeSleep(2timeSecond)

clt-i

close(c)

funcmain()

msg=Startingmain

fmtPrintln(msg)

bus=make(chanint)

msg=startingagofunc

gocounting(bus)

forcount=rangebus

fmtPrintln(countcount)

Nowwecompilethefilecreatinganexecutablefilecalledgdbfile

gobuild-gcflags-N-lgdbfilego

UsetheGDBcommandtostartdebugging

gdbgdbfile

AfterfirststartingGDByoullhavetoentertheruncommandtoseeyourprogramrunningYouwillthenseetheprogramoutputthefollowingexecutingtheprogramdirectlyfromthecommandlinewilloutputexactlythesamething

(gdb)run

Startingprogramhomexiemengjungdbfile

Startingmain

count0

count1

count2

count3

count4

count5

count6

count7

count8

count9

[LWP2771exited]

[Inferior1(process2771)exitednormally]

Oknowthatweknowhowtogettheprogramupandrunningletstakealookatsettingbreakpoints

DebuggingbyusingGDB

249

(gdb)b23

Breakpoint1at0x400d8dfilehomexiemengjungdbfilegoline23

(gdb)run

Startingprogramhomexiemengjungdbfile

Startingmain

[NewLWP3284]

[SwitchingtoLWP3284]

Breakpoint1mainmain()athomexiemengjungdbfilego23

23fmtPrintln(countcount)

Intheaboveexampleweusetheb23commandtosetabreakpointonline23ofourcodethenenterruntostarttheprogramWhenourprogramstopsatourbreakpointwetypicallyneedtolookatthecorrespondingsourcecodecontextEnteringthelistcommandintoourGDBsessionwecanseethefivelinesofcodeprecedingourbreakpoint

(gdb)list

18fmtPrintln(msg)

19bus=make(chanint)

20msg=startingagofunc

21gocounting(bus)

22forcount=rangebus

23fmtPrintln(countcount)

24

25

NowthatGDBisrunningthecurrentprogramenvironmentwehaveaccesstosomeusefuldebugginginformationthatwecanprintoutToseethecorrespondingvariabletypesandvaluestypeinfolocals

(gdb)infolocals

count=0

bus=0xf840001a50

(gdb)pcount

$1=0

(gdb)pbus

$2=(chanint)0xf840001a50

(gdb)whatisbus

type=chanint

Tolettheprogramcontinueitsexecutionuntilthenextbreakpointentertheccommand

(gdb)c

Continuing

count0

[NewLWP3303]

[SwitchingtoLWP3303]

Breakpoint1mainmain()athomexiemengjungdbfilego23

23fmtPrintln(countcount)

(gdb)c

Continuing

count1

[SwitchingtoLWP3302]

Breakpoint1mainmain()athomexiemengjungdbfilego23

23fmtPrintln(countcount)

AftereachcthecodewillexecuteoncethenjumptothenextiterationoftheforloopItwillofcoursecontinuetoprintouttheappropriateinformation

LetssaythatyouneedtochangethecontextvariablesinthecurrentexecutionenvironmentskiptheprocessthencontinuetothenextstepYoucandosobyfirstusinginfolocalstogetthevariablestatesthenthesetvariablecommandtomodifythem

DebuggingbyusingGDB

250

(gdb)infolocals

count=2

bus=0xf840001a50

(gdb)setvariablecount=9

(gdb)infolocals

count=9

bus=0xf840001a50

(gdb)c

Continuing

count9

[SwitchingtoLWP3302]

Breakpoint1mainmain()athomexiemengjungdbfilego23

23fmtPrintln(countcount)

FinallywhilerunningtheprogramcreatesanumberofgoroutinesWecanseewhateachgoroutineisdoingusinginfogoroutines

(gdb)infogoroutines

1runningruntimegosched

2syscallruntimeentersyscall

3waitingruntimegosched

4runnableruntimegosched

(gdb)goroutine1bt

00x000000000040e33binruntimegosched()athomexiemengjungosrcpkgruntimeprocc927

10x0000000000403091inruntimechanrecv(c=voidep=voidselected=voidreceived=void)

athomexiemengjungosrcpkgruntimechanc327

20x000000000040316finruntimechanrecv2(t=voidc=void)

athomexiemengjungosrcpkgruntimechanc420

30x0000000000400d6finmainmain()athomexiemengjungdbfilego22

40x000000000040d0c7inruntimemain()athomexiemengjungosrcpkgruntimeprocc244

50x000000000040d16ainschedunlock()athomexiemengjungosrcpkgruntimeprocc267

60x0000000000000000in()

FromthegoroutinescommandwecanhaveabetterpictureofwhatGosruntimesystemisdoinginternallythecallingsequenceforeachfunctionisplainlydisplayed

SummaryInthissectionweintroducedsomebasiccommandsfromtheGDBdebuggerthatyoucanusetodebugyourGoapplicationsTheseincludedtherunprintinfosetvariablecontinuelistandbreakcommandsamongothersFromthebriefexamplesaboveIhopethatyouwillhaveabetterunderstandingofhowthedebuggingprocessworksinGousingtheGDBdebuggerIfyouwanttogetmoredebuggingtipspleaserefertotheGDBmanualonitsofficialwebsite

LinksDirectoryPrevioussectionErrorhandlingNextsectionWritetestcases

DebuggingbyusingGDB

251

113WritingtestcasesInthecourseofdevelopmentaveryimportantstepistotestourcodetoensureitsqualityandintegrityWeneedtomakesurethateveryfunctionreturnstheexpectedresultandthatourcodeperformsoptimallyWealreadyknowthatthefocusofunittestsistofindlogicalerrorsinthedesignorimplementationofprogramsTheyareusedtodetectandexposeproblemsincodeearlyonsothatwecanmoreeasilyfixthembeforetheygetoutofhandWealsoknowthatperformancetestsareconductedforthepurposeofoptimizingourcodesothatitisstableunderloadandcanmaintainahighlevelofconcurrencyInthissectionwelltakealookatsomecommonlyaskedquestionsabouthowunitandperformancetestsareimplementedinGo

TheGolanguagecomeswithalightweighttestingframeworkcalledtestingandwecanusethegotestcommandtoexecuteunitandperformancetestsGostestingframeworkworkssimilarlytotestingframeworksinotherlanguagesYoucandevelopallsortsoftestsuiteswiththemwhichmayincludetestsforunittestesbenchmarkingstresstestsetcLetslearnabouttestinginGostepbystep

HowtowritetestcasesSincethegotestcommandcanonlybeexecutedinadirectorycontainingallcorrespondingfileswearegoingtocreateanewprojectdirectorygotestsothatallofourcodeandtestcodeareinthesamedirectory

Letsgoaheadandcreatetwofilesinthedirectorycalledgotestgoandgotest_testgo

1 GotestgoThisfiledeclaresourpackagenameandhasafunctionthatperformsadivisionoperation

packagegotest

import(

errors

)

funcDivision(abfloat64)(float64error)

ifb==0

return0errorsNew(Divisorcannotbe0)

returnabnil

2 Gotest_testgoThisisourunittestfileKeepinmindthefollowingprinciplesfortestfiles

3 Filenamesmustendin_testgosothatgotestcanfindandexecutetheappropriatecode

4 Youhavetoimportthetestingpackage5 AlltestcasefunctionsbeginwithTest6 Testcasesfollowthesourcecodeorder7 TestfunctionsoftheformTestXxx()takeatestingTargumentwecanusethistypetorecorderrorsortogetthe

testingstatus8 InfunctionsoftheformfuncTestXxx(ttestingT)theXxxsectioncanbeanyalphanumericcombinationbutthe

firstlettercannotbealowercaseletter[az]ForexampleTestintdivwouldbeaninvalidfunctionname9 BycallingoneoftheErrorErrorfFailNowFatalorFatalIfmethodsoftestingTonourtestingfunctions

wecanfailthetestInadditionwecancalltheLogmethodoftestingTtorecordtheinformationintheerrorlog

Hereisourtestcode

Writetestcases

252

packagegotest

import(

testing

)

funcTest_Division_1(ttestingT)

tryaunittestonfunction

ifie=Division(62)i=3||e=nil

Ifitisnotasexpectedthenthetesthasfailed

tError(divisionfunctiontestsdonotpass)

else

recordtheexpectedinformation

tLog(firsttestpassed)

funcTest_Division_2(ttestingT)

tError(justdoesnotpass)

Whenexecutinggotestintheprojectdirectoryitwilldisplaythefollowinginformation

---FAILTest_Division_2(000seconds)

gotest_testgo16isnotpassed

FAIL

exitstatus1

FAILgotest0013s

Wecanseefromthisresultthatthesecondtestfunctiondoesnotpasssincewewroteinadead-endusingtErrorButwhatabouttheperformanceofourfirsttestfunctionBydefaultexecutinggotestdoesnotdisplaytestresultsWeneedtosupplytheverboseargument-vlikegotest-vtodisplaythefollowingoutput

===RUNTest_Division_1

---PASSTest_Division_1(000seconds)

gotest_testgo11firsttestpassed

===RUNTest_Division_2

---FAILTest_Division_2(000seconds)

gotest_testgo16isnotpassed

FAIL

exitstatus1

FAILgotest0012s

TheaboveoutputshowsindetailtheresultsofourtestWeseethatthetestfunction1Test_Division_1passesandthetestfunction2Test_Division_2failsfinallyconcludingthatourtestsuitedoesnotpassNextwemodifythetestfunction2withthefollowingcode

funcTest_Division_2(ttestingT)

tryaunittestonfunction

if_e=Division(60)e==nil

Ifitisnotasexpectedthentheerror

tError(Divisiondidnotworkasexpected)

else

recordsomeoftheinformationyouexpecttorecord

tLog(onetestpassede)

Weexecutegotest-vonceagainThefollowinginformationshouldnowbedisplayed-thetestsuitehaspassed~

Writetestcases

253

===RUNTest_Division_1

---PASSTest_Division_1(000seconds)

gotest_testgo11firsttestpassed

===RUNTest_Division_2

---PASSTest_Division_2(000seconds)

gotest_testgo20onetestpasseddivisorcannotbe0

PASS

okgotest0013s

HowtowritestresstestsStresstestingisusedtodetectfunctionperformanceandbearssomeresemblancetounittesting(whichwewillnotgetintohere)howeverweneedtopayattentiontothefollowingpoints

StresstestsmustfollowthefollowingformatwhereXXXcanbeanyalphanumericcombinationanditsfirstlettercannotbealowercaseletter

funcBenchmarkXXX(btestingB)

BydefaultGotestdoesnotperformfunctionstresstestsIfyouwanttoperformstresstestsyouneedtosettheflag-testbenchwiththeformat-testbench=test_name_regexForinstancetorunallstresstestsinyoursuiteyouwouldrungotest-testbench=

InyourstresstestspleaseremembertousetestingBNanyloopbodiessothatthetestscanberunproperlyAsbeforetestfilenamesmustendin_testgo

Herewecreateastresstestfilecalledwebbench_testgo

packagegotest

import(

testing

)

funcBenchmark_Division(btestingB)

fori=0iltbNi++usebNforlooping

Division(45)

funcBenchmark_TimeConsumingFunction(btestingB)

bStopTimer()callthefunctiontostopthestresstesttimecount

Dosomeinitializationworksuchasreadingfiledatadatabaseconnectionsandthelike

Sothatourbenchmarksreflecttheperformanceofthefunctionitself

bStartTimer()re-starttime

fori=0iltbNi++

Division(45)

Wethenexecutethegotest-filewebbench_testgo-testbench=commandwhichoutputsthefollowingresults

PASS

Benchmark_Division500000000776nsop

Benchmark_TimeConsumingFunction500000000780nsop

okgotest9364s

TheaboveresultsshowthatwedidnotperformanyofourTestXXXunittestfunctionsandinsteadonlyperformedourBenchmarkXXXtests(whichisexactlyasexpected)ThefirstBenchmark_DivisiontestshowsthatourDivision()functionexecuted500milliontimeswithanaverageexecutiontimeof776nsThesecondBenchmark_TimeConsumingFunctionshows

Writetestcases

254

thatourTmeConsumingFunctionexecuted500milliontimeswithanaverageexecutiontimeof780nsFinallyitoutputsthetotalexecutiontimeofourtestsuite

SummaryFromourbriefencounterwithunitandstresstestinginGowecanseethatthetestingpackageisverylightweightyetpackedwithusefulutilitiesWesawthatwritingunitandstresstestscanbeverysimpleandrunningthemcanbeeveneasierwithGosbuilt-ingotestcommandEverytimewemodifyourcodewecansimplyrungotesttobeginregressiontesting

LinksDirectoryPrevioussectionDebuggingusingGDBNextsectionSummary

Writetestcases

255

114SummaryOverthecourseofthelastthreesectionsweveintroducedhowtohandleerrorsinGofirstlookingatgooderrorhandlingpracticesanddesignthenlearninghowtousetheGDBdebuggereffectivelyWesawthatwithGDBwecanperformsingle-stepdebuggingviewandmodifyourprogramvariablesduringexecutionandprintouttherelevantprocessinformationFinallywedescribedhowtouseGosbuilt-intestingframeworktowriteunitandstresstestsProperlyusingthisframeworkallowsustoeasilymakeanyfuturechangestoourcodeandperformthenecessaryregressiontestingGoodwebapplicationsmusthavegooderrorhandlingandpartofthatishavingreadableerrorsanderrorhandlingmechanismswhichcanscaleinapredictablemannerUsingthetoolsmentionedaboveaswellaswritinghighqualityandthoroughunitandstresstestswecanhavepeaceofmindknowingthatonceourapplicationsarelivetheycanmaintainoptimalperformanceandrunasexpected

LinksDirectoryPrevioussectionWritetestcasesNextchapterDeploymentandmaintenance

Summary

256

12DeploymentandmaintenanceSofarwevecoveredthebasicsofdevelopingdebuggingandtestingwebapplicationsinGoAsisoftensaidhoweverthelast10ofdevelopmenttakes90ofthetimeInthischapterwewillbeemphasizingthislast10ofapplicationdevelopmentinordertotrulycraftreliableandhighqualitywebapplicationsInthefirstsectionwewillexaminehowproductionservicesgeneratelogsandtheprocessofloggingitselfThesecondsectionwilldescribedealingwithruntimeerrorsandhowtomanagethemwhentheyoccursothattheimpactonendusersisminimizedInthethirdsectionwetacklethesubjectofdeployingstandaloneGoprogramswhichcanbetrickyatfirstAsyoumightknowGoprogramscannotbewrittenwithdaemonslikeyouwouldwithalanguagesuchasCWelldiscusshowbackgroundprocessesaretypicallymanagedinGoFinallyourfourthandlastsectionwilladdresstheprocessofbackingupandrecoveringapplicationdatainGoWelltakealookatsometechniquesforensuringthatintheeventofacrashwewillbeabletomaintaintheintegrityofourdata

LinksDirectoryPreviouschapterChapter11summaryNextsectionLogs

Deploymentandmaintenance

257

121LogsWewanttobuildwebapplicationsthatcankeeptrackofeventswhichhaveoccurredthroughoutexecutioncombiningthemallintooneplaceforeasyaccesslateronwhenweinevitablyneedtoperformdebuggingoroptimizationtasksGoprovidesasimplelogpackagewhichwecanusetohelpusimplementsimpleloggingfunctionalityLogscanbeprintedusingGosfmtpackagecalledinsideerrorhandlingfunctionsforgeneralerrorloggingGosstandardpackageonlycontainsbasicfunctionalityforlogginghoweverTherearemanythirdpartyloggingtoolsthatwecanusetosupplementitifyourneedsaremoresophisticated(toolssimilartolog4jandlog4cppifyouveeverhadtodealwithlogginginJavaorC++)Apopularandfullyfeaturedopen-sourceloggingtoolinGoistheseelogloggingframeworkLetstakealookathowwecanuseseelogtoperformlogginginourGoapplications

IntroductiontoseelogSeelogisaloggingframeworkforGothatprovidessomesimplefunctionalityforimplementingloggingtaskssuchasfilteringandformattingItsmainfeaturesareasfollows

DynamicconfigurationviaXMLyoucanloadconfigurationparametersdynamicallywithoutrecompilingyourprogramSupportshotupdatestheabilitytodynamicallychangetheconfigurationwithouttheneedtorestarttheapplicationSupportsmulti-outputstreamsthatcansimultaneouslypipelogoutputtomultiplestreamssuchasafilestreamnetworkflowetcSupportfordifferentlogoutputs

CommandlineoutputFileOutputCachedoutputSupportlogrotateSMTPMail

TheaboveisonlyapartiallistofseelogsfeaturesTofullytakeadvantageofallofseelogsfunctionalityhavealookatitsofficialwikiwhichthoroughlydocumentswhatyoucandowithitLetsseehowweduseseeloginourprojects

Firstinstallseelog

goget-ugithubcomcihubseelog

Thenletswriteasimpleexample

packagemain

importloggithubcomcihubseelog

funcmain()

deferlogFlush()

logInfo(HellofromSeelog)

CompileandruntheprogramIfyouseeaHellofromseeloginyourapplicationlogseeloghasbeensuccessfullyinstalledandisrunningoperatingnormally

CustomlogprocessingwithseelogSeelogsupportscustomlogprocessingThefollowingcodesnippetisbasedontheitscustomlogprocessingpartofitspackage

Logs

258

packagelogs

import(

errors

fmt

seeloggithubcomcihubseelog

io

)

varLoggerseelogLoggerInterface

funcloadAppConfig()

appConfig=`

ltseelogminlevel=warngt

ltoutputsformatid=commongt

ltrollingfiletype=sizefilename=datalogsrolllogmaxsize=100000maxrolls=5gt

ltfilterlevels=criticalgt

ltfilepath=datalogscriticallogformatid=criticalgt

ltsmtpformatid=criticalemailsenderaddress=astaxiegmailcomsendername=ShortUrlAPIhostname=smtp

gmailcomhostport=587username=mailusernamepassword=mailpasswordgt

ltrecipientaddress=xiemengjungmailcomgt

ltsmtpgt

ltfiltergt

ltoutputsgt

ltformatsgt

ltformatid=commonformat=DateTime[LEV]Msgngt

ltformatid=criticalformat=FileFullPathFuncMsgngt

ltformatid=criticalemailformat=CriticalerroronourservernTimeDateRelFileFuncMsgnSent

bySeeloggt

ltformatsgt

ltseeloggt

`

loggererr=seelogLoggerFromConfigAsBytes([]byte(appConfig))

iferr=nil

fmtPrintln(err)

return

UseLogger(logger)

funcinit()

DisableLog()

loadAppConfig()

DisableLogdisablesalllibrarylogoutput

funcDisableLog()

Logger=seelogDisabled

UseLoggerusesaspecifiedseelogLoggerInterfacetooutputlibrarylog

UsethisfuncifyouareusingSeelogloggingsysteminyourapp

funcUseLogger(newLoggerseelogLoggerInterface)

Logger=newLogger

Theaboveimplementsthethreemainfunctions

DisableLog

InitializesaglobalvariableLoggerwithseelogdisabledmainlyinordertopreventtheloggerfrombeingrepeatedlyinitialized

LoadAppConfig

InitializestheconfigurationsettingsofseelogaccordingtoaconfigurationfileInourexamplewearereadingtheconfigurationfromanin-memorystringbutofcourseyoucanreaditfromanXMLfilealsoInsidetheconfigurationwesetupthefollowingparameters

Logs

259

Seelog

TheminlevelparameterisoptionalIfconfiguredlogginglevelswhicharegreaterthanorequaltothespecifiedlevelwillberecordedTheoptionalmaxlevelparameterissimilarlyusedtoconfigurethemaximumloggingleveldesired

Outputs

ConfigurestheoutputdestinationInourparticularcasewechannelourloggingdataintotwooutputdestinationsThefirstisarollinglogfilewherewecontinuouslysavethemostrecentwindowofloggingdataTheseconddestinationisafilteredlogwhichrecordsonlycriticallevelerrorsWeadditionallyconfigureittoalertusviaemailwhenthesetypesoferrorsoccur

Formats

DefinesthevariousloggingformatsYoucanusecustomformattingorpredefinedformatting-afulllistofpredefinedformatscanbefoundonseelogswiki

UseLogger

Setthecurrentloggerasourlogprocessor

AbovewevedefinedandconfiguredacustomlogprocessingpackageThefollowingcodedemonstrateshowweduseit

packagemain

import(

nethttp

projectlogs

projectconfigs

projectroutes

)

funcmain()

addr_=configsMainConfigString(serveraddr)

logsLoggerInfo(Startserveratvaddr)

err=httpListenAndServe(addrroutesNewMux())

logsLoggerCritical(Servererrverr)

EmailnotificationsTheaboveexampleexplainshowtosetupemailnotificationswithseelogAsyoucanseeweusedthefollowingsmtpconfiguration

ltsmtpformatid=criticalemailsenderaddress=astaxiegmailcomsendername=ShortUrlAPIhostname=smtpgmailcom

hostport=587username=mailusernamepassword=mailpasswordgt

ltrecipientaddress=xiemengjungmailcomgt

ltsmtpgt

WesettheformatofouralertmessagesthroughthecriticalemailconfigurationprovidingourmailserverparameterstobeabletoreceivethemWecanalsoconfigureournotifiertosendoutalertstoadditionalusersusingtherecipientconfigurationItsasimplematterofaddingonelineforeachadditionalrecipient

Totestwhetherornotthiscodeisworkingproperlyyoucanaddafakecriticalmessagetoyourapplicationlikeso

logsLoggerCritical(testCriticalmessage)

Dontforgettodeleteitonceyouredonetestingorwhenyourapplicationgoesliveyourinboxmaybefloodedwithemailnotifications

NowwheneverourapplicationlogsacriticalmessagewhileonlineyouandyourspecifiedrecipientswillreceiveanotificationemailYouandyourteamcanthenprocessandremedythesituationinatimelymanner

Logs

260

UsingapplicationlogsWhenitcomestologseachapplicationsuse-casemayvaryForexamplesomepeopleuselogsfordataanalysispurposesothersforperformanceoptimizationSomelogsareusedtoanalyzeuserbehaviorandhowpeopleinteractwithyourwebsiteOfcoursetherearelogswhicharesimplyusedtorecordapplicationeventsasauxiliarydataforfindingproblems

AsanexampleletssayweneedtotrackuserattemptsatloggingintooursystemThisinvolvesrecordingbothsuccessfulandunsuccessfulloginattemptsintoourlogWedtypicallyusetheInfologleveltorecordthesetypesofeventsratherthansomethingmoreseriouslikewarnIfyoureusingalinux-typesystemyoucanconvenientlyviewallunsuccessfulloginattemptsfromthelogusingthegrepcommandlikeso

catdatalogsrolllog|grepfailedlogin

2012-12-11111200WARNfailedloginattemptfrom11223344usernamepassword

ThiswaywecaneasilyfindtheappropriateinformationinourapplicationlogwhichcanhelpustoperformstatisticalanalysisifneededInadditionwealsoneedtoconsiderthesizeoflogsgeneratedbyhigh-trafficwebapplicationsTheselogscansometimesgrowunpredictablyToresolvethisissuewecansetseelogupwiththelogrotateconfigurationtoensurethatsinglelogfilesdonotconsumeexcessivediskspace

SummaryInthissectionwevelearnedthebasicsofseelogandhowtobuildacustomloggingsystemwithitWesawthatwecaneasilyconfigureseelogintoaspowerfulalogprocessingsystemasweneedusingittosupplyuswithreliablesourcesofdataforanalysisThroughloganalysiswecanoptimizeoursystemandeasilylocatethesourcesofproblemswhentheyariseInadditionseelogshipswithvariousdefaultloglevelsWecanusetheminlevelconfigurationinconjunctionwithalogleveltoeasilysetuptestsorsendautomatednotificationmessages

LinksDirectoryPrevioussectionDeploymentandmaintenanceNextsectionErrorsandcrashes

Logs

261

122ErrorsandcrashesOnceourwebapplicationsgoliveitslikelythattherewillbesomeunforeseenerrorsAfewexampleofcommonerrorsthatmayoccurinthecourseofyourapplicationsdailyoperationsarelistedbelow

DatabaseErrorserrorsrelatedtoaccessingthedatabaseserverorstoreddataThefollowingaresomedatabaseerrorswhichyoumayencounter

ConnectionErrorsindicatesthataconnectiontothenetworkdatabaseservercouldnotbeestablishedasuppliedusernameorpasswordisincorrectorthatthedatabasedoesnotexist

QueryErrorstheillegalorincorrectuseofanSQLquerycanraiseanerrorsuchasthisThesetypesoferrorscanbeavoidedthroughrigoroustestingDataErrorsdatabaseconstraintviolationsuchasattemptingtoinsertafieldwithaduplicateprimarykeyThesetypesoferrorscanalsobeavoidedthroughrigoroustestingbeforedeployingyourapplicationintoaproductionenvironmentApplicationRuntimeErrorsThesetypesoferrorsvarygreatlycoveringalmostallerrorcodeswhichmayappearduringruntimePossibleapplicationerrorsareasfollows

FilesystemandpermissionerrorswhentheapplicationattemptstoreadafilewhichdoesnotexistordoesnothavepermissiontoreadorwhenitattemptstowritetoafilewhichitisnotallowedtowritetoerrorsofthiscategorywilloccurAfilesystemerrorwillalsooccurifanapplicationreadsafilewithanunexpectedformatforinstanceaconfigurationfilethatshouldbeintheINIformatbutisinsteadstructuredasJSON

Third-partyapplicationerrorsTheseerrorsoccurinapplicationswhichinterfacewithotherthird-partyapplicationsorservicesForinstanceifanapplicationpublishestweetsaftermakingcallstoTwittersAPIitsobviousthatTwittersservicesmustbeupandrunninginorderforourapplicationtocompleteitstaskWemustalsoensurethatwesupplythesethird-partyinterfaceswiththeappropriateparametersinourcallsorelsetheywillalsoreturnerrors

HTTPerrorsTheseerrorsvarygreatlyandarebasedonuserrequestsThemostcommonisthe404NotFounderrorwhichariseswhenusersattempttoaccessnon-existentresourcesinyourapplicationAnothercommonHTTPerroristhe401Unauthorizederror(authenticationisrequiredtoaccesstherequestedresource)403Forbiddenerror(usersarealtogetherrefusedaccesstothisresource)and503ServiceUnavailableerrors(indicativeofaninternalprogramerror)

OperatingsystemerrorsThesesortsoferrorsoccurattheoperatingsystemlayerandcanhappenwhenoperatingsystemresourcesareover-allocatedleadingtocrashesandsysteminstabilityAnothercommonoccurrenceatthisleveliswhentheoperatingsystemdiskgetsfilledtocapacitymakingitimpossibletowritetoThisnaturallyproducesinmanyerrorsNetworkerrorsnetworkerrorstypicallycomeintwoflavorsoneiswhenusersissuerequeststotheapplicationandthenetworkdisconnectsthusdisruptingitsprocessingandresponsephaseTheseerrorsdonotcausetheapplicationtocrashbutcanaffectuseraccesstothewebsitetheotheriswhenapplicationsattemptstoreaddatafromdisconnectednetworkscausingreadfailuresJudicioustestingisparticularlyimportantwhenmakingnetworkcallstoavoidsuchproblemswhichcancauseyourapplicationtocrash

ErrorhandlinggoalsBeforeimplementingerrorhandlingwemustbeclearaboutwhatgoalswearetryingtoachieveIngeneralerrorhandlingsystemsshouldaccomplishthefollowing

UsererrornotificationswhensystemorusererrorsoccurcausingcurrentuserrequeststofailtocompleteaffectedusersshouldbenotifiedoftheproblemForexampleforerrorscausebyuserrequestsweshowaunifiederrorpage(404html)Whenasystemerroroccursweuseacustomerrorpagetoprovidefeedbackforusersastowhathappened-forinstancethatthesystemistemporarilyunavailable(errorhtml)Logerrorswhensystemerrorsoccur(ingeneralwhenfunctionsreturnnon-nilerrorvariables)aloggingsystemsuch

Errorsandcrashes

262

astheonedescribedearliershouldbeusedtorecordtheeventintoalogfilefileIfitisafatalerrorthesystemadministratorshouldalsobenotifiedviae-mailIngeneralhowevermost404errorsdonotwarrantthesendingofemailnotificationsrecordingtheeventintoalogforlaterscrutinyisoftenadequateRollbackthecurrentrequestoperationIfauserrequestcausesaservererrorthenweneedtobeabletorollbackthecurrentoperationLetslookatanexampleasystemsavesauser-submittedformtoitsdatabasethensubmitsthisdatatoathird-partyserverHoweverthethird-partyserverdisconnectsandweareunabletoestablishaconnectionwithitwhichresultsinanerrorInthiscasethepreviouslystoredformdatashouldbedeletedfromthedatabase(voidshouldbeinformed)andtheapplicationshouldinformtheuserofthesystemerrorEnsurethattheapplicationcanrecoverfromerrorsweknowthatitsdifficultforanyprogramtoguarantee100uptimesoweneedtomakeprovisionforscenarioswhereourprogramsfailForinstanceifourprogramcrasheswefirstneedtologtheerrornotifytherelevantpartiesinvolvedthenimmediatelygettheprogramupandrunningagainThiswayourapplicationcancontinuetoprovideserviceswhileasystemadministratorinvestigatesandfixesthecauseoftheproblem

HowtohandleerrorsInchapter11weaddressedtheprocessoferrorhandlinganddesignusingsomeexamplesLetsgointotheseexamplesinabitmoredetailandseesomeothererrorhandlingscenarios

Notifytheuseroferrors

Whenanerroroccurswecanpresenttheuseraccessingthepagewithtwokindsoferrorspages404htmlanderrorhtmlHereisanexampleofwhatthesourcecodeofanerrorpagemightlooklike

lthtmllang=engt

ltheadgt

ltmetahttp-equiv=Content-Typecontent=texthtmlcharset=utf-8gt

lttitlegtPageNotFound

lttitlegt

ltmetaname=viewportcontent=width=device-widthinitial-scale=10gt

ltheadgt

ltbodygt

ltdivclass=containergt

ltdivclass=rowgt

ltdivclass=span10gt

ltdivclass=hero-unitgt

lth1gt404lth1gt

ltpgtErrorInfoltpgt

ltdivgt

ltdivgt

lt--span--gt

ltdivgt

ltdivgt

ltbodygt

lthtmlgt

Anotherexample

Errorsandcrashes

263

lthtmllang=engt

ltheadgt

ltmetahttp-equiv=Content-Typecontent=texthtmlcharset=utf-8gt

lttitlegtsystemerrorpage

lttitlegt

ltmetaname=viewportcontent=width=device-widthinitial-scale=10gt

ltheadgt

ltbodygt

ltdivclass=containergt

ltdivclass=rowgt

ltdivclass=span10gt

ltdivclass=hero-unitgt

lth1gtsystemistemporarilyunavailablelth1gt

ltpgtErrorInfoltpgt

ltdivgt

ltdivgt

lt--span--gt

ltdivgt

ltdivgt

ltbodygt

lthtmlgt

404error-handlinglogicintheoccurrenceofasystemerror

func(pMyMux)ServeHTTP(whttpResponseWriterrhttpRequest)

ifrURLPath==

sayhelloName(wr)

return

NotFound404(wr)

return

funcNotFound404(whttpResponseWriterrhttpRequest)

logError(pagenotfound)errorlogging

t_=tParseFiles(tmpl404htmlnil)parsethetemplatefile

ErrorInfo=FilenotfoundGetthecurrentuserinformation

tExecute(wErrorInfo)executethetemplatemergeroperation

funcSystemError(whttpResponseWriterrhttpRequest)

logCritical(SystemError)systemerrortriggeredCriticalthenloggingwillnotonly

sendamessage

t_=tParseFiles(tmplerrorhtmlnil)parsethetemplatefile

ErrorInfo=systemistemporarilyunavailableGetthecurrentuserinformation

tExecute(wErrorInfo)executethetemplatemergeroperation

HowtohandleexceptionsWeknowthatmanyotherlanguageshavetrycatchkeywordsusedtocapturetheunusualcircumstancesbutinfactmanyerrorscanbeexpectedtooccurwithouttheneedforexceptionhandlingandcanbeinsteadtreatedasanerrorsItsforthisreasonthatGofunctionsreturnerrorsbydesignForexampleifafileisnotfoundorifosOpenreturnsanerrorthesefunctionswillnotpanicasanotherexampleifanetworkconnectiongetsdisconnectedduringadatawriteoperationthenetConnfamilyofWritefunctionswillreturnerrorsinsteadofpanickingTheseerrorstatesaretobeexpectedinmostapplicationsandGoparticularlymakesitexplicitwhenoperationsmightfailbyreturningerrorvariablesLookingattheexampleabovewecanclearlyseetheerrorsthatcanbeexpectedtooccur

Errorsandcrashes

264

TherearehowevercaseswherepanicshouldbeusedForinstanceinoperationswherefailureisalmostimpossibleorincertainsituationswherethereisnowaytoreturnanerrorandtheoperationcannotcontinuepanicshouldbeusedTakeforexampleaprogramthattriestoobtainthevalueofanarrayatx[j]buttheindexjisoutofboundsThispartofthecodewillcausetheprogramtopanicaswillothercriticalunexpectederrorsofthisnatureBydefaultpanickingwillkillofftheoffendingprocess(goroutine)allowingthecodewhichdispatchedthegoroutineanopportunitytorecoverfromtheerrorThiswaythefunctioninwhichtheerroroccurredaswellasallsubsequentcodeafteritwillnotcontinuetoexecuteGospanicwasdeliberatelydesignedwiththisbehaviorinmindwhichisdifferentthantypicalerrorhandlingpanicisreallyjustexceptionhandlingIntheexamplebelowweexpectthatUser[UID]willreturnausernamefromtheUserarraybuttheUIDthatweuseisoutofboundsandthrowsanexceptionIfwedonothavearecoverymechanismtodealwiththisimmediatelytheprocesswillbekilledandthepanicwillpropagateupthestackuntilourprogramfinallycrashesInorderforourapplicationtoberobustandresilienttothesekindsofruntimeerrorsweneedtoimplementrecoverymechanismsincertainplaces

funcGetUser(uidint)(usernamestring)

deferfunc()

ifx=recover()x=nil

username=

()

username=User[uid]

return

TheabovedescribesthedifferencesbetweenerrorsandexceptionsSowhenitcomesdowntodevelopingourGoapplicationswhendoweuseoneortheotherTherulesaresimpleifyoudefineafunctionthatyouanticipatemightfailthenreturnanerrorvariableWhencallinganotherpackagesfunctionifitisimplementedwellthereshouldbenoneedtoworrythatitwillpanicunlessatrueexceptionhasoccurred(whetherrecoverylogichasbeenimplementedornot)PanicandrecovershouldonlybeusedinternallyinsidepackagestodealwithspecialcaseswherethestateoftheprogramcannotbeguaranteedorwhenaprogrammerserrorhasoccurredExternallyfacingAPIsshouldexplicitlyreturnerrorvalues

SummaryThisissectionsummarizeshowwebapplicationsshouldhandlevariouserrorssuchasnetworkdatabaseandoperatingsystemerrorsamongothersWeveoutlineseveraltechniquestoeffectivelydealwithruntimeerrorssuchasdisplayinguser-friendlyerrornotificationsrollingbackactionsloggingandalertingsystemadministratorsFinallyweexplainedhowtocorrectlyhandleerrorsandexceptionsTheconceptofanerrorisoftenconfusedwiththatofanexceptionhoweverinGothereisacleardistinctionbetweenthetwoForthisreasonwevediscussedtheprinciplesofprocessingbotherrorsandexceptionsinwebapplications

LinksDirectoryPrevioussectionLogsNextsectionDeployment

Errorsandcrashes

265

123DeploymentWhenourwebapplicationisfinallyproductionreadywhatarethestepsnecessarytogetitdeployedInGoanexecutablefileencapsulatingourapplicationiscreatedafterwecompileourprogramsProgramswritteninCcanrunperfectlyasbackgrounddaemonprocesseshoweverGodoesnotyethavenativesupportfordaemonsThegoodnewsisthatwecanusethirdpartytoolstohelpusmanagethedeploymentofourGoapplicationsexamplesofwhichareSupervisordupstartanddaemontoolsamongothersThissectionwillintroduceyoutosomebasicsoftheSupervisordprocesscontrolsystem

DaemonsCurrentlyGoprogramscannotberunasdaemonprocesses(foradditionalinformationseetheopenissueongithubhere)ItsdifficulttoforkexistingthreadsinGobecausethereisnowayofensuringaconsistentstateinallthreadsthathavebeenused

Wecanhoweverseemanyattemptsatimplementingdaemonsonlinesuchasinthetwofollowingways

MarGooneimplementationoftheconceptofusingCommandtodeployapplicationsIfyoureallywanttodaemonizeyourapplicationsitisrecommendedtousecodesimilartothefollowing

d=flagBool(dfalseWhetherornottolaunchinthebackground(likea

daemon))

ifd

cmd=execCommand(osArgs[0]

-close-fds

-addraddr

-callcall

)

serrerr=cmdStderrPipe()

iferr=nil

logFatalln(err)

err=cmdStart()

iferr=nil

logFatalln(err)

serr=ioutilReadAll(serr)

s=bytesTrimSpace(s)

ifbytesHasPrefix(s[]byte(addr))

fmtPrintln(string(s))

cmdProcessRelease()

else

logPrintf(unexpectedresponsefromMarGo`s`error`v`nserr)

cmdProcessKill()

Anothersolutionistousesyscallbutthissolutionisnotperfect

Deployment

266

packagemain

import(

log

os

syscall

)

funcdaemon(nochdirnocloseint)int

varretret2uintptr

varerruintptr

darwin=syscallOS==darwin

alreadyadaemon

ifsyscallGetppid()==1

return0

forkofftheparentprocess

retret2err=syscallRawSyscall(syscallSYS_FORK000)

iferr=0

return-1

failure

ifret2lt0

osExit(-1)

handleexceptionfordarwin

ifdarwinampampret2==1

ret=0

ifwegotagoodPIDthenwecallexittheparentprocess

ifretgt0

osExit(0)

Changethefilemodemask

_=syscallUmask(0)

createanewSIDforthechildprocess

s_rets_errno=syscallSetsid()

ifs_errno=0

logPrintf(ErrorsyscallSetsiderrnods_errno)

ifs_retlt0

return-1

ifnochdir==0

osChdir()

ifnoclose==0

fe=osOpenFile(devnullosO_RDWR0)

ife==nil

fd=fFd()

syscallDup2(fdosStdinFd())

syscallDup2(fdosStdoutFd())

syscallDup2(fdosStderrFd())

return0

Deployment

267

WhilethetwosolutionsaboveimplementdaemonizationinGoIstillcannotrecommendthatyouuseeithermethodssincethereisnoofficialsupportfordaemonsinGoNotwithstandingthisfactthefirstoptionisthemorefeasibleoneandiscurrentlybeingusedbysomewell-knownopensourceprojectslikeskynetforimplementingdaemons

SupervisordAbovewevelookedattwoschemesthatarecommonlyusedtoimplementdaemonsinGohoweverbothmethodslackofficialsupportSoitsrecommendedthatyouuseathird-partytooltomanageapplicationdeploymentHerewetakealookattheSupervisordprojectimplementedinPythonwhichprovidesextensivetoolsforprocessmanagementSupervisordwillhelpyoutodaemonizeyourGoapplicationsalsoallowingyoutodothingslikestartshutdownandrestartyourapplicationswithsomesimplecommandsamongmanyotheractionsInadditionSupervisordmanagedprocessescanautomaticallyrestartprocesseswhichhavecrashedensuringthatprogramscanrecoverfromanyinterruptions

AsanasideIrecentlyfellintoacommonpitfallwhiletryingtodeployanapplicationusingSupervisordAllapplicationsdeployedusingSupervisordarebornoutoftheSupervisordparentprocessWhenyouchangeanoperatingsystemfiledescriptordontforgettocompletelyrestartSupervisord-simplyrestartingtheapplicationitismanagingwillnotsufficeWhenIfirstdeployedanapplicationwithSupervisordImodifiedthedefaultfiledescriptorfieldchangingthedefaultnumberfrom1024to100000andthenrestartingmyapplicationInrealitySupervisordcontinuedusingonly1024filedescriptorstomanageallofmyapplicationsprocessesUpondeployingmyapplicationtheloggerbeganreportingalackoffiledescriptorsItwasalongprocessfindingandfixingthismistakesobeware

InstallingSupervisord

Supervisordcaneasilybeinstalledusingsudoeasy_installsupervisorOfcoursethereisalsotheoptionofdirectlydownloadingitfromitsofficialwebsiteuncompressingitgoingintothefolderthenrunningsetuppyinstalltoinstallitmanually

Ifyouregoingtheeasy_installroutethenyouneedtofirstinstallsetuptools

GotohttppypipythonorgpypisetuptoolsfilesanddownloadtheappropriatefiledependingonyoursystemspythonversionEnterthedirectoryandexecuteshsetuptoolsxxxxeggWhenthenscriptisdoneyoullbeabletousetheeasy_installcommandtoinstallSupervisord

ConfiguringSupervisord

SupervisordsdefaultconfigurationfilepathisetcsupervisordconfandcanbemodifiedusingatexteditorThefollowingiswhatatypicalconfigurationfilemaylooklike

Deployment

268

etcsupervisordconf

[unix_http_server]

file=varrunsupervisordsock

chmod=0777

chown=rootroot

[inet_http_server]

Webmanagementinterfacesettings

port=9001

username=admin

password=yourpassword

[supervisorctl]

Mustunix_http_servermatchthesettingsinside

serverurl=unixvarrunsupervisordsock

[supervisord]

logfile=varlogsupervisordsupervisordlog(mainlogfiledefault$CWDsupervisordlog)

logfile_maxbytes=50MB(maxmainlogfilebytesb4rotationdefault50MB)

logfile_backups=10(numofmainlogfilerotationbackupsdefault10)

loglevel=info(logleveldefaultinfoothersdebugwarntrace)

pidfile=varrunsupervisordpid(supervisordpidfiledefaultsupervisordpid)

nodaemon=true(startinforegroundiftruedefaultfalse)

minfds=1024(minavailstartupfiledescriptorsdefault1024)

minprocs=200(minavailprocessdescriptorsdefault200)

user=root(defaultiscurrentuserrequiredifroot)

childlogdir=varlogsupervisord(AUTOchildlogdirdefault$TEMP)

[rpcinterfacesupervisor]

supervisorrpcinterface_factory=supervisorrpcinterfacemake_main_rpcinterface

Managetheconfigurationofasingleprocessyoucanaddmultipleprogram

[programblogdemon]

command=datablogblogdemon

autostart=true

startsecs=5

user=root

redirect_stderr=true

stdout_logfile=varlogsupervisordblogdemonlog

SupervisordmanagementAfterinstallationiscompletetwoSupervisordcommandsbecomeavailabletoyouonthecommandlinesupervisorandsupervisorctlThecommandsareasfollows

supervisordinitialstartuplaunchandprocessconfigurationmanagementsupervisorctlstopprogramxxxstoptheprogramxxxprocesswhereprogramxxxisavalueconfiguredinyoursupervisordconffileForinstanceifyouhavesomethinglike[programblogdemon]configuredyouwouldusethesupervisorctlstopblogdemoncommandtokilltheprocesssupervisorctlstartprogramxxxstarttheprogramxxxprocesssupervisorctlrestartprogramxxxrestarttheprogramxxxprocesssupervisorctlstopallstopallprocessesnotestartrestartstopwillnotloadthelatestconfigurationfilessupervisorctlreloadloadthelatestconfigurationfilelaunchthemandmanageallprocesseswiththenewconfiguration

SummaryInthissectionwedescribedhowtoimplementdaemonsinGoWelearnedthatGodoesnotnativelysupportdaemonsandthatweneedtousethird-partytoolstohelpusmanagethemOnesuchtoolistheSupervisordprocesscontrolsystemwhichwecanusetoeasilydeployandmanageourGoprograms

Links

Deployment

269

DirectoryPrevioussectionErrorsandcrashesNextsectionBackupandrecovery

Deployment

270

124BackupandrecoveryInthissectionwelldiscussanotheraspectofapplicationmanagementdatabackupandrecoveryonproductionserversWeoftenencountersituationswhereproductionserversdontbehaveasweexpectthemtoServernetworkoutagesharddrivemalfunctionsoperatingsystemcrashesandothersimilareventscancausedatabasestobecomeunavailableTheneedtorecoverfromthesetypesofeventshasledtotheemergenceofmanycoldstandbyhotstandbytoolsthatcanhelptofacilitatedisasterrecoveryremotelyInthissectionwellexplainhowtobackupdeployedapplicationsinadditiontobackingupandrestoringanyMySQLandRedisdatabasesyoumightbeusing

ApplicationBackupInmostclusterenvironmentswebapplicationsdonotneedtobebackedupsincetheyareactuallycopiesofcodefromourlocaldevelopmentenvironmentorfromaversioncontrolsystemInmanycaseshoweverweneedtobackupdatawhichhasbeensuppliedbytheusersofoursiteForinstancewhensitesrequireuserstouploadfilesweneedtobeabletobackupanyfilesthathavebeenuploadedbyuserstoourwebsiteThecurrentapproachforprovidingthiskindofredundancyistoutilizeso-calledcloudstoragewhereuserfilesandotherrelatedresourcesarepersistedintoahighlyavailablenetworkofserversIfoursystemcrashesaslongasuserdatahasbeenpersistedontothecloudwecanatleastbesurethatnodatawillbelost

ButwhataboutthecaseswherewedidnotbackupourdatatoacloudserviceorwherecloudstoragewasnotanoptionHowdowebackupdatafromourwebapplicationsthenHerewedescribeatoolcalledrsyncwhichcanbecommonlyfoundonunix-likesystemsRsyncisatoolwhichcanbeusedtosynchronizefilesresidingondifferentsystemsandaperfectuse-caseforthisfunctionalityistokeepourwebsitebackedup

NoteCwrsyncisanimplementationofrsyncfortheWindowsenvironment

RsyncinstallationYoucanfindthelatestversionofrsyncfromitsofficialwebsiteOfcoursebecausersyncisveryusefulsoftwaremanyLinuxdistributionswillalreadyhaveitinstalledbydefault

PackageInstallation

sudoapt-getinstallrsyncNotedebianubuntuandotheronlineinstallationmethods

yuminstallrsyncNoteFedoraRedhatCentOSandotheronlineinstallationmethods

rpm-ivhrsyncNoteFedoraRedhatCentOSandotherrpmpackageinstallationmethods

FortheotherLinuxdistributionspleaseusetheappropriatepackagemanagementmethodstoinstallitAlternativelyyoucanbuildityourselffromthesource

tarxvfrsync-xxxtargz

cdrsync-xxx

configure-prefix=usrmakemakeinstall

NoteIfwanttocompileandinstallthersyncfromitssourceyouhavetoinstallgcccompilertoolssuchasjob

NoteBeforeusingsourcepackagescompiledandinstalledyouhavetoinstallgcccompilertoolssuchasjob

RsyncConfiguration

Rsynccanbeconfiguredfromthreemainconfigurationfilesrsyncdconfwhichisthemainconfigurationfilersyncdsecretswhichholdspasswordsandrsyncdmotdwhichcontainsserverinformation

Backupandrecovery

271

Youcanrefertotheofficialdocumentationonrsyncswebsiteformoredetailedexplanationsbutherewewillsimplyintroducethebasicsofsettinguprsync

Startinganrsyncdaemonserver-side

usrbinrsync--daemon--config=etcrsyncdconf

the--daemonparameterisforrunningrsyncinservermodeMakethisthedefaultboot-timesettingbyjoiningittotherclocalfile

echorsync--daemongtgtetcrcdrclocal

SetupanrsyncusernameandpasswordmakingsurethatitsownedonlybyrootsothatlocalunauthorizedusersorexploitsdonothaveaccesstoitIfthesepermissionsarenotsetcorrectlyrsyncmaynotboot

echoYourUsernameYourPasswordgtetcrsyncdsecrets

chmod600etcrsyncdsecrets

Clientsynchronization

Clientscansynchronizeserverfileswiththefollowingcommand

rsync-avzP--delete--password-file=rsyncdsecretsusername1921681455wwwvarrsyncbackup

Letsbreakthisdownintoafewkeypoints

1 -avzParesomecommonoptionsUsersync--helptoreviewwhatthesedo2 --deletedeletesextraneousfilesonthereceivingsideForexampleiffilesaredeletedonthesendingsidethenext

timethetwomachinesaresynchronizedthereceivingsideswillautomaticallydeletethecorrespondingfiles3 --password-filespecifiesapasswordfileforaccessinganrsyncdaemonOntheclientsidethisistypicallythe

clientetcrsyncdsecretsfileandontheserversideitsetcrsyncdsecretsWhenusingsomethinglikeCrontoautomatersyncyouwontneedtomanuallyenterapassword

4 usernamespecifiestheusernametobeusedinconjunctionwiththeserver-sideetcrsyncdsecretspassword5 1921681455istheIPaddressoftheserver6 www(notethedoublecolons)specifiescontactinganrsyncdaemondirectlyviaTCPforsynchronizingthewww

moduleaccordingtotheserver-sideconfigurationslocatedinetcrsyncdconfWhenonlyasinglecolonisusedthersyncdaemonisnotcontacteddirectlyinsteadaremote-shellprogramsuchassshisusedasthetransport

InordertoperiodicallysynchronizefilesyoucansetupacrontabfilethatwillrunrsynccommandsasoftenasneededOfcourseuserscanvarythefrequencyofsynchronizationaccordingtohowcriticalitistokeepcertaindirectoriesorfilesuptodate

MySQLbackupMySQLdatabasesarestillthemainstreamgo-tosolutionformostwebapplicationsThetwomostcommonmethodsofbackingupMySQLdatabasesarehotbackupsandcoldbackupsHotbackupsareusuallyusedwithsystemssetupinamasterslaveconfigurationtobackuplivedata(themasterslavesynchronizationmodeistypicallyusedforseparatingdatabasereadwriteoperationsbutcanalsobeusedforbackinguplivedata)ThereisalotofinformationavailableonlinedetailingthevariouswaysonecanimplementthistypeofschemeForcoldbackupsincomingdataisnotbackedupinreal-timeasisthecasewithhotbackupsInsteaddatabackupsareperformedperiodicallyThiswayifthesystemfailstheintegrityofdatabeforeacertainperiodoftimecanstillbeguaranteedForinstanceincaseswhereasystemmalfunctioncausesdatatobelostandthemasterslavemodelisunabletoretrieveitcoldbackupscanbeusedforapartialrestoration

Ashellscriptisgenerallyusedtoimplementregularcoldbackupsofdatabasesexecutingsynchronizationtasksusingrsyncinanon-localmode

Backupandrecovery

272

ThefollowingisanexampleofabackupscriptthatperformsscheduledbackupsforaMySQLdatabaseWeusethemysqldumpprogramwhichallowsustoexportthedatabasetoafile

binbash

Configurationinformationmodifyitasneeded

mysql_user=USERMySQLbackupuser

mysql_password=PASSWORDMySQLbackupuserspassword

mysql_host=localhost

mysql_port=3306

mysql_charset=utf8MySQLencoding

backup_db_arr=(db1db2)Nameofthedatabasetobebackedupseparatingmultipledatabaseswihspaces(DB1

DB2db3)

backup_location=varwwwmysqlBackupdatastoragelocationpleasedonotendwithaandleaveitatitsdefau

ltfortheprogramtoautomaticallycreateafolder

expire_backup_delete=ONWhethertodeleteoutdatedbackupsornot

expire_days=3Settheexpirationtimeofbackupsindays(defaultstothreedays)thisisonlyvalidwhenthe`ex

pire_backup_delete`optionisON

Wedonotneedtomodifythefollowinginitialsettingsbelow

backup_time=`date+YmdHM`Definethebackuptimeformat

backup_Ymd=`date+Y-m-d`Definethebackupdirectorydatetime

backup_3ago=`date-d3daysago+Y-m-d`3daysbeforethedate

backup_dir=$backup_location$backup_YmdFullpathtothebackupfolder

welcome_msg=WelcometouseMySQLbackuptoolsGreeting

DeterminewhethertoMySQLisrunningifnotthenabortthebackup

mysql_ps=`ps-ef|grepmysql|wc-l`

mysql_listen=`netstat-an|grepLISTEN|grep$mysql_port|wc-l`

if[[$mysql_ps==0]-o[$mysql_listen==0]]then

echoERRORMySQLisnotrunningbackupaborted

exit

else

echo$welcome_msg

fi

Connecttothemysqldatabaseifaconnectioncannotbemadeabortthebackup

mysql-h$mysql_host-P$mysql_port-u$mysql_user-p$mysql_passwordltltend

usemysql

selecthostuserfromuserwhereuser=rootandhost=localhost

exit

end

flag=`echo$`

if[$flag=0]then

echoERRORCantconnectmysqlserverbackupaborted

exit

else

echoMySQLconnectokPleasewait

DeterminewhetherabackupdatabaseisdefinedornotIfsobeginthebackupifnotthenabort

if[$backup_db_arr=]then

dbnames=$(cut-d-f1-5$backup_database)

echoarris($backup_db_arr[])

fordbnamein$backup_db_arr[]

do

echodatabase$dbnamebackupstart

`mkdir-p$backup_dir`

`mysqldump-h$mysql_host-P$mysql_port-u$mysql_user-p$mysql_password$dbname-default-character-set=

$mysql_charset|gzipgt$backup_dir$dbname-$backup_timesqlgz`

flag=`echo$`

if[$flag==0]then

echodatabase$dbnamesuccessfullybackedupto$backup_dir$dbname-$backup_timesqlgz

else

echodatabase$dbnamebackuphasfailed

fi

done

else

echoERRORNodatabasetobackupbackupaborted

exit

fi

Ifdeletingexpiredbackupsisenableddeleteallexpiredbackups

Backupandrecovery

273

if[$expire_backup_delete==ON-a$backup_location=]then

`find$backup_location-typed-o-typef-ctime+$expire_days-execrm-rf`

`find$backup_location-typed-mtime+$expire_days|xargsrm-rf`

echoExpiredbackupdatadeletecomplete

fi

echoAlldatabaseshavebeensuccessfullybackedupThankyou

exit

fi

Modifythepropertiesoftheshellscriptlikeso

chmod600rootmysql_backupsh

chmod+xrootmysql_backupsh

Thenaddthecrontabcommand

0000rootmysql_backupsh

Thissetsupregularbackupsofyourdatabasestothevarwwwmysqldirectoryeverydayat0000whichcanthenbesynchronizedusingrsync

MySQLRecoveryWevejustdescribedsomecommonlyusedbackuptechniquesforMySQLnamelyhotbackupsandcoldbackupsTorecapthemaingoalofahotbackupistobeabletorecoverdatainreal-timeafteranapplicationhasfailedinsomewaysuchasinthecaseofaserverhard-diskmalfunctionWelearnedthatthistypeofschemecanbeimplementedbymodifyingdatabaseconfigurationfilessothatdatabasesarereplicatedontoaslaveminimizinginterruptiontoservices

ButsometimesweneedtoperformacoldbackupoftheSQLdatarecoveryaswithdatabasebackupyoucanimportthroughthecommandHotbackupsarehoweversometimesinadequateTherearecertainsituationswherecoldbackupsarerequiredtoperformdatarecoveryevenifitsonlyapartialoneWhenyouhaveacoldbackupofyourdatabaseyoucanusethefollowingMySQLcommandtoimportit

mysql-uusername-pdatabseltbackupsql

AsyoucanseeimportingandexportingdatabaseisafairlysimplematterIfyouneedtomanageadministrativeprivilegesordealwithdifferentcharactersetsthisprocessmaybecomealittlemorecomplicatedthoughthereareanumberofcommandswhichwillhelpyoutodothis

RedisbackupRedisisoneofthemostpopularNoSQLdatabasesandbothhotandcoldbackuptechniquescanalsobeusedinsystemswhichuseitLikeMySQLRedisalsosupportsmasterslavemodewhichisidealforimplementinghotbackups(refertoRedisofficialdocumentationtolearnhowtoconfigurethistheprocessisverystraightforward)AsforcoldbackupsRedisroutinelysavescacheddatainmemorytothedatabasefileon-diskWecansimplyusethersyncbackupmethoddescribedabovetosynchronizeitwithanon-localmachine

RedisrecoverySimilarlyRedisrecoverycanbedividedintohotandcoldbackuprecoveryThemethodsandobjectivesofrecoveringdatafromahotbackupofaRedisdatabasearethesameasthosementionedaboveforMySQLaslongastheRedisapplicationisusingtheappropriatedatabaseconnection

Backupandrecovery

274

ARediscoldbackuprecoverysimplyinvolvescopyingbacked-updatabasefilesintotheworkingdirectorythenstartingRedisonitThedatabasefilesareautomaticallyloadedintomemoryatboottimethespeedwithwhichRedisbootswilldependonthesizeofthedatabasefiles

SummaryInthissectionwelookedatsometechniquesforbackingupdataaswellasrecoveringfromdisasterswhichmayoccurafterdeployingourapplicationsWealsointroducedrsyncatoolwhichcanbeusedtosynchronizefilesondifferentsystemsUsingrsyncwecaneasilyperformbackupandrestorationproceduresforbothMySQLandRedisdatabasesamongothersWehopethatbybeingintroducedtosomeoftheseconceptsyouwillbeabletodevelopdisasterrecoveryprocedurestobetterprotectthedatainyourwebapplications

LinksDirectoryPrevioussectionDeploymentNextsectionSummary

Backupandrecovery

275

125SummaryInthischapterwediscussedhowtodeployandmaintainourGowebapplicationsWealsolookedatsomecloselyrelatedtopicswhichcanhelpustokeepthemrunningsmoothlywithminimalmaintenance

Specificallywelookedat

CreatingarobustloggingsystemcapableofrecordingerrorsandnotifyingsystemadministratorsHandlingruntimeerrorsthatmayoccurincludingloggingthemandhowtorelaythisinformationinauser-friendlymannerthatthereisaproblemHandling404errorsandnotifyingusersthattherequestedpagecannotbefoundDeployingapplicationstoaproductionenvironment(includinghowtodeployupdates)HowtodeployhighlyavailableapplicationsBackingupandrestoringfilesanddatabases

Afterreadingthecontentsofthischapterthosethinkingaboutdevelopingawebapplicationfromscratchshouldalreadyhavethefullpictureonhowtodosothischapterprovidedanintroductiononhowtomanagedeploymentenvironmentswhilepreviouschaptershavefocusedonthedevelopmentofcode

LinksDirectoryPrevioussectionBackupandrecoveryNextchapterBuildingawebframework

Summary

276

13BuildingawebframeworkThePrecedingtwelvechaptersdescribehowtodevelopwebapplicationsinGointroducingalotofbasicknowledgedevelopmenttoolsandtechniquesInthischapterwewillbeusingthisknowledgetoimplementasimplewebframeworkThefirstsectionofthischapterwilltakeyouthroughtheplanninganddesignstageofbuildingawebframeworkWelllookatleveragingtheMVCpatternaswellasdesigningprogramexecutionflowamongotherthingsThesecondsectionwilldescribethefirstfeatureofourframeworkRoutingnamelyhowtomapURLstoprocessinglogicTheninthethirdsectionwedescribetheprocessinglogicitselfwhichinvolvesdesigninggenericcontrollersandhowtohandlerequestsandreturnresponsesafterinheritingfromanobjecthandlerNextwedescribesomeoftheauxiliaryfunctionalitycommontomostwebframeworkssuchaslogprocessinginformationconfigurationetcFinallywellimplementasimplebloggingsystemontopofourframeworkwhichwilldemonstratetheapplicationlogicnecessaryforpublishingmodifyingdeletinganddisplayinglistsofblogposts

Byseeingfirst-handhowtoimplementsuchacompleteprojectfromscratchyouwillhopefullyhaveabetterunderstandingoftheinnerworkingsofGowebapplicationsYoullbecomfortablebuildingyourownprojectdirectorystructuresimplementingURLroutersandutilizingMVCamongotheraspectsofwebdevelopmentAmongtheframeworksprevalenttodayMVCisnolongeramythItsnotuncommontohearprogrammersarguingaboutwhichframeworksaregoodandwhicharebadwhichisoftentooshallowofanapproachFrameworksareonlytoolsandsometoolsaremoresuitableforcertainapplicationsthanothersTherearenouniversallygoodorbadtoolsThusbyteachingyourselfhowtowriteaframeworkfromscratchyouwillbeabletotailor-maketheperfecttooltobestrealizeyourideas

LinksDirectoryPreviouschapterChapter12summaryNextsectionProjectprogram

Buildawebframework

277

131ProjectplanningAnythingyouintendtodowellmustfirstbeplannedwellInourcaseourintentionistodevelopabloggingsystemsothefirststepweshouldtakeistodesigntheflowoftheapplicationinitsentiretyWhenwehaveaclearunderstandingoftheourapplicationsprocessofexecutionthesubsequentdesignandcodingstepsbecomemucheasier

GOPATHandprojectsettingsLetsproceedbyassumingthatourGOPATHpointstoafolderwithanordinarydirectoryname(ifnotwecaneasilysetupasuitabledirectoryandsetitspathastheGOPATH)AswevedescribeearlieraGOPATHcancontainmorethanonedirectoryinWindowswecansetthisasanenvironmentvariableinlinuxOSXsystemsGOPATHcanbesetusingexportieexportgopath=pathtoyourdirectoryaslongasthedirectorywhichGOPATHpointstocontainsthethreesub-directoriespkgbinandsrcBelowweveplacedthesourcecodeofournewprojectinthesrcdirectorywiththetentativenamebeelogHerearesomescreenshotsoftheWindowsenvironmentvariablesaswellasofthedirectorystructure

Figure131SettingtheGOPATHenvironmentvariable

Figure132Theworkingdirectoryunder$gopathsrc

ApplicationflowchartOurbloggingsystemwillbebasedonthemodel-view-controllerdesignpatternMVCistheseparationoftheapplicationlogicfromthepresentationlayerInpracticewhenwekeepthepresentationlayerseparatedwecandrasticallyreducetheamountofcodeneededonourwebpages

ModelsrepresentdataaswellastherulesandlogicgoverningitInGeneralamodelclasswillcontainfunctionsforremovinginsertingandupdatingdatabaseinformationViewsarearepresentationofthestateofamodelAviewisusuallyapagebutinGoaviewcanalsobeafragmentofapagesuchasaheaderorfooterItcanalsobeanRSSfeedoranyothertypeofpageGostemplatepackageprovidesverygoodsupportforviewlayerfunctionalityControllersarethegluelogicbetweenthemodelandviewlayersandencompassesalltheintermediarylogicnecessaryforhandlingHTTPrequestsandgeneratingWebpages

Thefollowingfigureisanoverviewoftheprojectframeworkanddemonstrateshowdatawillflowthroughthesystem

Figure133frameworkdataflow

1 Maingoistheapplicationsentrypointandinitializessomebasicresourcesrequiredtoruntheblogsuchasconfigurationinformationlisteningportsetc

2 RoutingchecksallincomingHTTPrequestsandaccordingtothemethodURLandparametersmatchesitwiththecorrespondingcontrolleraction

3 Iftherequestedresourcehasalreadybeencachedtheapplicationwillbypasstheusualexecutionprocessandreturnaresponsedirectlytotheusersbrowser

4 SecuritydetectionTheapplicationwillfilterincomingHTTPrequestsandanyotherusersubmitteddatabeforehandingitofftothecontroller

5 ControllerloadsmodelscorelibrariesandanyotherresourcesrequiredtoprocessspecificrequestsThecontrollerisprimarilyresponsibleforhandlingbusinesslogic

Projectprogram

278

6 OutputtherenderedviewtobesenttotheclientswebbrowserIfcachinghasbeenenabledthefirstviewiscachedforfuturerequeststothesameresource

DirectorystructureAccordingtotheframeworkflowwevedesignedaboveourblogprojectsdirectorystructureshouldlooksomethinglikethefollowing

|mdashmdashmaingoimportdocuments

|mdashmdashconfconfigurationfilesandprocessingmodule

|mdashmdashcontrollerscontrollerentry

|mdashmdashmodelsdatabaseprocessingmodule

|mdashmdashutilsusefulfunctionlibrary

|mdashmdashstaticstaticfiledirectory

|mdashmdashviewsviewgallery

FrameworkdesignInordertoquicklybuildourblogweneedtodevelopaminimalframeworkbasedontheapplicationwevedesignedaboveTheframeworkshouldincluderoutingcapabilitiessupportforRESTfulcontrollersautomatedtemplaterenderingaloggingsystemconfigurationmanagementandmore

SummaryThissectiondescribestheinitialdesignofourbloggingsystemfromsettingupourGOPATHtobrieflyintroducingtheMVCpatternWealsolookedattheflowofdataandtheexecutionsequenceofourbloggingsystemFinallywedesignedthestructureofourprojectdirectoryAtthispointwevebasicallycompletedthegroundworkrequiredforassemblingourframeworkInthenextfewsectionswewillimplementeachofthecomponentswevediscussedonebyone

LinksDirectoryPrevioussectionBuildingawebframeworkNextsectionCustomizingrouters

Projectprogram

279

132Customizingrouters

HTTProutingTheHTTProutingcomponentisresponsibleformappingHTTPrequeststoacorrespondingfunctionorstructmethodTheroutertakestwokeypiecesofinformationfromincomingrequests

-Theuserrequestedpath(forexampleuser123article123)andanyquerystringsorparametersthatcomewithit(forexampleid=11)-TheHTTPrequestmethod(GETPOSTPUTandDELETEPATCHetc)

Therouterthenforwardstherequesttothehandlerfunction(controllerlayer)thathasbeenregisteredwiththatparticularHTTPmethodandpath

DefaultroutingimplementationInsection34weintroducedGoshttppackageindetailwhichincludedhowtodesignandimplementroutingHerewetakeanotherlookatanexamplethatillustratestheroutingprocess

funcfooHandler(whttpResponseWriterrhttpRequest)

fmtFprintf(wHelloqhtmlEscapeString(rURLPath))

httpHandle(foofooHandler)

httpHandleFunc(barfunc(whttpResponseWriterrhttpRequest)

fmtFprintf(wHelloqhtmlEscapeString(rURLPath))

)

logFatal(httpListenAndServe(8080nil))

TheexampleabovecallshttpsdefaultmuxcalledDefaultServeMuximplicitlyspecifiedbythenilparameterinthecalltohttpListenAndServeThehttpHandlefunctiontakestwoparametersthefirstparameteristheresourceyouwantuserstoaccessspecifiedbyitsURLpath(whichisstoredinrURLPath)andthesecondargumentbindsahandlerfunctionwiththispathTheRouterhastwomainjobs

ToaddandstoreroutinginformationToforwardrequeststoahandlerfunctionforprocessing

BydefaultGoroutesarehandledwithhttpHandleandhttpHandleFunctypesregisteredbydefaultthroughtheunderlyingDefaultServeMuxHandle(patternstringhandlerHandler)functionThisfunctionmapsresourcepathstohandlersandstorestheminamap[string]muxEntrymapThisisthefirstjobthatwementionedabove

WhentheapplicationisrunningtheGoserverlistenstoaportWhenitreceivesatcpconnectionitusesaHandlertoprocessitAsaforementionedsincetheHandlerintheexampleaboveisnilthedefaultrouterhttpDefaultServeMuxisusedUsingthemapofpreviouslystoredroutesDefaultServeMuxServeHTTPwilldispatchtherequesttothefirsthandlerwithamatchingpathThisistherouterssecondjob

forkv=rangemuxm

ifpathMatch(kpath)

continue

ifh==nil||len(k)gtn

n=len(k)

h=vh

Customizedrouters

280

RoutingwithBeegoAtpresentmostGowebapplicationsbasetheirroutingonhttpsdefaultrouterhoweverthishasseverallimitations

DoesnotsupportdynamicrouteswithparameterssuchastheuserUIDDoesnothavegoodsupportforRESTTheaccessmethodscannotberestrictedforinstanceintheaboveexamplewhenusersaccessfootheycanusetheGETPOSTDELETEandHEADHTTPmethodsamongothersInlargeappsroutingrulescanbecomerepetitiveandcumbersomePersonallyIvedevelopedsimplewebAPIscomposedofnearlythirtyroutingruleswheninfacttheserulescouldhavebeenfurthersimplifiedusingmethodstructs

TheBeegoframeworksrouterisdesignedtoovercometheselimitationstakingtheRESTparadigmintoconsiderationandsimplifyingthestoringandforwardingofroutesandrequests

Storingroutes

ToaddressthefirstlimitationofthedefaultrouterweneedtobeabletosupportdynamicURLparametersForthesecondandthirdpointsweadoptanalternativeapproachmappingRESTmethodstostructmethodsandroutingrequeststothisstructinsteadoftohandlerfunctionsThiswayaforwardedrequestcanbehandledaccordingtoitsHTTPmethod

BasedontheaboveideaswevedesignedtwodatatypescontrollerInfowhichsavesthepathandthecorrespondingcontrollerTypestructasareflectTypetypeandControllerRegistorwhichsavesroutinginformationforthespecifiedBeegoapplication

typecontrollerInfostruct

regexregexpRegexp

paramsmap[int]string

controllerTypereflectType

typeControllerRegistorstruct

routers[]controllerInfo

ApplicationApp

ControllerRegistorsexternalinterfacecontainsthefollowingmethod

func(pControllerRegistor)Add(patternstringcControllerInterface)

Itsdetailedimplementationisasfollows

Customizedrouters

281

func(pControllerRegistor)Add(patternstringcControllerInterface)

parts=stringsSplit(pattern)

j=0

params=make(map[int]string)

foripart=rangeparts

ifstringsHasPrefix(part)

expr=([^]+)

ausermaychoosetooverridethedefaultexpression

similartoexpressjslsquouserid([0-9]+)rsquo

ifindex=stringsIndex(part()index=-1

expr=part[index]

part=part[index]

params[j]=part

parts[i]=expr

j++

recreatetheurlpatternwithparametersreplaced

byregularexpressionsThencompiletheregex

pattern=stringsJoin(parts)

regexregexErr=regexpCompile(pattern)

ifregexErr=nil

TODOadderrorhandlingheretoavoidpanic

panic(regexErr)

return

nowcreatetheRoute

t=reflectIndirect(reflectValueOf(c))Type()

route=ampcontrollerInfo

routeregex=regex

routeparams=params

routecontrollerType=t

prouters=append(proutersroute)

StaticroutingWeveimplementeddynamicroutinginourexampleaboveBydefaultGoshttppackagesupportsservingstaticfileswithhttpFileServerwhichreturnsaHandlerSincewehaveimplementedacustomrouterwewillalsoneedawayofhandlingstaticfilesBeegosstaticfolderpathissavedinaglobalvariablecalledStaticDirwhichmapstheURLtocorrespondingpathsTheSetStaticPathsimplementationcanbeseenbelow

func(appApp)SetStaticPath(urlstringpathstring)App

StaticDir[url]=path

returnapp

Theapplicationsstaticroutescanbesetlikeso

beegoSetStaticPath(imgstaticimg)

Forwardingroutes

Customizedrouters

282

WecanforwardroutesbasedontheforwardinginformationcontainedwithinControllerRegistorThedetailedimplementationcanbeseeninthefollowingcodesnippet

AutoRoute

func(pControllerRegistor)ServeHTTP(whttpResponseWriterrhttpRequest)

deferfunc()

iferr=recover()err=nil

ifRecoverPanic

gobacktopanic

panic(err)

else

Critical(Handlercrashedwitherrorerr)

fori=1i+=1

_filelineok=runtimeCaller(i)

ifok

break

Critical(fileline)

()

varstartedbool

forprefixstaticDir=rangeStaticDir

ifstringsHasPrefix(rURLPathprefix)

file=staticDir+rURLPath[len(prefix)]

httpServeFile(wrfile)

started=true

return

requestPath=rURLPath

findamatchingRoute

for_route=rangeprouters

checkifRoutepatternmatchesurl

ifrouteregexMatchString(requestPath)

continue

getsubmatches(params)

matches=routeregexFindStringSubmatch(requestPath)

doublecheckthattheRoutematchestheURLpattern

iflen(matches[0])=len(requestPath)

continue

params=make(map[string]string)

iflen(routeparams)gt0

addurlparameterstothequeryparammap

values=rURLQuery()

forimatch=rangematches[1]

valuesAdd(routeparams[i]match)

params[routeparams[i]]=match

reassemblequeryparamsandaddtoRawQuery

rURLRawQuery=urlValues(values)Encode()+amp+rURLRawQuery

rURLRawQuery=urlValues(values)Encode()

Invoketherequesthandler

vc=reflectNew(routecontrollerType)

init=vcMethodByName(Init)

in=make([]reflectValue2)

ct=ampContextResponseWriterwRequestrParamsparams

in[0]=reflectValueOf(ct)

in[1]=reflectValueOf(routecontrollerTypeName())

initCall(in)

in=make([]reflectValue0)

Customizedrouters

283

method=vcMethodByName(Prepare)

methodCall(in)

ifrMethod==GET

method=vcMethodByName(Get)

methodCall(in)

elseifrMethod==POST

method=vcMethodByName(Post)

methodCall(in)

elseifrMethod==HEAD

method=vcMethodByName(Head)

methodCall(in)

elseifrMethod==DELETE

method=vcMethodByName(Delete)

methodCall(in)

elseifrMethod==PUT

method=vcMethodByName(Put)

methodCall(in)

elseifrMethod==PATCH

method=vcMethodByName(Patch)

methodCall(in)

elseifrMethod==OPTIONS

method=vcMethodByName(Options)

methodCall(in)

ifAutoRender

method=vcMethodByName(Render)

methodCall(in)

method=vcMethodByName(Finish)

methodCall(in)

started=true

break

ifnomatchestourlthrowanotfoundexception

ifstarted==false

httpNotFound(wr)

GettingstartedUsingourrouterdesignwecansolvethethreelimitationsmentionedearlierThethreemainuse-casesare

Registeringroutehandlers

beegoBeeAppRegisterController(ampcontrollersMainController)

Handlingdynamicparameters

beegoBeeAppRegisterController(paramampcontrollersUserController)

Regexmatching

beegoBeeAppRegisterController(usersuid([0-9]+)ampcontrollersUserController)

LinksDirectoryPrevioussectionProjectplanningNextsectionDesigningcontrollers

Customizedrouters

284

Customizedrouters

285

133DesigningcontrollersMosttraditionalMVCframeworksarebasedonsuffixactionmappingNowadaystheRESTstylewebarchitectureisbecomingincreasinglypopularOnecanimplementREST-styleURLsbyfilteringorrewritingthembutwhynotjustdesignanewREST-styleMVCframeworkinsteadThissectionisbasedonthisideaandfocusesondesigningandimplementingacontrollerbasedREST-styleMVCframeworkfromscratchOurgoalistosimplifythedevelopmentofwebapplicationsperhapsevenallowingustowriteasinglelineofcodecapableofservingHelloworld

ThecontrollersroleTheMVCdesignpatterniscurrentlythemostusedframeworkmodelforwebapplicationsBykeepingModelsViewsandControllersseparatedwecankeepourwebapplicationsmodularmaintainabletestableandextensibleAmodelencapsulatesdataandanyofthebusinesslogicthatgovernsthatdatasuchasaccessibilityrulespersistencevalidationetcViewsserveasthedatasrepresentationandinthecaseofwebapplicationstheyusuallyliveastemplateswhicharethenrenderedintoHTMLandservedControllersserveasthegluelogicbetweenModelsandViewsandtypicallyhavemethodsforhandlingdifferentURLsAsdescribedintheprevioussectionwhenaURLrequestisforwardedtoacontrollerbytherouterthecontrollerdelegatescommandstotheModeltoperformsomeactionthennotifiestheViewofanychangesIncertaincasesthereisnoneedformodelstoperformanykindoflogicalordataprocessingorforanyviewstoberenderedForinstanceinthecaseofanHTTP302redirectnoviewneedstoberenderedandnoprocessingneedstobeperformedbytheModelhowevertheControllersjobisstillessential

RESTfuldesigninBeegoTheprevioussectiondescribesregisteringroutehandlerswithRESTfulstructsNowweneedtodesignthebaseclassforalogiccontrollerthatwillbecomposedoftwopartsastructandinterfacetype

typeControllerstruct

CtContext

TpltemplateTemplate

Datamap[interface]interface

ChildNamestring

TplNamesstring

Layout[]string

TplExtstring

typeControllerInterfaceinterface

Init(ctContextcnstring)Initializethecontextandsubclassname

Prepare()someprocessingbeforeexecutionbegins

Get()method=GETprocessing

Post()method=POSTprocessing

Delete()method=DELETEprocessing

Put()method=PUThandling

Head()method=HEADprocessing

Patch()method=PATCHtreatment

Options()method=OPTIONSprocessing

Finish()executedaftercompletionoftreatment

Render()errormethodexecutedafterthecorrespondingmethodtorenderthepage

ThenaddtheroutehandlingfunctiondescribedearlierinthischapterWhenarouteisdefinedtobeaControllerInterfacetypesolongaswecanimplementthisinterfacewecanhaveaccesstothefollowingmethodsofourbaseclasscontroller

func(cController)Init(ctContextcnstring)

cData=make(map[interface]interface)

cLayout=make([]string0)

Designcontrollers

286

cTplNames=

cChildName=cn

cCt=ct

cTplExt=tpl

func(cController)Prepare()

func(cController)Finish()

func(cController)Get()

httpError(cCtResponseWriterMethodNotAllowed405)

func(cController)Post()

httpError(cCtResponseWriterMethodNotAllowed405)

func(cController)Delete()

httpError(cCtResponseWriterMethodNotAllowed405)

func(cController)Put()

httpError(cCtResponseWriterMethodNotAllowed405)

func(cController)Head()

httpError(cCtResponseWriterMethodNotAllowed405)

func(cController)Patch()

httpError(cCtResponseWriterMethodNotAllowed405)

func(cController)Options()

httpError(cCtResponseWriterMethodNotAllowed405)

func(cController)Render()error

iflen(cLayout)gt0

varfilenames[]string

for_file=rangecLayout

filenames=append(filenamespathJoin(ViewsPathfile))

terr=templateParseFiles(filenames)

iferr=nil

Trace(templateParseFileserrerr)

err=tExecuteTemplate(cCtResponseWritercTplNamescData)

iferr=nil

Trace(templateExecuteerrerr)

else

ifcTplNames==

cTplNames=cChildName++cCtRequestMethod++cTplExt

terr=templateParseFiles(pathJoin(ViewsPathcTplNames))

iferr=nil

Trace(templateParseFileserrerr)

err=tExecute(cCtResponseWritercData)

iferr=nil

Trace(templateExecuteerrerr)

returnnil

Designcontrollers

287

func(cController)Redirect(urlstringcodeint)

cCtRedirect(codeurl)

AbovethecontrollerbaseclassalreadyimplementsthefunctionsdefinedintheinterfaceThroughourroutingrulestherequestwillberoutedtotheappropriatecontrollerwhichwillinturnexecutethefollowingmethods

Init()initializationroutine

Prepare()pre-initializationroutineeachinheritingsubclassmayimplementthisfunction

method()dependingontherequestmethodperformdifferentfunctionsGETPOSTPUTHEADetcSubclassesshouldi

mplementthesefunctionsifnotimplementedthenthedefaultis403

Render()optionalmethodDeterminewhetherornottoexecuteaccordingtotheglobalvariableAutoRender

Finish()isexecutedaftertheactionbeencompletedEachinheritingsubclassmayimplementthisfunction

ApplicationguideAbovewevejustfinisheddiscussingBeegosimplementationofthebasecontrollerclassWecannowusethisinformationtodesignourrequesthandlinginheritingfromthebaseclassandimplementingthenecessarymethodsinourowncontroller

packagecontrollers

import(

githubcomastaxiebeego

)

typeMainControllerstruct

beegoController

func(thisMainController)Get()

thisData[Username]=astaxie

thisData[Email]=astaxiegmailcom

thisTplNames=indextpl

InthecodeaboveweveimplementedasubclassofControllercalledMainControllerwhichonlyimplementstheGet()methodIfausertriestoaccesstheresourceusinganyoftheotherHTTPmethods(POSTHEADetc)a403ForbiddenwillbereturnedHoweverifausersubmitsaGETrequesttotheresourceandwehavetheAutoRendervariablesettotruetheresourcescontrollerwillautomaticallycallitsRender()functionrenderingthecorrespondingtemplateandrespondingwiththefollowing

Theindextplcodecanbeseenbelowasyoucanseeparsingmodeldataintoatemplateisquitesimple

ltDOCTYPEhtmlgt

lthtmlgt

ltheadgt

lttitlegtbeegowelcometemplatelttitlegt

ltheadgt

ltbodygt

lth1gtHelloworldUsernameEmaillth1gt

ltbodygt

lthtmlgt

LinksDirectory

Designcontrollers

288

PrevioussectionCustomizingroutersNextsectionLogsandconfigurations

Designcontrollers

289

134Loggingandconfiguration

TheimportanceofloggingandconfigurationPreviouslyinthebookwesawthateventloggingplaysaveryimportantroleinapplicationdevelopmentWithadequateloggingwecanrecordcrucialinformationthatcanlaterbedissectedfordebuggingandoptimizationpurposesInthesectionwherewelookedattheseelogloggingutilitywesawthatithadsettingsforvariousloglevelgradationswhichcanbeessentialforprogramdevelopmentanddeploymentwecansetthelogginglevellowerinadevelopmentenvironmentwhilesettingithighinproductionsothatwecanmaskextraneousinformationwhenwearetryingtodebugourapplication

SettinguptheserverconfigurationmodulefordeployinganapplicationinvolvesanumberofdifferentserversettingsForexamplewetypicallyneedtoprovideinformationregardingdatabaseconfigurationlisteningportsetcviatheconfigurationfileSettingupacentralizedconfigurationfileallowsustheflexibilityofdeployingtheapplicationtodifferentmachinesandconnectingtoremotedatabasesifneeded

TheBeegologgingsystemTheBeegologgersdesignborrowsideasfromseelogandprovidessimilarfunctionalityintermsofsettinglogginglevelsBeegossystemishowevermorelightweightandmakesuseoftheGoslogLoggerinterfaceBydefaultlogsareoutputtoosStdoutbutuserscanimplementthisinterfacethroughbeegoSetLoggertocustomizethisAdetailedexampleofanimplementedinterfacecanbeseenbelow

Loglevelsforcontrollingtheloggingoutput

const(

LevelTrace=iota

LevelDebug

LevelInfo

LevelWarning

LevelError

LevelCritical

)

logLevelcontrolsthegloballoglevelusedbythelogger

varlevel=LevelTrace

LogLevelreturnsthegloballoglevelandcanbeusedin

acustomimplementationsoftheloggerinterface

funcLevel()int

returnlevel

SetLogLevelsetsthegloballoglevelusedbythesimple

logger

funcSetLevel(lint)

level=l

ThissectionimplementstheaboveloggradingsystemThedefaultlevelissettoTraceanduserscancustomizegradinglevelsusingSetLevel

Logsandconfigurations

290

loggerreferencestheusedapplicationlogger

varBeeLogger=logNew(osStdoutlogLdate|logLtime)

SetLoggersetsanewlogger

funcSetLogger(llogLogger)

BeeLogger=l

Tracelogsamessageattracelevel

funcTrace(vinterface)

iflevellt=LevelTrace

BeeLoggerPrintf([T]vnv)

Debuglogsamessageatdebuglevel

funcDebug(vinterface)

iflevellt=LevelDebug

BeeLoggerPrintf([D]vnv)

Infologsamessageatinfolevel

funcInfo(vinterface)

iflevellt=LevelInfo

BeeLoggerPrintf([I]vnv)

Warninglogsamessageatwarninglevel

funcWarn(vinterface)

iflevellt=LevelWarning

BeeLoggerPrintf([W]vnv)

Errorlogsamessageaterrorlevel

funcError(vinterface)

iflevellt=LevelError

BeeLoggerPrintf([E]vnv)

Criticallogsamessageatcriticallevel

funcCritical(vinterface)

iflevellt=LevelCritical

BeeLoggerPrintf([C]vnv)

ThecodesnippetaboveinitializesaBeeLoggerobjectbydefaultoutputtinglogstoosStdoutAsmentioneduserscanimplementbeegoSetLoggertocustomizetheloggersoutputBeeLoggerimplementssixfunctions

Trace(recordgeneralinformationforexample)EnteredparsefunctionvalidationblockValidationenteredsecondifDictionaryDictisemptyUsingdefaultvalue

Debug(debugginginformationforexample)WebpagerequestedhttpsomesitecomParams=ResponsegeneratedResponsesize10000SendingNewfilereceivedTypePNGSize20000

Info(printinggeneralinformationforexample)WebserverrestartedHourlystatisticsRequestedpages12345Errors123ServicepausedWaitingforresumecall

Logsandconfigurations

291

Warn(warningmessagesforexample)Cachecorruptedforfile=testfileReadingfromback-endDatabase19216807DBnotrespondingUsingbackup19216808DBNoresponsefromstatisticsserverStatisticsnotsent

Error(errormessagesforexample)InternalerrorCannotprocessrequest12345ErrorCannotperformlogincredentialsDBnotresponding

Critical(fatalerrorsforexample)CriticalpanicreceivedShuttingdownFatalerrorAppisshuttingdowntopreventdatacorruptionorloss

YoucanseethateachoftheselevelshasaspecificpurposeForinstanceifwesettheloggingleveltoWarn(level=LevelWarning)atthetimeofdeploymentallofthelowerlevellogs(TraceDebugInfo)willnotoutputanything

BeegoconfigurationdesignForprocessingconfigurationinformationBeegoimplementsakey=valuefileparserwhichreadsinformationformattedsimilarlytoiniconfigurationfilesTheparserreadstheconfigurationdataandsavesittoamapFinallyitcallsseveralfunctionsforretrievingthevaluesdatatype(intstringetc)Thedetailedimplementationcanbeseenbelow

Definesomeglobalconstantsfortheiniconfigurationfile

var(

bComment=[]byte

bEmpty=[]byte

bEqual=[]byte=

bDQuote=[]byte

)

Definestheformatoftheconfigurationfile

AConfigrepresentstheconfiguration

typeConfigstruct

filenamestring

commentmap[int][]stringid[]commentkeyid1isformaincomment

datamap[string]stringkeyvalue

offsetmap[string]int64keyoffsetforediting

syncRWMutex

DefinesafunctionforparsingthefileTheprocessbeginsbyopeningthefilethenreadingitlinebylineandparsingcommentsblanklinesandkey=valuedata

Logsandconfigurations

292

ParseFilecreatesanewConfigandparsesthefileconfigurationfromthe

namedfile

funcLoadConfig(namestring)(Configerror)

fileerr=osOpen(name)

iferr=nil

returnnilerr

cfg=ampConfig

fileName()

make(map[int][]string)

make(map[string]string)

make(map[string]int64)

syncRWMutex

cfgLock()

defercfgUnlock()

deferfileClose()

varcommentbytesBuffer

buf=bufioNewReader(file)

fornCommentoff=0int64(1)

line_err=bufReadLine()

iferr==ioEOF

break

ifbytesEqual(linebEmpty)

continue

off+=int64(len(line))

ifbytesHasPrefix(linebComment)

line=bytesTrimLeft(line)

line=bytesTrimLeftFunc(lineunicodeIsSpace)

commentWrite(line)

commentWriteByte(n)

continue

ifcommentLen()=0

cfgcomment[nComment]=[]stringcommentString()

commentReset()

nComment++

val=bytesSplitN(linebEqual2)

ifbytesHasPrefix(val[1]bDQuote)

val[1]=bytesTrim(val[1]``)

key=stringsTrimSpace(string(val[0]))

cfgcomment[nComment-1]=append(cfgcomment[nComment-1]key)

cfgdata[key]=stringsTrimSpace(string(val[1]))

cfgoffset[key]=off

returncfgnil

BelowareanumberoffunctionstheparserusesforreadingtheconfigurationfileThereturnvalueisdeterminedaseitheraboolintfloat64orstring

Logsandconfigurations

293

Boolreturnsthebooleanvalueforagivenkey

func(cConfig)Bool(keystring)(boolerror)

returnstrconvParseBool(cdata[key])

Intreturnstheintegervalueforagivenkey

func(cConfig)Int(keystring)(interror)

returnstrconvAtoi(cdata[key])

Floatreturnsthefloatvalueforagivenkey

func(cConfig)Float(keystring)(float64error)

returnstrconvParseFloat(cdata[key]64)

Stringreturnsthestringvalueforagivenkey

func(cConfig)String(keystring)string

returncdata[key]

ApplicationguideThefollowingfunctionisanexampleofanapplicationIusedtofetchjsondatafromaremoteurladdress

funcGetJson()

resperr=httpGet(beegoAppConfigString(url))

iferr=nil

beegoCritical(httpgetinfoerror)

return

deferrespBodyClose()

bodyerr=ioutilReadAll(respBody)

err=jsonUnmarshal(bodyampAllInfo)

iferr=nil

beegoCritical(errorerr)

BeegosCritical()loggingfunctioniscalledtoreportanyerrorswhichmayoccurintheGetJson()functionbeegoAppConfigString(url)isusedtoobtaininformationfromaconfigurationfile(typicallyappconf)whichmightlooksomethinglikethefollowing

appname=hs

url=httpwwwapicomapihtml

LinksDirectoryPrevioussectionDesigningcontrollersNextsectionAddingdeletingandupdatingblogs

Logsandconfigurations

294

135AddingdeletingandupdatingblogsWevealreadyintroducedtheentireconceptbehindtheBeegoframeworkthroughexamplesandpseudo-codeThissectionwilldescribehowtoimplementabloggingsystemusingBeegoincludingtheabilitytobrowseaddmodifyanddeleteblogposts

BlogdirectoryOurblogsdirectorystructurecanbeseenbelow

maingo

views

viewtpl

newtpl

layouttpl

indextpl

edittpl

modelsmodelgo

controllers

indexgo

viewgo

newgo

deletego

editgo

BlogroutingOurblogsmainroutingrulesareasfollows

ShowblogHome

beegoRegisterController(ampcontrollersIndexController)

Viewblogdetails

beegoRegisterController(viewid([0-9]+)ampcontrollersViewController)

CreateblogBowen

beegoRegisterController(newampcontrollersNewController)

DeleteBowen

beegoRegisterController(deleteid([0-9]+)ampcontrollersDeleteController)

EditBowen

beegoRegisterController(editid([0-9]+)ampcontrollersEditController)

DatabasestructureAtrivialdatabasetabletostorebasicbloginformation

CREATETABLEentries(

idINTAUTO_INCREMENT

titleTEXT

contentTEXT

createdDATETIME

primarykey(id)

)

ControllerIndexController

Adddeleteandupdateblogs

295

typeIndexControllerstruct

beegoController

func(thisIndexController)Get()

thisData[blogs]=modelsGetAll()

thisLayout=layouttpl

thisTplNames=indextpl

ViewController

typeViewControllerstruct

beegoController

func(thisViewController)Get()

inputs=thisInput()

id_=strconvAtoi(thisCtxParams[id])

thisData[Post]=modelsGetBlog(id)

thisLayout=layouttpl

thisTplNames=viewtpl

NewController

typeNewControllerstruct

beegoController

func(thisNewController)Get()

thisLayout=layouttpl

thisTplNames=newtpl

func(thisNewController)Post()

inputs=thisInput()

varblogmodelsBlog

blogTitle=inputsGet(title)

blogContent=inputsGet(content)

blogCreated=timeNow()

modelsSaveBlog(blog)

thisCtxRedirect(302)

EditController

Adddeleteandupdateblogs

296

typeEditControllerstruct

beegoController

func(thisEditController)Get()

inputs=thisInput()

id_=strconvAtoi(thisCtxParams[id])

thisData[Post]=modelsGetBlog(id)

thisLayout=layouttpl

thisTplNames=edittpl

func(thisEditController)Post()

inputs=thisInput()

varblogmodelsBlog

blogId_=strconvAtoi(inputsGet(id))

blogTitle=inputsGet(title)

blogContent=inputsGet(content)

blogCreated=timeNow()

modelsSaveBlog(blog)

thisCtxRedirect(302)

DeleteController

typeDeleteControllerstruct

beegoController

func(thisDeleteController)Get()

id_=strconvAtoi(thisCtxInputParams[id])

blog=modelsGetBlog(id)

thisData[Post]=blog

modelsDelBlog(blog)

thisCtxRedirect(302)

Modellayer

Adddeleteandupdateblogs

297

packagemodels

import(

databasesql

githubcomastaxiebeedb

_githubcomziutekmymysqlgodrv

time

)

typeBlogstruct

Idint`PK`

Titlestring

Contentstring

CreatedtimeTime

funcGetLink()beedbModel

dberr=sqlOpen(mymysqlblogastaxie123456)

iferr=nil

panic(err)

orm=beedbNew(db)

returnorm

funcGetAll()(blogs[]Blog)

db=GetLink()

dbFindAll(ampblogs)

return

funcGetBlog(idint)(blogBlog)

db=GetLink()

dbWhere(id=id)Find(ampblog)

return

funcSaveBlog(blogBlog)(bgBlog)

db=GetLink()

dbSave(ampblog)

returnbg

funcDelBlog(blogBlog)

db=GetLink()

dbDelete(ampblog)

return

Viewlayerlayouttpl

Adddeleteandupdateblogs

298

lthtmlgt

ltheadgt

lttitlegtMyBloglttitlegt

ltstylegt

menu

width200px

floatright

ltstylegt

ltheadgt

ltbodygt

ltulid=menugt

ltligtltahref=gtHomeltagtltligt

ltligtltahref=newgtNewPostltagtltligt

ltulgt

LayoutContent

ltbodygt

lthtmlgt

indextpl

lth1gtBlogpostslth1gt

ltulgt

rangeblogs

ltligt

ltahref=viewIdgtTitleltagt

fromCreated

ltahref=editIdgtEditltagt

ltahref=deleteIdgtDeleteltagt

ltligt

end

ltulgt

viewtpl

lth1gtPostTitlelth1gt

PostCreatedltbrgt

PostContent

newtpl

lth1gtNewBlogPostlth1gt

ltformaction=method=postgt

Titleltinputtype=textname=titlegtltbrgt

Contentlttextareaname=contentcolspan=3rowspan=10gtlttextareagt

ltinputtype=submitgt

ltformgt

edittpl

lth1gtEditPostTitlelth1gt

lth1gtNewBlogPostlth1gt

ltformaction=method=postgt

Titleltinputtype=textname=titlevalue=PostTitlegtltbrgt

Contentlttextareaname=contentcolspan=3rowspan=10gtPostContentlttextareagt

ltinputtype=hiddenname=idvalue=PostIdgt

ltinputtype=submitgt

ltformgt

Adddeleteandupdateblogs

299

LinksDirectoryPrevioussectionLogsandconfigurationsNextsectionSummary

Adddeleteandupdateblogs

300

136SummaryInthischapterwedescribedhowtoimplementthemajorcomponentsofaGowebframeworkWefirstdesignedaroutertomakeupforsomeofshortcomingsinGosbuilt-inhttppackagecreatingaroutercapableofdynamicroutingandRESTsupportWealsodesignedourownRESTfulControllerclassinaccordwiththeprinciplesofMVCborrowingideasfromframeworkssuchasTornadoNextwedesignedandimplementedatemplatelayoutandautomatedrenderingsystemmainlyusingGosbuilt-intemplatingengineWethenimplementedacustomloggerandtalkedaboutframeworkconfigurationtoallowforflexibleapplicationdeploymentThroughthisprocesswehaveimplementedabasicwebframeworkcalledBeegowhichatpresenthasbeenopen-sourcedonGithubLastlyweimplementedasimplebloggingapplicationontopofBeegoAfterhavinggonethroughalloftheseexamplesyouwillhopefullyhavelearnedhowtoquicklydevelopwebsitesinGo

LinksDirectoryPrevioussectionAdddeleteandupdateblogsNextchapterDevelopwebframework

Summary

301

14DevelopingawebframeworkChapter13describedhowtodevelopawebframeworkinGoWeintroducedtheMVCarchitecturearoutingandloggingsystemandwealsolookedatsimpleserverconfigurationThesearethebasicbuildingblocksofmostframeworksanditsagoodstartHoweverformoresophisticatedneedssomeauxiliarytoolsareneededtofacilitaterapidwebsitedevelopmentInthischapterwewillprovidesomequicktipsandtoolsforspeedingupdevelopmentThefirstsectionwillcoverthehow-toshowprocessingstaticfilesandwewillbeusingTwittersopensourceCSSandJavascriptframeworkcalledBootstrapforbeautifyingourwebsiteThesecondsectiondescribeshowtousethepreviouslydescribedsessionsforuserloginprocessingNextthethirdsectiondescribeshowtogenerateformsandhowtoprocesstheseformsforvaliddataWewillalsotalkabouthowtobindmodelsforCRUDoperationsInsection4welldescribehowtoperformsomeuserauthenticationincludingbasicHTTPauthenticationandHTTPdigestauthenticationFinallythelastsectionwilltalkaboutimplementingthepreviouslydescribedi18ntosupportmulti-lingualwebapplications

ByextendingBeegointhischapterwewillbeabletorapidlydevelopfullstackwebapplicationsOfcoursewellgothroughthefeaturesoftheseextensionsstep-by-stepapplyingthemtothebloggingsystemwedevelopedinChapter13ThroughthedevelopmentofacompleteandbeautifulbloggingsystemuserswillhopefullybeabletoseehowBeegocanhelptoboostdeveloperproductivity

LinksDirectoryPreviouschapterChapter13summaryNextsectionStaticfiles

Developwebframework

302

141StaticfilesWevealreadytalkedabouthowtodealwithstaticfilesinprevioussectionsNowletslookathowtosetupandusestaticfilesinsideofBeegoThenthroughintroducingTwittersopensourceHTMLandCSSframeworkBootstrapwellbeablequicklycreatebeautifullookingwebsiteswithouthavingtodotoomuchdesignwork

BeegostaticfilesandsettingsGosnethttppackageprovidesastaticfileserverwithfunctionssuchasServeFileandFileServerBeegosstaticfilehandlingisbasedonthislayeranditsspecificimplementationisasfollow

staticfileserver

forprefixstaticDir=rangeStaticDir

ifstringsHasPrefix(rURLPathprefix)

file=staticDir+rURLPath[len(prefix)]

httpServeFile(wrfile)

wstarted=true

return

StaticDirstorestheURLwhichcorrespondstoastaticfiledirectorysowhenhandlingrequestswesimplyneedtodeterminewhetherornottheURLbeginswithastaticfilepathIfsowecansimplyrespondusinghttpServeFile

Thefollowingisanexample

beegoStaticDir[asset]=static

ThenarequestwithaURLsuchashttpwwwbeegomeassetbootstrapcsswillresultinstaticbootstrapcssbeingservedtotheclient

BootstrapintegrationBootstrapisanopensourceToolkitforfront-enddevelopmentlaunchedbyTwitterFordevelopersBootstrapisoneofthebestfrontendkitsforrapidWebapplicationdevelopmentItisacollectionofHTMLCSSandjavascriptcomponentsusingthelatestHTML5standardsTheseincludearesponsivegridformsbuttonstablesandmanyotherusefulthings

ComponentsBootstrapcontainsawealthofWebcomponentsUsingthesecomponentsyoucanquicklybuildabeautifulfullyfunctionalwebsitewhichincludesthefollowingcomponentsPull-downmenusbuttongroupsbuttondrop-downmenusnavigationnavigationbarsbreadcrumbspaginationlayoutthumbnailswarningdialogsprogressbarsandothermediaobjectsJavaScriptpluginsBootstrapcomeswith13jQueryplug-insforBootstrapcomponentswhichgivesthemlifeTheseincludeModaldialogstabsscrollbarspop-upboxesandsoonBootstrapframeworkcustomizationAllBootstrapcssvariablescanbemodifiedaccordingtoyourneeds

Figure141abootstrapwebsite

NextletsseehowwecanuseBootstrapinsideourBeegoapplicationtoquicklycreateabeautifulwebsite

1 Firstletsdownloadthebootstrapdirectoryintoourprojectsstaticdirectoryasshowninthefollowingscreenshot

Staticfiles

303

Figure142Projectstaticfiledirectorystructure

2 BecauseBeegosetsadefaultvalueforStaticDirifyourstaticfilesdirectoryisstaticthenyouneednotgoanyfurther

StaticDir[static]=static

3 Ourtemplatesusethefollowingassetpaths

cssfile

ltlinkhref=staticcssbootstrapcssrel=stylesheetgt

jsfile

ltscriptsrc=staticjsbootstrap-transitionjsgtltscriptgt

Picturefiles

ltimgsrc=staticimglogopnggt

WiththeabovecodeweareintegratingBootstrapintoourBeegoapplicationThefigurebelowdemonstratestherenderedpage

Figure143websiteintegratedwithBootstrap

ThesetemplatesandformatsallcomeshippedwithBootstrapsowewontrepeatthecompletecodeherehoweveryoucantakealookattheprojectsofficialpagetolearnhowtowriteyourowntemplates

LinksDirectoryPrevioussectionDevelopingawebframeworkNextsectionSessions

Staticfiles

304

142SessionsInchapter6weintroducedsomebasicconceptspertainingtosessionsinGoandweimplementedasessionmanagerTheBeegoframeworkusesthissessionmanagertoimplementsomeconvenientsession-handlingfunctionality

IntegratingsessionsBeegohandlessessionsmainlyaccordingtothefollowingglobalvariables

relatedtosession

SessionOnboolwhetherornottoopenthesessionmoduleDefaultstofalse

SessionProviderstringthedesiredsessionbackendprocessingmoduleDefaultstoanin-memorysessionManager

SessionNamestringthenameoftheclientsavedcookies

SessionGCMaxLifetimeint64cookievalidity

GlobalSessionssessionManagerglobalsessioncontroller

OfcoursethevaluesofthesevariablesshownaboveneedtobeinitializedYoucanalsousethevaluesfromthefollowingconfigurationfilecodetosetthesevalues

ifarerr=AppConfigBool(sessionon)err=nil

SessionOn=false

else

SessionOn=ar

ifar=AppConfigString(sessionprovider)ar==

SessionProvider=memory

else

SessionProvider=ar

ifar=AppConfigString(sessionname)ar==

SessionName=beegosessionID

else

SessionName=ar

ifarerr=AppConfigInt(sessiongcmaxlifetime)err=nilampampar=0

int64val_=strconvParseInt(strconvItoa(ar)1064)

SessionGCMaxLifetime=int64val

else

SessionGCMaxLifetime=3600

AddthefollowingcodeinthebeegoRunfunction

ifSessionOn

GlobalSessions_=sessionNewManager(SessionProviderSessionNameSessionGCMaxLifetime)

goGlobalSessionsGC()

AslongasSessionOnissettotrueitwillopenthesessionbydefaultwithanindependentgoroutinesessionhandler

InordertofacilitateourcustomControllerquicklyusingsessiontheauthorbeegoControllerprovidesthefollowingmethods

ToassistusinquicklyusingsessionsinacustomControllerbeegoControllerprovidesthefollowingmethod

Session

305

func(cController)StartSession()(sesssessionSession)

sess=GlobalSessionsSessionStart(cCtxResponseWritercCtxRequest)

return

UsingsessionsFromthecodeabovewecanseethattheBeegoframeworksimplyinheritsitssessionfunctionalitySohowdoweuseitinourprojects

Firstofallweneedtoopenthesessionattheentrypointofourapplication

beegoSessionOn=true

Wecanthenusethecorrespondingsessionmethodinsideourcontrollerlikeso

func(thisMainController)Get()

varintcountint

sess=thisStartSession()

count=sessGet(count)

ifcount==nil

intcount=0

else

intcount=count(int)

intcount=intcount+1

sessSet(countintcount)

thisData[Username]=astaxie

thisData[Email]=astaxiegmailcom

thisData[Count]=intcount

thisTplNames=indextpl

ThecodeaboveshowshowtousesessionsinthecontrollerlogicTheprocesscanbedividedintotwosteps

1 Gettingsessionobject

GettheobjectsimilarinPHPsession_start()

sess=thisStartSession()

2 Usingthesessionforgeneraloperations

GetthesessionvaluessimilarinPHP$_SESSION[count]

sessGet(count)

Setthesessionvalue

sessSet(countintcount)

AsyoucanseeapplicationsbasedontheBeegoframeworkcaneasilyimplementsessionsTheprocessisverysimilartocallingsession_start()inPHPapplications

LinksDirectoryPrevioussectionStaticfilesNextsectionForms

Session

306

Session

307

143FormsInwebdevelopmentthefollowingworkflowwillprobablylookquitefamiliar

OpenawebpageshowingaformUsersfilloutandsubmittheformIfausersubmitssomeinvalidinformationorhasneglectedtofilloutarequiredfieldtheformwillbereturnedtotheuser(alongwiththefilledindata)withsomedescriptiveinformationabouttheproblemUsersre-filltheinvalidfieldsandcontinueattemptingtosubmittheformuntilitsaccepted

Atthereceivingendthescriptmust

ChecktheusersubmittedformdataVerifywhetherthedataisthecorrecttypeandoftheappropriatestandardForexampleifausernameissubmitteditmustverifythatitcontainsonlyvalidcharactersOtherexampleswouldbecheckingforminimumandmaximumlengthsusernameuniquenessandsoonFilteringdataandcleaningupunsafecharacterstoguaranteethatourapplicationonlyprocessesdatawhichissafeIfnecessarypre-formatthedata(ordatagapsneedtobeclearedthroughtheHTMLcodingandsoon)Preparethedataforinsertionintothedatabase

AlthoughtheprocedureisnotverycomplexitusuallyrequiresalotofboilerplateInadditionwebapplicationsoftenuseavarietyofdifferentcontrolstructurestodisplayerrormessagesonreturnedpagesImplementingformvalidationisasimplebutboringtask

FormsandvalidationFordevelopersthegeneraldevelopmentprocesscanbequitecomplexbutitsmostlyrepetitiveworkSupposeascenarioariseswhereyousuddenlyneedtoaddaformtoyourprojectcausingyoutorewriteallofthelocalcodetiedinwiththeformWeknowthatstructsareaverycommonlyuseddatastructureinGoandBeegousesthemtoitsadvantageforprocessingforminformation

FirstwedefineastructwithfieldscorrespondingtothefieldsinourformelementWecanusestructtagswhichmaptotheformelementasshownbelow

WhendevelopingWebapplicationsfirstdefineastructthatmatchesafieldtoacorrespondingformelementdefinedbyusingastructtagcorrespondingtotheelementinformationandauthenticationinformationasshownbelow

FordevelopersthegeneraldevelopmentprocessisverycomplexandmostlyconsistsofrepeatingthesameworkprocessAssumingascenarioforaprojectwherebyaneedarisestoadddatatoaformthenthelocalcodeoftheentireprocessneedstobemodifiedWeknowinGoastructisacommondatastructuresobeegousesaformstructtoprocessforminformation

Firstdefineastructwithfieldscorrespondingtoourformelementusingstructtagstodefinethecorrespondingformelementandauthenticationinformationlikeso

typeUserstruct

Usernamestring`formtextvalidrequired`

Nicknamestring`formtextvalidrequired`

Ageint`formtextvalidrequired|numeric`

Emailstring`formtextvalidrequired|valid_email`

Introducestring`formtextarea`

Afterdefiningourstructwecanaddthisactioninourcontroller

Form

308

func(thisAddController)Get()

thisData[form]=beegoForm(ampUser)

thisLayout=adminlayouthtml

thisTplNames=adminaddtpl

Theformisdisplayedinourtemplatelikeso

lth1gtNewBlogPostlth1gt

ltformaction=method=postgt

formrender()

ltformgt

AbovewevedefinedtheentirefirststepofdisplayingaformmappedtoastructThenextstepisforuserstofillintheirinformationandsubmittheformafterwhichtheserverwillreceivethedataandverifyitFinallytherecordwillbeinsertedintothedatabase

func(thisAddController)Post()

varuserUser

form=thisGetInput(ampuser)

ifformValidates()

return

modelsUserInsert(ampuser)

thisCtxRedirect(302adminindex)

FormtypeThefollowingtableliststhecorrespondingformelementinformation

lttablecellpadding=0cellspacing=1border=0style=width100class=tablebordergt

lttbodygt

lttrgt

ltthgtNameltthgt

ltthgtparameterltthgt

ltthgtDescriptionltthgt

lttrgt

lttrgt

lttdclass=tdgtltstronggttextltstronggt

lttdgt

lttdclass=tdgtNolttdgt

lttdclass=tdgttextboxinputboxlttdgt

lttrgt

lttrgt

lttdclass=tdgtltstronggtbuttonltstronggt

lttdgt

lttdclass=tdgtNolttdgt

lttdclass=tdgtbuttonlttdgt

lttrgt

lttrgt

lttdclass=tdgtltstronggtcheckboxltstronggt

lttdgt

lttdclass=tdgtNolttdgt

lttdclass=tdgtmulti-selectboxlttdgt

lttrgt

lttrgt

lttdclass=tdgtltstronggtdropdownltstronggt

lttdgt

lttdclass=tdgtNolttdgt

lttdclass=tdgtdrop-downselectionboxlttdgt

Form

309

lttrgt

lttrgt

lttdclass=tdgtltstronggtfileltstronggt

lttdgt

lttdclass=tdgtNolttdgt

lttdclass=tdgtfileuploadlttdgt

lttrgt

lttrgt

lttdclass=tdgtltstronggthiddenltstronggt

lttdgt

lttdclass=tdgtNolttdgt

lttdclass=tdgthiddenelementslttdgt

lttrgt

lttrgt

lttdclass=tdgtltstronggtpasswordltstronggt

lttdgt

lttdclass=tdgtNolttdgt

lttdclass=tdgtpasswordinputboxlttdgt

lttrgt

lttrgt

lttdclass=tdgtltstronggtradioltstronggt

lttdgt

lttdclass=tdgtNolttdgt

lttdclass=tdgtsingleboxlttdgt

lttrgt

lttrgt

lttdclass=tdgtltstronggttextarealtstronggt

lttdgt

lttdclass=tdgtNolttdgt

lttdclass=tdgttextinputboxlttdgt

lttrgt

lttbodygt

lttablegt

FormvalidationThefollowingtablelistssomeformvalidationrulesnativetoBeegothatcanbeused

lttablecellpadding=0cellspacing=1border=0style=width100class=tablebordergt

lttbodygt

lttrgt

ltthgtrulesltthgt

ltthgtparameterltthgt

ltthgtDescriptionltthgt

ltthgtExampleltthgt

lttrgt

lttrgt

lttdclass=tdgtltstronggtrequiredltstronggt

lttdgt

lttdclass=tdgtNolttdgt

lttdclass=tdgtIftheelementisemptyitreturnsFALSElttdgt

lttdclass=tdgtlttdgt

lttrgt

lttrgt

lttdclass=tdgtltstronggtmatchesltstronggt

lttdgt

lttdclass=tdgtYeslttdgt

lttdclass=tdgtiftheformelementsvaluewiththecorrespondingformfieldparametervaluesarenotequalth

enreturn

FALSElttdgt

lttdclass=tdgtmatches[form_item]lttdgt

lttrgt

Form

310

lttrgt

lttdclass=tdgtltstronggtis_uniqueltstronggt

lttdgt

lttdclass=tdgtYeslttdgt

lttdclass=tdgtiftheformelementsvaluewiththespecifiedfieldinatablehasduplicatedataitreturnsF

alse(Translators

NoteForexampleis_unique[UserEmail]thenthevalidationclasswilllookfortheUsertableinthe

Emailfieldthereisnoformelementswiththesamevaluesuchasdepositrepeatitreturnsfalseso

developersdonothavetowriteanotherCallbackverificationcode)lttdgt

lttdclass=tdgtis_unique[tablefield]lttdgt

lttrgt

lttrgt

lttdclass=tdgtltstronggtmin_lengthltstronggt

lttdgt

lttdclass=tdgtYeslttdgt

lttdclass=tdgtformelementvaluesifthecharacterlengthislessthanthenumberofdefinedparametersitre

turnsFALSElttdgt

lttdclass=tdgtmin_length[6]lttdgt

lttrgt

lttrgt

lttdclass=tdgtltstronggtmax_lengthltstronggt

lttdgt

lttdclass=tdgtYeslttdgt

lttdclass=tdgtiftheformelementsvalueisgreaterthanthelengthofthecharacterdefinednumericargument

itreturns

FALSElttdgt

lttdclass=tdgtmax_length[12]lttdgt

lttrgt

lttrgt

lttdclass=tdgtltstronggtexact_lengthltstronggt

lttdgt

lttdclass=tdgtYeslttdgt

lttdclass=tdgtiftheformelementvaluesandparametersdefinedcharacterlengthnumberdoesnotmatchitret

urnsFALSElttdgt

lttdclass=tdgtexact_length[8]lttdgt

lttrgt

lttrgt

lttdclass=tdgtltstronggtgreater_thanltstronggt

lttdgt

lttdclass=tdgtYeslttdgt

lttdclass=tdgtIftheformelementvaluesnon-numerictypesorlessthanthevaluedefinedparametersitret

urnsFALSElttdgt

lttdclass=tdgtgreater_than[8]lttdgt

lttrgt

lttrgt

lttdclass=tdgtltstronggtless_thanltstronggt

lttdgt

lttdclass=tdgtYeslttdgt

lttdclass=tdgtIftheformelementvaluesnon-numerictypesorgreaterthanthevaluedefinedparametersit

returnsFALSElttdgt

lttdclass=tdgtless_than[8]lttdgt

Form

311

lttrgt

lttrgt

lttdclass=tdgtltstronggtalphaltstronggt

lttdgt

lttdclass=tdgtNolttdgt

lttdclass=tdgtIftheformelementvaluecontainscharactersotherthanlettersbesidesitreturnsFALSElttdgt

lttdclass=tdgtlttdgt

lttrgt

lttrgt

lttdclass=tdgtltstronggtalpha_numericltstronggt

lttdgt

lttdclass=tdgtNolttdgt

lttdclass=tdgtIftheformelementvaluescontainedinadditiontolettersandothercharactersotherthannumb

ersitreturns

FALSElttdgt

lttdclass=tdgtlttdgt

lttrgt

lttrgt

lttdclass=tdgtltstronggtalpha_dashltstronggt

lttdgt

lttdclass=tdgtNolttdgt

lttdclass=tdgtIftheformelementvaluecontainsinadditiontotheletternumberunderlinecharactersothe

rthandash

returnsFALSElttdgt

lttdclass=tdgtlttdgt

lttrgt

lttrgt

lttdclass=tdgtltstronggtnumericltstronggt

lttdgt

lttdclass=tdgtNolttdgt

lttdclass=tdgtIftheformelementvaluecontainscharactersotherthannumbersinadditionitreturnsFALSElt

tdgt

lttdclass=tdgtlttdgt

lttrgt

lttrgt

lttdclass=tdgtltstronggtintegerltstronggt

lttdgt

lttdclass=tdgtNolttdgt

lttdclass=tdgtexceptiftheformelementcontainscharactersotherthananintegeritreturnsFALSElttdgt

lttdclass=tdgtlttdgt

lttrgt

lttrgt

lttdclass=tdgtltstronggtdecimalltstronggt

lttdgt

lttdclass=tdgtYeslttdgt

lttdclass=tdgtIftheformelementtype(non-decimal)isnotcompleteitreturnsFALSElttdgt

lttdclass=tdgtlttdgt

lttrgt

lttrgt

lttdclass=tdgtltstronggtis_naturalltstronggt

lttdgt

lttdclass=tdgtNolttdgt

lttdclass=tdgtvalueiftheformelementcontainsanumberofotherunnaturalvalues(othervaluesexcludingz

ero)it

returnsFALSENaturalnumberslikethis0123andsoonlttdgt

lttdclass=tdgtlttdgt

lttrgt

lttrgt

lttdclass=tdgtltstronggtis_natural_no_zeroltstronggt

Form

312

lttdgt

lttdclass=tdgtNolttdgt

lttdclass=tdgtvalueiftheformelementcontainsanumberofotherunnaturalvalues(othervaluesincludingz

ero)it

returnsFALSENonzeronaturalnumbers123andsoonlttdgt

lttdclass=tdgtlttdgt

lttrgt

lttrgt

lttdclass=tdgtltstronggtvalid_emailltstronggt

lttdgt

lttdclass=tdgtNolttdgt

lttdclass=tdgtIftheformelementvaluecontainsinvalidemailaddressitreturnsFALSElttdgt

lttdclass=tdgtlttdgt

lttrgt

lttrgt

lttdclass=tdgtltstronggtvalid_emailsltstronggt

lttdgt

lttdclass=tdgtNolttdgt

lttdclass=tdgtformelementvaluesifanyonevaluecontainsinvalidemailaddress(addressesseparatedbycomm

asinEnglish

)itreturnsFALSElttdgt

lttdclass=tdgtlttdgt

lttrgt

lttrgt

lttdclass=tdgtltstronggtvalid_ipltstronggt

lttdgt

lttdclass=tdgtNolttdgt

lttdclass=tdgtiftheformelementsvalueisnotavalidIPaddressitreturnsFALSElttdgt

lttdclass=tdgtlttdgt

lttrgt

lttrgt

lttdclass=tdgtltstronggtvalid_base64ltstronggt

lttdgt

lttdclass=tdgtNolttdgt

lttdclass=tdgtiftheformelementsvaluecontainsthebase64-encodedcharactersinadditiontootherthanthe

characters

returnsFALSElttdgt

lttdclass=tdgtlttdgt

lttrgt

lttbodygt

lttablegt

LinksDirectoryPrevioussectionSessionsNextsectionUservalidation

Form

313

144UservalidationIntheprocessofdevelopingwebapplicationsuserauthenticationisaproblemwhichdevelopersfrequentlyencounterUserloginregistrationandlogoutamongotheroperationsaswellasgeneralauthenticationcanbedividedintothreeparts

HTTPBasicandHTTPDigestAuthenticationThirdPartyAuthenticationIntegrationQQmicro-bloggingwatercressOPENIDGoogleGitHubFacebookandtwitteretcCustomuserloginregistrationlogoutaregenerallybasedonsessionsandcookieauthentication

BeegodoesnotnativelyprovidesupportforanyofthesethreethingshoweveryoucaneasilymakeuseofexistingthirdpartyopensourcelibrariestoimplementthemThefirsttwoauthenticationsolutionsareonBeegosroadmaptoeventuallybeintegrated

HTTPbasicanddigestauthenticationBothHTTPbasicanddigestauthenticationarerelativelysimpletechniquescommonlyusedbywebapplicationsTherearealreadymanyopensourcethird-partylibrarieswhichsupportthesetwoauthenticationmethodssuchas

githubcomabbotgo-http-auth

ThefollowingcodedemonstrateshowtousethislibrarytoimplementauthenticationinaBeegoapplication

packagecontrollers

import(

githubcomabbotgo-http-auth

githubcomastaxiebeego

)

funcSecret(userrealmstring)string

ifuser==john

passwordishello

return$1$dlPL2MqE$oQmn16q49SqdmhenQuNgs1

return

typeMainControllerstruct

beegoController

func(thisMainController)Prepare()

a=authNewBasicAuthenticator(examplecomSecret)

ifusername=aCheckAuth(thisCtxRequest)username==

aRequireAuth(thisCtxResponseWriterthisCtxRequest)

func(thisMainController)Get()

thisData[Username]=astaxie

thisData[Email]=astaxiegmailcom

thisTplNames=indextpl

TheabovecodetakesadvantageofBeegosprepare()functiontoperformauthenticationbeforeallowingthenormalflowofexecutiontoproceedasyoucanseeitsverysimpletoimplementHTTPauthenticationDigestauthenticationcanbeimplementedinmuchthesameway

Uservalidation

314

OAuthandOAuth2authenticationOAuthandOAuth2arecurrentlytwoofthemostpopularauthenticationmethodsFortunatelytherearethird-partylibrarieswhichimplementthistypeofauthenticationsuchasthegoauthpackageavailableongithub

githubcombradrydzewskigoauth

ThecodebelowdemonstrateshowtousethislibrarytoimplementOAuthauthenticationinBeegousingourGithubcredentials

1 Letsaddsomeroutes

beegoRegisterController(authloginampcontrollersGithubController)

beegoRegisterController(mainpageampcontrollersPageController)

2 ThenwedealwiththeGithubControllerlandingpage

packagecontrollers

import(

githubcomastaxiebeego

githubcombradrydzewskigoauth

)

const(

githubClientKey=a0864ea791ce7e7bd0df

githubSecretKey=a0ec09a647a688a64a28f6190b5a0d2705df56ca

)

typeGithubControllerstruct

beegoController

func(thisGithubController)Get()

settheauthparameters

authConfigCookieSecret=[]byte(7H9xiimk2QdTdYI7rDddfJeV)

authConfigLoginSuccessRedirect=mainpage

authConfigCookieSecure=false

githubHandler=authGithub(githubClientKeygithubSecretKey)

githubHandlerServeHTTP(thisCtxResponseWriterthisCtxRequest)

3 Handlingafterasuccessfullandingpage

Uservalidation

315

packagecontrollers

import(

githubcomastaxiebeego

githubcombradrydzewskigoauth

nethttp

neturl

)

typePageControllerstruct

beegoController

func(thisPageController)Get()

settheauthparameters

authConfigCookieSecret=[]byte(7H9xiimk2QdTdYI7rDddfJeV)

authConfigLoginSuccessRedirect=mainpage

authConfigCookieSecure=false

usererr=authGetUserCookie(thisCtxRequest)

ifnoactiveusersessionthenauthorizeuser

iferr=nil||userId()==

httpRedirect(thisCtxResponseWriterthisCtxRequestauthConfigLoginRedirecthttpStatusSeeOther

)

return

elseaddtheusertotheURLandcontinue

thisCtxRequestURLUser=urlUser(userId())

thisData[pic]=userPicture()

thisData[id]=userId()

thisData[name]=userName()

thisTplNames=hometpl

Thewholeprocessisasfollows

firstopenyourbrowserandentertheaddress

Figure144showsthehomepagewithaloginbutton

Whenclickingonthelinkthefollowingscreenappears

Figure145displayedafterclickingtheloginbuttontoauthenticatewithyourGitHubcredentials

AfterclickingAuthorizeappthefollowingscreenappears

Figure146authorizedGithubinformationgetsdisplayedaftertheloginpage

CustomauthenticationCustomauthenticationisgenerallycombinedwithsessionauthenticationthefollowingcodeisaBeegobasedopensourceblogwhichdemonstratesthis

Loginprocess

func(thisLoginController)Post()

thisTplNames=logintpl

thisCtxRequestParseForm()

username=thisCtxRequestFormGet(username)

Uservalidation

316

password=thisCtxRequestFormGet(password)

md5Password=md5New()

ioWriteString(md5Passwordpassword)

buffer=bytesNewBuffer(nil)

fmtFprintf(bufferxmd5PasswordSum(nil))

newPass=bufferString()

now=timeNow()Format(2006-01-02150405)

userInfo=modelsGetUserInfo(username)

ifuserInfoPassword==newPass

varusersmodelsUser

usersLast_logintime=now

modelsUpdateUserInfo(users)

Setthesessionsuccessfullogin

sess=globalSessionsSessionStart(thisCtxResponseWriterthisCtxRequest)

sessSet(uiduserInfoId)

sessSet(unameuserInfoUsername)

thisCtxRedirect(302)

Registrationprocess

func(thisRegController)Post()

thisTplNames=regtpl

thisCtxRequestParseForm()

username=thisCtxRequestFormGet(username)

password=thisCtxRequestFormGet(password)

usererr=checkUsername(username)

fmtPrintln(usererr)

ifusererr==false

thisData[UsernameErr]=UsernameerrorPleasetoagain

return

passerr=checkPassword(password)

ifpasserr==false

thisData[PasswordErr]=PassworderrorPleasetoagain

return

md5Password=md5New()

ioWriteString(md5Passwordpassword)

buffer=bytesNewBuffer(nil)

fmtFprintf(bufferxmd5PasswordSum(nil))

newPass=bufferString()

now=timeNow()Format(2006-01-02150405)

userInfo=modelsGetUserInfo(username)

ifuserInfoUsername==

varusersmodelsUser

usersUsername=username

usersPassword=newPass

usersCreated=now

usersLast_logintime=now

modelsAddUser(users)

Setthesessionsuccessfullogin

sess=globalSessionsSessionStart(thisCtxResponseWriterthisCtxRequest)

sessSet(uiduserInfoId)

sessSet(unameuserInfoUsername)

thisCtxRedirect(302)

else

thisData[UsernameErr]=Useralreadyexists

Uservalidation

317

funccheckPassword(passwordstring)(bbool)

ifok_=regexpMatchString(^[a-zA-Z0-9]416$password)ok

returnfalse

returntrue

funccheckUsername(usernamestring)(bbool)

ifok_=regexpMatchString(^[a-zA-Z0-9]416$username)ok

returnfalse

returntrue

Onceyouhaveimplementeduserloginandregistrationothermodulescanbeaddedtodeterminewhethertheuserhasbeenloggedinornot

func(thisAddBlogController)Prepare()

sess=globalSessionsSessionStart(thisCtxResponseWriterthisCtxRequest)

sess_uid=sessGet(userid)

sess_username=sessGet(username)

ifsess_uid==nil

thisCtxRedirect(302adminlogin)

return

thisData[Username]=sess_username

LinksDirectoryPrevioussectionFormNextsectionMulti-languagesupport

Uservalidation

318

145Multi-languagesupportInthechapterwhereweintroducedinternationalizationandlocalizationwedevelopedthego-i18nlibraryInthissectionwewillseehowthislibraryisintegratedintotheBeegoframeworkandhowitenablesourBeegoapplicationstosupportbothinternationalizationandlocalization

I18nintegrationBeegofirstsetssomeglobalvariables

Translationi18nIL

Langstringsetthelanguagepackzhen

LangPathstringsetthelanguagepacklocation

Amulti-languageinitializationfunctionisdefined

funcInitLang()

beegoTranslation=i18nNewLocale()

beegoTranslationLoadPath(beegoLangPath)

beegoTranslationSetLocale(beegoLang)

Inordertofacilitatemulti-languagecallsinthetemplatepackagedirectlywedesignedthreefunctionsforhandlingmulti-languageresponses

Multi-languagesupport

319

beegoTplFuncMap[Trans]=i18nI18nT

beegoTplFuncMap[TransDate]=i18nI18nTimeDate

beegoTplFuncMap[TransMoney]=i18nI18nMoney

funcI18nT(argsinterface)string

ok=false

varsstring

iflen(args)==1

sok=args[0](string)

ifok

s=fmtSprint(args)

returnbeegoTranslationTranslate(s)

funcI18nTimeDate(argsinterface)string

ok=false

varsstring

iflen(args)==1

sok=args[0](string)

ifok

s=fmtSprint(args)

returnbeegoTranslationTime(s)

funcI18nMoney(argsinterface)string

ok=false

varsstring

iflen(args)==1

sok=args[0](string)

ifok

s=fmtSprint(args)

returnbeegoTranslationMoney(s)

Multi-languagedevelopment1 Settingthelanguageandlocationofthelanguagepacktheninitializei18nobjects

beegoLang=zh

beegoLangPath=viewslang

beegoInitLang()

2 Designingamulti-languagepackage

Abovewetalkedabouthowtoinitializeamulti-languagepackageNowletslookathowtodesignoneMulti-languagepackagesaretypicallyJSONfilesasyouvealreadyseeninChapter10WemustprovidetranslationfilesforlanguageswewishtosupportonourLangPathsuchasthefollowing

Multi-languagesupport

320

zhjson

zh

submit提交

create创建

enjson

en

submitSubmit

createCreate

3 Usinglanguagepackages

Wecancallthecontrollertogetthetranslatedresponseinthedesiredlanguagelikeso

func(thisMainController)Get()

thisData[create]=beegoTranslationTranslate(create)

thisTplNames=indextpl

Wecanalsodirectlyinterpolatetranslatedresponsesinourtemplates

DirectTexttranslation

create|Trans

Timetotranslate

time|TransDate

Currencytranslation

money|TransMoney

LinksDirectoryPrevioussectionUservalidationNextsectionpprof

Multi-languagesupport

321

146pprofAgreatfeatureofGosstandardlibraryisitscodeperformancemonitoringtoolsThesepackagesexistintwoplaces

nethttppprof

runtimepprof

InfactnethttppprofsimplyexposesruntimeprofilingdatafromtheruntimepprofpackageonanHTTPport

pprofsupportinBeegoTheBeegoframeworkcurrentlysupportspprofhoweveritisnotturnedonbydefaultIfyouneedtotesttheperformanceofyourapplication(forinstancebyviewingtheexecutiongoroutine)suchinformationfromGosdefaultpackagenethttppprofalreadyhasthisfeatureBecausebeegohasrepackagedtheServHTTPfunctionyoucannotopenthedefaultfeatureincludedinpprofThisresultedinbeegosupportingpprofinternally

FirstinourbeegoRunfunctionwechoosewhetherornottoautomaticallyloadtheperformancepackaccordingtoourconfigurationvariable(inthiscasePprofOn)

ifPprofOn

BeeAppRegisterController(`debugpprof`ampProfController)

BeeAppRegisterController(`debugpprofpp([w]+)`ampProfController)

DesigningProfController

packagebeego

import(

nethttppprof

)

typeProfControllerstruct

Controller

func(thisProfController)Get()

switchthisCtxParams[pp]

default

pprofIndex(thisCtxResponseWriterthisCtxRequest)

case

pprofIndex(thisCtxResponseWriterthisCtxRequest)

casecmdline

pprofCmdline(thisCtxResponseWriterthisCtxRequest)

caseprofile

pprofProfile(thisCtxResponseWriterthisCtxRequest)

casesymbol

pprofSymbol(thisCtxResponseWriterthisCtxRequest)

thisCtxResponseWriterWriteHeader(200)

GettingstartedFromtheabovewecanseethatenablingpprofisassimpleassettingthePprofOnconfigurationvariabletotrue

pprof

322

beegoPprofOn=true

YoucanthenopenthefollowingURLinyourbrowsertoseethefollowinginterface

Figure147currentsystemgoroutineheapthreadinformation

Byclickingonagoroutinewecanseealotofdetailedinformation

Figure148showsthecurrentgoroutinedetails

Ofcoursewecanalsogetmoredetailsfromthecommandline

gotoolpprofhttplocalhost8080debugpprofprofile

Thistimetheprogramwillbeginprofilingtheapplicationforaperiodof30secondsduringwhichtimeitwillrepeatedlyrefreshthepageinthebrowserinanattempttogatherCPUusageandperformancedata

(pprof)top10

Total3samples

13333331333MHeap_AllocLocked

13336671333osexec(Cmd)closeDescriptors

133310001333runtimesigprocmask

00010001333MCentral_Grow

00010002667mainCompile

00010002667maincompile

00010002667mainrun

00010001333makeslice1

00010002667nethttp(ServeMux)ServeHTTP

00010002667nethttp(conn)serve

(pprof)web

Figure149showstheexecutionflowofinformation

LinksDirectoryPrevioussectionMulti-languagesupportNextsectionSummary

pprof

323

147SummaryThischapterillustratessomewaysinwhichtheBeegoframeworkcanbeextendedWefirstlookedatstaticfilesupportlearninghowBeegohandlesservingstaticfilesinternallyWesawhowthisfunctionalityallowedustoeasilyintegratestaticassets(suchasBootstrapsCSSfiles)forrapidandgreatlookingwebsitedevelopmentNextwesawhowtointegratesessionManagertopainlesslyfacilitateusersessionsinBeegoWethendescribedformmanagementandvalidationleveragingGosstructstoreducecoderepetitionandforsimplifyingfieldvalidationAfterthatwediscusseduserauthenticationwhichinvolvedthreemainstrategiesHTTPauthentication(basicanddigest)thirdpartyauthenticationandcustomauthenticationWelearnedaboutsomeexistingthirdpartyauthenticationpackagesthathavealreadyimplementedthesestrategieswhichareconvenientlyaccommodatedbyBeegoThenextsectionre-introducedlanguagesupportinBeegowesawhowtointegratethego-i18npackageandlearnedhowtoeasilyloadmultiplelanguagepacksintoourapplicationsasneededLastlywediscussedhowtoworkwithGospprofpackagesinBeegoThepprofpackageisusedforperformanceprofilinginGoandBeegorepackagesitsoitcanservethesamepurposeinBeegoapplicationswithoutmuchadditionalworkThroughthesesixsectionsweveextendedBeegowithmanyfeaturesmakingitintoaversatileframeworksuitablefortherequirementsofmanywebapplicationsUsershavethefreedomofextendingtheframeworktosuittheirindividualneedsthisbriefintroductiontoBeegosimplyoffersasmalltasteofwhatcanbedone

LinksDirectoryPrevioussectionpprofNextchapterAppendixAReferences

Summary

324

AppendixAReferencesThisbookisasummaryofmyGoexperiencesomecontentarefromotherGopherseitherblogsorsitesThankstothem

1 golangblog2 RussCoxsblog3 gobook4 golangtutorials5 轩脉刃de刀光剑影

6 GoProgrammingLanguage7 NetworkprogrammingwithGo8 setup-the-rails-application-for-internationalization9 TheCross-SiteScripting(XSS)FAQ

References

325

1Goenvironmentconfiguration11Installation12$GOPATHandworkspace13Gocommands14Godevelopmenttools15Summary

2Gobasicknowledge21HelloGo22Gofoundation23Controlstatementsandfunctions24struct25Object-oriented26interface27Concurrency28Summary

3Webfoundation31Webworkingprinciples32Buildasimplewebserver33HowGoworkswithweb34Getintohttppackage35Summary

4Userform41Processforminputs42Verificationofinputs43Crosssitescripting44Duplicatesubmissions45Fileupload46Summary

5Database51databasesqlinterface52MySQL53SQLite54PostgreSQL55DevelopORMbasedonbeedb56NoSQLdatabase57Summary

6Datastorageandsession61Sessionandcookies62HowtousesessioninGo63Sessionstorage64Preventhijackofsession65Summary

7Textfiles71XML72JSON73Regexp74Templates75Files76Strings77Summary

8Webservices81Sockets82WebSocket

preface

326

83REST84RPC85Summary

9Securityandencryption91CSRFattacks92Filterinputs93XSSattacks94SQLinjection95Passwordstorage96Encryptanddecryptdata97Summary

10Internationalizationandlocalization101Timezone102Localizedresources103Internationalsites104Summary

11Errorhandlingdebuggingandtesting111Errorhandling112DebuggingbyusingGDB113Writetestcases114Summary

12Deploymentandmaintenance121Logs122Errorsandcrashes123Deployment124Backupandrecovery125Summary

13Buildawebframework131Projectprogram132Customizedrouters133Designcontrollers134Logsandconfigurations135Adddeleteandupdateblogs136Summary

14Developwebframework141Staticfiles142Session143Form144Uservalidation145Multi-languagesupport146pprof147Summary

AppendixAReferences

preface

327

  • Introduction
  • Go Environment Configuration
    • Installation
    • $GOPATH and workspace
    • Go commands
    • Go development tools
    • Summary
      • Go basic knowledge
        • Hello Go
        • Go foundation
        • Control statements and functions
        • struct
        • Object-oriented
        • interface
        • Concurrency
        • Summary
          • Web foundation
            • Web working principles
            • Build a simple web server
            • How Go works with web
            • Get into http package
            • Summary
              • HTTP Form
                • Process form inputs
                • Validation of inputs
                • Cross site scripting
                • Duplicate submissions
                • File upload
                • Summary
                  • Database
                    • databasesql interface
                    • How to use MySQL
                    • How to use SQLite
                    • How to use PostgreSQL
                    • How to use beedb ORM
                    • NOSQL
                    • Summary
                      • Data storage and session
                        • Session and cookies
                        • How to use session in Go
                        • Session storage
                        • Prevent hijack of session
                        • Summary
                          • Text files
                            • XML
                            • JSON
                            • Regexp
                            • Templates
                            • Files
                            • Strings
                            • Summary
                              • Web services
                                • Sockets
                                • WebSocket
                                • REST
                                • RPC
                                • Summary
                                  • Security and encryption
                                    • CSRF attacks
                                    • Filter inputs
                                    • XSS attacks
                                    • SQL injection
                                    • Password storage
                                    • Encrypt and decrypt data
                                    • Summary
                                      • Internationalization and localization
                                        • Time zone
                                        • Localized resources
                                        • International sites
                                        • Summary
                                          • Error handling debugging and testing
                                            • Error handling
                                            • Debugging by using GDB
                                            • Write test cases
                                            • Summary
                                              • Deployment and maintenance
                                                • Logs
                                                • Errors and crashes
                                                • Deployment
                                                • Backup and recovery
                                                • Summary
                                                  • Build a web framework
                                                    • Project program
                                                    • Customized routers
                                                    • Design controllers
                                                    • Logs and configurations
                                                    • Add delete and update blogs
                                                    • Summary
                                                      • Develop web framework
                                                        • Static files
                                                        • Session
                                                        • Form
                                                        • User validation
                                                        • Multi-language support
                                                        • pprof
                                                        • Summary
                                                          • References
                                                          • preface
Page 5: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 6: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 7: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 8: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 9: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 10: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 11: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 12: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 13: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 14: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 15: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 16: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 17: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 18: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 19: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 20: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 21: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 22: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 23: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 24: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 25: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 26: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 27: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 28: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 29: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 30: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 31: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 32: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 33: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 34: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 35: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 36: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 37: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 38: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 39: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 40: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 41: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 42: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 43: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 44: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 45: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 46: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 47: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 48: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 49: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 50: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 51: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 52: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 53: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 54: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 55: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 56: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 57: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 58: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 59: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 60: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 61: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 62: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 63: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 64: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 65: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 66: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 67: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 68: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 69: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 70: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 71: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 72: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 73: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 74: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 75: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 76: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 77: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 78: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 79: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 80: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 81: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 82: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 83: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 84: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 85: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 86: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 87: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 88: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 89: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 90: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 91: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 92: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 93: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 94: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 95: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 96: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 97: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 98: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 99: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 100: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 101: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 102: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 103: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 104: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 105: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 106: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 107: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 108: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 109: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 110: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 111: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 112: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 113: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 114: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 115: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 116: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 117: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 118: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 119: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 120: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 121: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 122: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 123: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 124: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 125: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 126: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 127: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 128: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 129: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 130: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 131: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 132: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 133: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 134: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 135: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 136: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 137: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 138: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 139: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 140: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 141: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 142: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 143: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 144: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 145: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 146: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 147: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 148: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 149: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 150: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 151: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 152: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 153: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 154: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 155: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 156: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 157: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 158: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 159: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 160: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 161: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 162: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 163: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 164: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 165: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 166: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 167: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 168: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 169: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 170: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 171: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 172: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 173: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 174: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 175: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 176: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 177: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 178: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 179: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 180: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 181: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 182: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 183: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 184: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 185: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 186: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 187: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 188: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 189: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 190: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 191: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 192: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 193: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 194: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 195: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 196: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 197: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 198: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 199: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 200: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 201: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 202: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 203: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 204: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 205: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 206: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 207: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 208: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 209: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 210: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 211: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 212: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 213: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 214: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 215: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 216: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 217: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 218: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 219: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 220: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 221: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 222: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 223: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 224: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 225: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 226: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 227: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 228: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 229: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 230: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 231: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 232: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 233: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 234: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 235: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 236: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 237: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 238: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 239: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 240: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 241: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 242: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 243: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 244: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 245: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 246: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 247: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 248: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 249: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 250: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 251: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 252: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 253: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 254: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 255: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 256: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 257: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 258: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 259: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 260: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 261: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 262: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 263: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 264: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 265: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 266: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 267: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 268: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 269: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 270: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 271: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 272: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 273: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 274: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 275: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 276: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 277: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 278: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 279: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 280: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 281: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 282: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 283: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 284: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 285: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 286: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 287: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 288: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 289: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 290: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 291: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 292: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 293: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 294: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 295: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 296: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 297: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 298: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 299: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 300: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 301: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 302: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 303: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 304: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 305: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 306: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 307: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 308: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 309: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 310: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 311: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 312: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 313: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 314: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 315: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 316: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 317: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 318: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 319: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 320: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 321: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 322: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 323: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 324: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 325: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write
Page 326: Table of Contents - WordPress.com · 2018. 3. 2. · Build Web Application with Golang Purpose Because I'm interested in web application development, I used my free time to write